diff options
author | Ryan Lortie <desrt@desrt.ca> | 2014-12-19 12:22:40 -0500 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2014-12-19 12:22:40 -0500 |
commit | ef7759e617a49440209999b2655e2ce7cebe3b03 (patch) | |
tree | d02f233b2e23f72e0459f017c89f28679be7e652 | |
parent | d6bb450e7dfd9ff9f2d80010aae3ac6a3f25c8da (diff) | |
download | glib-wip/ghandle.tar.gz |
gio fixupswip/ghandle
-rw-r--r-- | gio/gcancellable.c | 303 | ||||
-rw-r--r-- | gio/gcancellable.h | 13 | ||||
-rw-r--r-- | gio/gsocket.c | 17 | ||||
-rw-r--r-- | gio/gunixinputstream.c | 16 | ||||
-rw-r--r-- | gio/gunixoutputstream.c | 16 |
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; |