summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2014-12-19 12:22:40 -0500
committerRyan Lortie <desrt@desrt.ca>2014-12-19 12:22:40 -0500
commitef7759e617a49440209999b2655e2ce7cebe3b03 (patch)
treed02f233b2e23f72e0459f017c89f28679be7e652
parentd6bb450e7dfd9ff9f2d80010aae3ac6a3f25c8da (diff)
downloadglib-wip/ghandle.tar.gz
gio fixupswip/ghandle
-rw-r--r--gio/gcancellable.c303
-rw-r--r--gio/gcancellable.h13
-rw-r--r--gio/gsocket.c17
-rw-r--r--gio/gunixinputstream.c16
-rw-r--r--gio/gunixoutputstream.c16
5 files changed, 137 insertions, 228 deletions
diff --git a/gio/gcancellable.c b/gio/gcancellable.c
index 7c8a693f9..6b1cce2d9 100644
--- a/gio/gcancellable.c
+++ b/gio/gcancellable.c
@@ -24,6 +24,9 @@
#include "glib-private.h"
#include "gcancellable.h"
#include "glibintl.h"
+#ifdef G_OS_UNIX
+#include "glib-unix.h"
+#endif
#include <string.h>
#include <errno.h>
@@ -304,6 +307,16 @@ g_cancellable_is_cancelled (GCancellable *cancellable)
return cancellable != NULL && cancellable->priv->cancelled;
}
+static gboolean
+g_cancellable_set_error (GError **error)
+{
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ return FALSE;
+}
+
/**
* g_cancellable_set_error_if_cancelled:
* @cancellable: (allow-none): a #GCancellable or %NULL
@@ -319,13 +332,7 @@ g_cancellable_set_error_if_cancelled (GCancellable *cancellable,
GError **error)
{
if (g_cancellable_is_cancelled (cancellable))
- {
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- _("Operation was cancelled"));
- return TRUE;
- }
+ return !g_cancellable_set_error (error);
return FALSE;
}
@@ -465,232 +472,164 @@ g_cancellable_release_fd (GCancellable *cancellable)
g_mutex_unlock (&cancellable_mutex);
}
-gint
-ready_time_to_timeout (gint64 ready_time)
-{
- gint timeout;
-
- if (ready_time > 0)
- {
- gint64 now = g_get_monotonic_time ();
-
- if (now < ready_time)
- timeout = (ready_time - now + 999) / G_TIME_SPAN_MILLISECOND;
- else
- timeout = 0;
- }
- else if (ready_time < 0)
- timeout = -1;
- else
- timeout = 0;
-
- return timeout;
-}
-
/**
- * g_cancellable_poll_simple:
+ * g_cancellable_wait_for_handle:
* @cancellable: (nullable): a #GCancellable object
- * @pollfd: a single #GPollFD record to poll
+ * @handle: the handle to wait for, or %G_HANDLE_NULL
* @ready_time: the monotonic time past which to return
* @error: a pointer to a %NULL #GError, or %NULL
*
- * Waits on @pollfd until the requested condition is met, until the
- * @ready_time is reached, or until @cancellable is cancelled.
+ * Waits on @handle until @handle is ready, until the @ready_time is
+ * reached, or until @cancellable is cancelled.
*
* If @cancellable is cancelled or if polling returns an error then
- * @error will be set and %FALSE will be returned. EINTR is handled
- * internally by retrying the poll. Other errors, including
- * cancellation, are generally reported in the %G_IO_ERROR domain.
+ * @error will be set and %FALSE will be returned.
*
- * If the condition requested by @pollfd becomes ready then the revents
- * field of @pollfd will be updated accordingly and %TRUE will be
- * returned.
+ * If the handle becomes ready then %TRUE will be returned.
*
- * If @ready_time was reached and the @pollfd was not ready then
- * %G_IO_ERROR_TIMED_OUT will be returned.
+ * If @ready_time passes, %G_IO_ERROR_TIMED_OUT will be returned. A
+ * ready time in the past (ideally 0) means to return immediately and a
+ * ready time of -1 means to block indefinitely.
*
- * If @ready_time is in the past (including a value of 0) then the call
- * will return immediately. Checking of cancellation and the @pollfd
- * will still occur in the normal way -- it just won't block. A
- * negative @ready_time means that there is no timeout.
+ * Interruptions due to signal delivery on POSIX (`EINTR`), or async
+ * procedure calls or IO completion handlers on Windows
+ * (`WAIT_IO_COMPLETION`) are dealt with internally by rescheduling the
+ * wait.
*
- * @cancellable can be %NULL, in which case cancellation is not checked
- * for.
+ * If you are on POSIX and need to check for specific IO conditions, use
+ * g_cancellable_wait_for_unix_fd().
*
- * See g_cancellable_poll_full() for a more powerful version of this
- * call, if you need it.
+ * If @handle is %G_HANDLE_NULL and ready_time is 0 then this function
+ * only checks for cancellation and returns immediately (successfully)
+ * otherwise. It is not valid to use %G_HANDLE_NULL with a non-zero
+ * @ready_time.
*
- * Returns: %TRUE if the requested condition was met, or %FALSE on error
- * or cancellation
+ * Returns: %TRUE if @handle became ready,
+ * otherwise %FALSE with @error set
*
* Since: 2.44
- **/
-gint
-g_cancellable_poll_simple (GCancellable *cancellable,
- GPollFD *pollfd,
- gint64 ready_time,
- GError **error)
+ */
+gboolean
+g_cancellable_wait_for_handle (GCancellable *cancellable,
+ ghandle handle,
+ gint64 ready_time,
+ GError **error)
{
- GPollFD fds[2];
- guint nfds;
+ ghandle handles[2];
+ GThread *self;
gint result;
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return FALSE;
+ g_return_val_if_fail (g_handle_is_valid (handle) || ready_time == 0, FALSE);
- fds[0] = *pollfd;
- nfds = 1;
-
- nfds += g_cancellable_make_pollfd (cancellable, &fds[1]);
- fds[1].revents = 0; /* we check this below */
-
-again:
- result = g_poll (fds, nfds, ready_time_to_timeout (ready_time));
-
- if (result == -1)
+ /* save ourselves the trouble of entering the critical section */
+ if (ready_time == 0)
{
- gint saved_errno = errno;
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
- if (saved_errno == EINTR)
- goto again;
+ if (!g_handle_is_valid (handle))
+ return TRUE;
+ }
- g_set_error_literal (error, G_IO_ERROR,
- g_io_error_from_errno (saved_errno),
- g_strerror (saved_errno));
+ if (!cancellable)
+ return g_handle_wait_multiple (&handle, 1, ready_time, error);
- goto out;
- }
+ /* OK: now we do the "full strength version" */
+ self = g_thread_self ();
+ handles[0] = g_cancellable_enter_critical_section_using_handle (cancellable, self, error);
+ if (!g_handle_is_valid (handles[0]))
+ return FALSE;
- if (result == 0)
- {
- g_assert (ready_time >= 0);
- g_set_error_literal (error, G_IO_ERROR,
- G_IO_ERROR_TIMED_OUT,
- _("Operation timed out"));
- result = -1;
- goto out;
- }
+ handles[1] = handle;
- if (result && fds[1].revents)
- {
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- _("Operation was cancelled"));
- result = -1;
- goto out;
- }
+ /* result will be -1, 0 or 1 */
+ result = g_handle_wait_multiple (handles, 2, ready_time, error);
- pollfd->revents = fds[0].revents;
+ /* This is the case where we had a cancellation from another thread */
+ if (result == 0)
+ g_cancellable_set_error (error);
-out:
- g_cancellable_release_fd (cancellable);
+ /* Otherwise, for -1 we already have an error set and '1' is success */
+ g_cancellable_leave_critical_section (cancellable, self, NULL);
- return result != -1;
+ return (result == 1);
}
/**
- * g_cancellable_poll_full:
+ * g_cancellable_wait_for_unix_fd:
* @cancellable: (nullable): a #GCancellable object
- * @pollfds: an array of #GPollFD records to poll
- * @nfds: the length of @pollfds
+ * @fd: a file descriptor, or -1
+ * @condition: the condition to wait for
* @ready_time: the monotonic time past which to return
* @error: a pointer to a %NULL #GError, or %NULL
*
- * Waits on @pollfds until at least one of the requested conditions is
- * met, until the @ready_time is reached, or until @cancellable is
- * cancelled.
- *
- * If @cancellable is cancelled or if polling returns an error then
- * @error will be set and -1 will be returned. EINTR is returned as
- * %G_FILE_ERROR_INTR (as there is no equivalent error code in GIO). In
- * general, this function will return error codes from #GFileError,
- * except in case of cancellation in which case %G_IO_ERROR_CANCELLED is
- * used.
- *
- * Otherwise, the number of ready @pollfds is returned. Their revents
- * fields will be updated accordingly. If @ready_time was reached then
- * the result may be zero.
- *
- * If @ready_time is in the past (including a value of 0) then the call
- * will return immediately. Checking of cancellation and the @pollfds
- * will still occur in the normal way -- it just won't block. A
- * negative @ready_time means that there is no timeout.
+ * Waits on @handle until the requested condition is met, until the
+ * @ready_time is reached, or until @cancellable is cancelled.
*
- * @cancellable can be %NULL, in which case cancellation is not checked
- * for.
+ * This function is equivalent to g_cancellable_wait_for_handle(). The
+ * only difference is that it takes @condition and that is is only
+ * available on POSIX.
*
- * g_cancellable_poll_simple() will be easier to use for most cases.
+ * If @fd is -1 and ready_time is 0 then this function only checks for
+ * cancellation and returns immediately (successfully) otherwise. It is
+ * not valid to use an @fd of -1 with a non-zero @ready_time.
*
- * Returns: the number of @pollfds that are ready, or -1 on error
+ * Returns: %TRUE if @handle became ready,
+ * otherwise %FALSE with @error set
*
* Since: 2.44
- **/
-gint
-g_cancellable_poll_full (GCancellable *cancellable,
- GPollFD *pollfds,
- guint nfds,
- gint64 ready_time,
- GError **error)
+ */
+#ifdef G_OS_UNIX
+gboolean
+g_cancellable_wait_for_unix_fd (GCancellable *cancellable,
+ gint fd,
+ GIOCondition condition,
+ gint64 ready_time,
+ GError **error)
{
- GPollFD *all_pollfds;
- gint all_nfds;
+ GPollFD pollfds[2];
+ GThread *self;
gint result;
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return FALSE;
+ g_return_val_if_fail (fd != -1 || ready_time == 0, FALSE);
- if (cancellable)
+ /* save ourselves the trouble of entering the critical section */
+ if (ready_time == 0)
{
- /* not that we ever expect this to happen... */
- if (nfds >= 1024)
- all_pollfds = g_new (GPollFD, nfds + 1);
- else
- all_pollfds = g_newa (GPollFD, nfds + 1);
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
- g_cancellable_make_pollfd (cancellable, &all_pollfds[0]);
- memcpy (all_pollfds + 1, pollfds, nfds * sizeof (GPollFD));
- all_nfds = nfds + 1;
- }
- else
- {
- all_pollfds = pollfds;
- all_nfds = nfds;
+ if (fd == -1)
+ return TRUE;
}
- result = g_poll (all_pollfds, all_nfds, ready_time_to_timeout (ready_time));
+ pollfds[1].fd = fd;
+ pollfds[1].events = condition;
- if (result == -1)
- {
- gint saved_errno = errno;
+ if (!cancellable)
+ return g_unix_fd_wait_multiple (&pollfds[1], 1, ready_time, error);
- g_set_error_literal (error, G_FILE_ERROR,
- g_file_error_from_errno (saved_errno),
- g_strerror (saved_errno));
- goto out;
- }
+ /* OK: now we do the "full strength version" */
+ self = g_thread_self ();
+ pollfds[0].fd = g_cancellable_enter_critical_section_using_handle (cancellable, self, error);
+ pollfds[0].events = G_IO_IN;
- if (cancellable && all_pollfds[0].revents)
- {
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- _("Operation was cancelled"));
- result = -1;
- goto out;
- }
+ if (pollfds[0].fd == -1)
+ return FALSE;
- if (cancellable)
- memcpy (pollfds, all_pollfds + 1, nfds * sizeof (GPollFD));
+ /* result will be -1, 0 or 1 */
+ result = g_unix_fd_wait_multiple (pollfds, 2, ready_time, error);
-out:
- g_cancellable_release_fd (cancellable);
+ /* This is the case where we had a cancellation from another thread */
+ if (result == 0)
+ g_cancellable_set_error (error);
- if (cancellable && nfds >= 1024)
- g_free (all_pollfds);
+ /* Otherwise, for -1 we already have an error set and '1' is success */
+ g_cancellable_leave_critical_section (cancellable, self, NULL);
- return result;
+ return (result == 1);
}
+#endif
/**
* g_cancellable_cancel:
@@ -1195,10 +1134,7 @@ g_cancellable_enter_critical_section_using_handle (GCancellable *cancellable,
g_mutex_unlock (&cancellable_mutex);
if (!g_handle_is_valid (result))
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- _("Operation was cancelled"));
+ g_cancellable_set_error (error);
return result;
}
@@ -1246,10 +1182,7 @@ g_cancellable_leave_critical_section (GCancellable *cancellable,
g_mutex_unlock (&cancellable_mutex);
if (!success)
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- _("Operation was cancelled"));
+ return g_cancellable_set_error (error);
return TRUE;
}
diff --git a/gio/gcancellable.h b/gio/gcancellable.h
index 17247133c..9775639c6 100644
--- a/gio/gcancellable.h
+++ b/gio/gcancellable.h
@@ -89,16 +89,19 @@ GLIB_AVAILABLE_IN_ALL
void g_cancellable_release_fd (GCancellable *cancellable);
GLIB_AVAILABLE_IN_2_44
-gboolean g_cancellable_poll_simple (GCancellable *cancellable,
- GPollFD *pollfd,
+gboolean g_cancellable_wait_for_handle (GCancellable *cancellable,
+ ghandle handle,
gint64 ready_time,
GError **error);
+
+#ifdef G_OS_UNIX
GLIB_AVAILABLE_IN_2_44
-gint g_cancellable_poll_full (GCancellable *cancellable,
- GPollFD *pollfds,
- guint nfds,
+gint g_cancellable_wait_for_unix_fd (GCancellable *cancellable,
+ gint fd,
+ GIOCondition condition,
gint64 ready_time,
GError **error);
+#endif
GLIB_AVAILABLE_IN_ALL
GSource * g_cancellable_source_new (GCancellable *cancellable);
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 479387ea8..516fdcb02 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -3577,20 +3577,16 @@ g_socket_condition_timed_wait (GSocket *socket,
#ifdef G_OS_WIN32
{
GIOCondition current_condition;
- GPollFD pollfd;
/* Always check these */
condition |= G_IO_ERR | G_IO_HUP;
add_condition_watch (socket, &condition);
- pollfd.fd = (gintptr) socket->priv->event;
- pollfd.events = G_IO_IN;
-
current_condition = update_condition (socket);
while ((condition & current_condition) == 0)
{
- if (!g_cancellable_poll_simple (cancellable, &pollfd, end_time, error))
+ if (!g_cancellable_wait_for_handle (cancellable, socket->priv->event, end_time, error))
{
g_prefix_error (error, _("Waiting for socket condition: "));
break;
@@ -3603,15 +3599,8 @@ g_socket_condition_timed_wait (GSocket *socket,
return (condition & current_condition) != 0;
}
#else
- {
- GPollFD pollfd;
-
- pollfd.fd = socket->priv->fd;
- pollfd.events = condition;
-
- return g_cancellable_poll_simple (cancellable, &pollfd, end_time, error);
- }
- #endif
+ return g_cancellable_wait_for_unix_fd (cancellable, socket->priv->fd, condition, end_time, error);
+#endif
}
/**
diff --git a/gio/gunixinputstream.c b/gio/gunixinputstream.c
index 6996b0b79..2d7c84c23 100644
--- a/gio/gunixinputstream.c
+++ b/gio/gunixinputstream.c
@@ -340,23 +340,15 @@ g_unix_input_stream_read (GInputStream *stream,
{
GUnixInputStream *unix_stream;
gssize res = -1;
- GPollFD pollfd;
unix_stream = G_UNIX_INPUT_STREAM (stream);
- pollfd.fd = unix_stream->priv->fd;
- pollfd.events = G_IO_IN;
-
while (1)
{
- gboolean result;
-
- if (unix_stream->priv->is_pipe_or_socket)
- result = g_cancellable_poll_simple (cancellable, &pollfd, -1, error);
- else
- result = !g_cancellable_set_error_if_cancelled (cancellable, error);
-
- if (!result)
+ if (!g_cancellable_wait_for_unix_fd (cancellable,
+ unix_stream->priv->is_pipe_or_socket ? unix_stream->priv->fd : -1, G_IO_IN,
+ unix_stream->priv->is_pipe_or_socket ? -1 : 0,
+ error))
{
g_prefix_error (error, _("Error reading from file descriptor: "));
break;
diff --git a/gio/gunixoutputstream.c b/gio/gunixoutputstream.c
index a4193a21e..151e796ef 100644
--- a/gio/gunixoutputstream.c
+++ b/gio/gunixoutputstream.c
@@ -325,23 +325,15 @@ g_unix_output_stream_write (GOutputStream *stream,
{
GUnixOutputStream *unix_stream;
gssize res = -1;
- GPollFD pollfd;
unix_stream = G_UNIX_OUTPUT_STREAM (stream);
- pollfd.fd = unix_stream->priv->fd;
- pollfd.events = G_IO_OUT;
-
while (1)
{
- gboolean result;
-
- if (unix_stream->priv->is_pipe_or_socket)
- result = g_cancellable_poll_simple (cancellable, &pollfd, -1, error);
- else
- result = !g_cancellable_set_error_if_cancelled (cancellable, error);
-
- if (!result)
+ if (!g_cancellable_wait_for_unix_fd (cancellable,
+ unix_stream->priv->is_pipe_or_socket ? unix_stream->priv->fd : -1, G_IO_OUT,
+ unix_stream->priv->is_pipe_or_socket ? -1 : 0,
+ error))
{
g_prefix_error (error, _("Error writing to file descriptor: "));
break;