[glib/wip/ghandle: 1/16] GCancellable: add new poll wrapper APIs
- From: Ryan Lortie <desrt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/ghandle: 1/16] GCancellable: add new poll wrapper APIs
- Date: Fri, 19 Dec 2014 17:25:23 +0000 (UTC)
commit 69c3ce7148c8a8084f7dbcbd93992e0f5537dd59
Author: Ryan Lortie <desrt desrt ca>
Date: Thu Dec 18 01:46:52 2014 -0500
GCancellable: add new poll wrapper APIs
Add two APIs to GCancellable for waiting on one or more GPollFD records until
they are ready, or until cancellation.
This is basically a cancellable version of g_poll().
This makes many typical operations easier; it will be possible to
replace all cases of g_cancellable_make_pollfd() in GIO with just the
simple version of this function, often at a large reduction in lines of
code. Even better is that in the future, users of this API may be able
to avoid allocating an fd at all.
I'm not sure if it's worth keeping the _full version.
https://bugzilla.gnome.org/show_bug.cgi?id=741716
docs/reference/gio/gio-sections.txt | 2 +
gio/gcancellable.c | 238 +++++++++++++++++++++++++++++++++++
gio/gcancellable.h | 12 ++
3 files changed, 252 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index e7330bf..a14778b 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1218,6 +1218,8 @@ g_cancellable_get_fd
g_cancellable_make_pollfd
g_cancellable_release_fd
g_cancellable_source_new
+g_cancellable_poll_simple
+g_cancellable_poll_full
GCancellableSourceFunc
g_cancellable_get_current
g_cancellable_pop_current
diff --git a/gio/gcancellable.c b/gio/gcancellable.c
index 258b88d..533ae99 100644
--- a/gio/gcancellable.c
+++ b/gio/gcancellable.c
@@ -25,6 +25,9 @@
#include "gcancellable.h"
#include "glibintl.h"
+#include <string.h>
+#include <errno.h>
+
/**
* SECTION:gcancellable
@@ -457,6 +460,241 @@ g_cancellable_release_fd (GCancellable *cancellable)
}
/**
+ * g_cancellable_poll_simple:
+ * @cancellable: (nullable): a #GCancellable object
+ * @pollfd: a single #GPollFD record to poll
+ * @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.
+ *
+ * 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.
+ *
+ * If the condition requested by @pollfd becomes ready then the revents
+ * field of @pollfd will be updated accordingly and %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 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.
+ *
+ * @cancellable can be %NULL, in which case cancellation is not checked
+ * for.
+ *
+ * See g_cancellable_poll_full() for a more powerful version of this
+ * call, if you need it.
+ *
+ * Returns: %TRUE if the requested condition was met, or %FALSE on error
+ * or cancellation
+ *
+ * Since: 2.44
+ **/
+gint
+g_cancellable_poll_simple (GCancellable *cancellable,
+ GPollFD *pollfd,
+ gint64 ready_time,
+ GError **error)
+{
+ GPollFD fds[2];
+ guint nfds;
+ gint timeout;
+ gint result;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ fds[0] = *pollfd;
+ nfds = 1;
+
+ nfds += g_cancellable_make_pollfd (cancellable, &fds[1]);
+ fds[1].revents = 0; /* we check this below */
+
+again:
+ 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;
+
+ result = g_poll (fds, nfds, timeout);
+
+ if (result == -1)
+ {
+ gint saved_errno = errno;
+
+ if (saved_errno == EINTR)
+ goto again;
+
+ g_set_error_literal (error, G_IO_ERROR,
+ g_io_error_from_errno (saved_errno),
+ g_strerror (saved_errno));
+
+ goto out;
+ }
+
+ 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;
+ }
+
+ if (result && fds[1].revents)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ result = -1;
+ goto out;
+ }
+
+ pollfd->revents = fds[0].revents;
+
+out:
+ g_cancellable_release_fd (cancellable);
+
+ return result != -1;
+}
+
+/**
+ * g_cancellable_poll_full:
+ * @cancellable: (nullable): a #GCancellable object
+ * @pollfds: an array of #GPollFD records to poll
+ * @nfds: the length of @pollfds
+ * @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.
+ *
+ * @cancellable can be %NULL, in which case cancellation is not checked
+ * for.
+ *
+ * g_cancellable_poll_simple() will be easier to use for most cases.
+ *
+ * Returns: the number of @pollfds that are ready, or -1 on error
+ *
+ * Since: 2.44
+ **/
+gint
+g_cancellable_poll_full (GCancellable *cancellable,
+ GPollFD *pollfds,
+ guint nfds,
+ gint64 ready_time,
+ GError **error)
+{
+ GPollFD *all_pollfds;
+ gint all_nfds;
+ gint timeout;
+ gint result;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ if (cancellable)
+ {
+ /* 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);
+
+ 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 (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;
+
+ result = g_poll (all_pollfds, all_nfds, timeout);
+
+ if (result == -1)
+ {
+ gint saved_errno = errno;
+
+ g_set_error_literal (error, G_FILE_ERROR,
+ g_file_error_from_errno (saved_errno),
+ g_strerror (saved_errno));
+ goto out;
+ }
+
+ 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 (cancellable)
+ memcpy (pollfds, all_pollfds + 1, nfds * sizeof (GPollFD));
+
+out:
+ g_cancellable_release_fd (cancellable);
+
+ if (cancellable && nfds >= 1024)
+ g_free (all_pollfds);
+
+ return result;
+}
+
+/**
* g_cancellable_cancel:
* @cancellable: a #GCancellable object.
*
diff --git a/gio/gcancellable.h b/gio/gcancellable.h
index fec7382..493e5ff 100644
--- a/gio/gcancellable.h
+++ b/gio/gcancellable.h
@@ -88,6 +88,18 @@ gboolean g_cancellable_make_pollfd (GCancellable *cancellable,
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,
+ gint64 ready_time,
+ GError **error);
+GLIB_AVAILABLE_IN_2_44
+gint g_cancellable_poll_full (GCancellable *cancellable,
+ GPollFD *pollfds,
+ guint nfds,
+ gint64 ready_time,
+ GError **error);
+
GLIB_AVAILABLE_IN_ALL
GSource * g_cancellable_source_new (GCancellable *cancellable);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]