[glib/wip/new-gsource: 5/8] gsource: Add support for 'handles'
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/new-gsource: 5/8] gsource: Add support for 'handles'
- Date: Tue, 30 Oct 2012 12:02:38 +0000 (UTC)
commit ff3cb012c1af72421dd10c2ed372261a7618ef3a
Author: Ryan Lortie <desrt desrt ca>
Date: Mon Oct 29 18:54:22 2012 +0100
gsource: Add support for 'handles'
Handles (as in g_source_add_handle(), a new API) provide similar
functionality to the old g_source_add_poll() API with two main
differences.
First: the list of handles is managed internally and therefore users are
prevented from randomly modifying the ->events field. This prepares us
for an epoll future where changing the event mask is a syscall.
Second: keeping the list internally allows us to check the ->revents for
events for ourselves, allowing the source to skip implementing
check/prepare. This also prepares us from the future by allowing an
implementation that doesn't need to iterate over all of the sources
every time.
https://bugzilla.gnome.org/show_bug.cgi?id=686853
docs/reference/glib/glib-sections.txt | 4 +
glib/glib.symbols | 4 +
glib/gmain.c | 254 ++++++++++++++++++++++++++++++++-
glib/gmain.h | 10 ++
glib/gpoll.h | 2 +-
5 files changed, 268 insertions(+), 6 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 2ac3429..42ec0f9 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -529,6 +529,10 @@ g_source_get_context
g_source_set_callback
GSourceFunc
g_source_set_callback_indirect
+g_source_add_handle
+g_source_remove_handle
+g_source_modify_handle
+g_source_query_handle
g_source_add_poll
g_source_remove_poll
g_source_add_child_source
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 2ae79d9..92df304 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -627,6 +627,7 @@ g_main_loop_ref
g_main_loop_run
g_main_loop_unref
g_source_add_child_source
+g_source_add_handle
g_source_add_poll
g_source_attach
g_source_destroy
@@ -637,12 +638,15 @@ g_source_get_current_time
g_source_get_id
g_source_get_name
g_source_get_priority
+g_source_modify_handle
g_source_new
+g_source_query_handle
g_source_ref
g_source_remove
g_source_remove_by_funcs_user_data
g_source_remove_by_user_data
g_source_remove_child_source
+g_source_remove_handle
g_source_remove_poll
g_source_set_callback
g_source_set_callback_indirect
diff --git a/glib/gmain.c b/glib/gmain.c
index 6721f09..4d66e89 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -315,6 +315,9 @@ struct _GSourcePrivate
{
GSList *child_sources;
GSource *parent_source;
+
+ GPollFD **handles;
+ gint n_handles;
};
typedef struct _GSourceIter
@@ -1033,6 +1036,7 @@ g_source_attach_unlocked (GSource *source,
{
guint result = 0;
GSList *tmp_list;
+ gint i;
source->context = context;
result = source->source_id = context->next_id++;
@@ -1047,6 +1051,14 @@ g_source_attach_unlocked (GSource *source,
tmp_list = tmp_list->next;
}
+ for (i = 0; i < source->priv->n_handles; i++)
+ {
+ GPollFD *handle = source->priv->handles[i];
+
+ if (handle != NULL)
+ g_main_context_add_poll_unlocked (context, source->priority, handle);
+ }
+
tmp_list = source->priv->child_sources;
while (tmp_list)
{
@@ -1126,12 +1138,22 @@ g_source_destroy_internal (GSource *source,
if (!SOURCE_BLOCKED (source))
{
+ gint i;
+
tmp_list = source->poll_fds;
while (tmp_list)
{
g_main_context_remove_poll_unlocked (context, tmp_list->data);
tmp_list = tmp_list->next;
}
+
+ for (i = 0; i < source->priv->n_handles; i++)
+ {
+ GPollFD *handle = source->priv->handles[i];
+
+ if (handle != NULL)
+ g_main_context_remove_poll_unlocked (context, handle);
+ }
}
while (source->priv->child_sources)
@@ -1563,6 +1585,8 @@ g_source_set_priority_unlocked (GSource *source,
if (!SOURCE_BLOCKED (source))
{
+ gint i;
+
tmp_list = source->poll_fds;
while (tmp_list)
{
@@ -1571,6 +1595,17 @@ g_source_set_priority_unlocked (GSource *source,
tmp_list = tmp_list->next;
}
+
+ for (i = 0; i < source->priv->n_handles; i++)
+ {
+ GPollFD *handle = source->priv->handles[i];
+
+ if (handle != NULL)
+ {
+ g_main_context_remove_poll_unlocked (context, handle);
+ g_main_context_add_poll_unlocked (context, priority, handle);
+ }
+ }
}
}
@@ -1805,6 +1840,8 @@ g_source_unref_internal (GSource *source,
source->ref_count--;
if (source->ref_count == 0)
{
+ gint i;
+
old_cb_data = source->callback_data;
old_cb_funcs = source->callback_funcs;
@@ -1833,6 +1870,10 @@ g_source_unref_internal (GSource *source,
g_slist_free (source->poll_fds);
source->poll_fds = NULL;
+ for (i = 0; i < source->priv->n_handles; i++)
+ g_free (source->priv->handles[i]);
+ g_free (source->priv->handles);
+
g_slice_free (GSourcePrivate, source->priv);
source->priv = NULL;
@@ -2087,6 +2128,176 @@ g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
}
/**
+ * g_source_add_handle:
+ * @source: a #GSource
+ * @handle: the #GHandle to monitor
+ * @events: an event mask
+ *
+ * Monitors @handle for the IO events in @events.
+ *
+ * The tag returned by this function can be used to remove or modify the
+ * monitoring of the handle using g_source_remove_handle() or
+ * g_source_modify_handle().
+ *
+ * It is not necessary to remove the handle before destroying the
+ * source; it will be cleaned up automatically.
+ *
+ * Returns: a tag
+ *
+ * Since: 2.36
+ **/
+guint
+g_source_add_handle (GSource *source,
+ GHandle handle,
+ GIOCondition events)
+{
+ GMainContext *context;
+ GPollFD *poll_fd;
+ guint tag;
+
+ g_return_val_if_fail (source != NULL, -1);
+ g_return_val_if_fail (!SOURCE_DESTROYED (source), -1);
+
+ context = source->context;
+
+ if (context)
+ LOCK_CONTEXT (context);
+
+ for (tag = 0; tag < source->priv->n_handles; tag++)
+ if (source->priv->handles[tag] == NULL)
+ break;
+
+ /* Since we store pointers to the GPollFD into the GMainContext we
+ * can't be calling g_renew() on them (or the memory would move).
+ *
+ * We need to add another layer of pointer indirection...
+ */
+ if (tag == source->priv->n_handles)
+ source->priv->handles = g_renew (GPollFD *, source->priv->handles, ++source->priv->n_handles);
+
+ poll_fd = g_slice_new (GPollFD);
+ source->priv->handles[tag] = poll_fd;
+ poll_fd->fd = (gssize) handle;
+ poll_fd->events = events;
+ poll_fd->revents = 0;
+
+ if (context)
+ {
+ if (!SOURCE_BLOCKED (source))
+ g_main_context_add_poll_unlocked (context, source->priority, poll_fd);
+ UNLOCK_CONTEXT (context);
+ }
+
+ return tag;
+}
+
+/**
+ * g_source_modify_handle:
+ * @source: a #GSource
+ * @tag: the tag from g_source_add_handle()
+ * @new_events: the new event mask to watch
+ *
+ * Updates the event mask to watch for the handle identified by @tag.
+ *
+ * @tag is the tag returned from g_source_add_handle().
+ *
+ * If you want to remove a handle, don't set its event mask to zero.
+ * Instead, call g_source_remove_handle().
+ *
+ * Since: 2.36
+ **/
+void
+g_source_modify_handle (GSource *source,
+ guint tag,
+ GIOCondition new_events)
+{
+ GMainContext *context;
+ GPollFD *poll_fd;
+
+ g_return_if_fail (source != NULL);
+ g_return_if_fail (tag < source->priv->n_handles);
+
+ context = source->context;
+
+ poll_fd = source->priv->handles[tag];
+ poll_fd->events = new_events;
+
+ if (context)
+ g_main_context_wakeup (context);
+}
+
+/**
+ * g_source_remove_handle:
+ * @source: a #GSource
+ * @tag: the tag from g_source_add_handle()
+ *
+ * Reverses the effect of a previous call to g_source_add_handle().
+ *
+ * You only need to call this if you want to remove a handle from being
+ * watched while keeping the same source around. In the normal case you
+ * will just want to destroy the source.
+ *
+ * Since: 2.36
+ **/
+void
+g_source_remove_handle (GSource *source,
+ guint tag)
+{
+ GMainContext *context;
+ GPollFD *poll_fd;
+
+ g_return_if_fail (source != NULL);
+ g_return_if_fail (tag < source->priv->n_handles);
+
+ context = source->context;
+
+ if (context)
+ LOCK_CONTEXT (context);
+
+ poll_fd = source->priv->handles[tag];
+ source->priv->handles[tag] = NULL;
+
+ if (context)
+ {
+ if (!SOURCE_BLOCKED (source))
+ g_main_context_remove_poll_unlocked (context, poll_fd);
+
+ UNLOCK_CONTEXT (context);
+ }
+
+ g_slice_free (GPollFD, poll_fd);
+}
+
+/**
+ * g_source_query_handle:
+ * @source: a #GSource
+ * @tag: the tag from g_source_add_handle()
+ *
+ * Queries the events reported for the file handle corresponding to
+ * @tag on @source during the last poll.
+ *
+ * The return value of this function is only defined when the function
+ * is called from the check or dispatch functions for @source.
+ *
+ * Returns: the conditions reported on the handle
+ *
+ * Since: 2.36
+ **/
+GIOCondition
+g_source_query_handle (GSource *source,
+ guint tag)
+{
+ GPollFD *poll_fd;
+
+ g_return_val_if_fail (source != NULL, 0);
+ g_return_val_if_fail (tag < source->priv->n_handles, 0);
+
+ poll_fd = source->priv->handles[tag];
+
+ return poll_fd->revents;
+}
+
+/**
* g_get_current_time:
* @result: #GTimeVal structure in which to store current time.
*
@@ -2599,6 +2810,7 @@ static void
block_source (GSource *source)
{
GSList *tmp_list;
+ gint i;
g_return_if_fail (!SOURCE_BLOCKED (source));
@@ -2611,6 +2823,14 @@ block_source (GSource *source)
tmp_list = tmp_list->next;
}
+ for (i = 0; i < source->priv->n_handles; i++)
+ {
+ GPollFD *handle = source->priv->handles[i];
+
+ if (handle != NULL)
+ g_main_context_remove_poll_unlocked (source->context, handle);
+ }
+
if (source->priv && source->priv->child_sources)
{
tmp_list = source->priv->child_sources;
@@ -2627,7 +2847,8 @@ static void
unblock_source (GSource *source)
{
GSList *tmp_list;
-
+ gint i;
+
g_return_if_fail (SOURCE_BLOCKED (source)); /* Source already unblocked */
g_return_if_fail (!SOURCE_DESTROYED (source));
@@ -2640,6 +2861,14 @@ unblock_source (GSource *source)
tmp_list = tmp_list->next;
}
+ for (i = 0; i < source->priv->n_handles; i++)
+ {
+ GPollFD *handle = source->priv->handles[i];
+
+ if (handle != NULL)
+ g_main_context_add_poll_unlocked (source->context, source->priority, handle);
+ }
+
if (source->priv && source->priv->child_sources)
{
tmp_list = source->priv->child_sources;
@@ -3171,12 +3400,9 @@ g_main_context_check (GMainContext *context,
check = source->source_funcs ? source->source_funcs->check : NULL;
- /* If the check function is set, call it.
- *
- * Otherwise assume it would return FALSE.
- */
if (check)
{
+ /* If the check function is set, call it. */
context->in_check_or_prepare++;
UNLOCK_CONTEXT (context);
@@ -3186,6 +3412,24 @@ g_main_context_check (GMainContext *context,
context->in_check_or_prepare--;
}
+ else
+ {
+ /* Otherwise, we are ready in the case that any of our
+ * handles are ready.
+ *
+ * Note: handles are not checked if the source has its own
+ * check function. In that case, it has to do it itself.
+ */
+ gint i;
+
+ for (i = 0; i < source->priv->n_handles; i++)
+ if (source->priv->handles[i]->fd != -1 && source->priv->handles[i]->revents)
+ {
+ result = TRUE;
+ break;
+ }
+ }
+
if (result)
{
GSource *ready_source = source;
diff --git a/glib/gmain.h b/glib/gmain.h
index a40cb93..eaa6bb6 100644
--- a/glib/gmain.h
+++ b/glib/gmain.h
@@ -410,6 +410,16 @@ const char * g_source_get_name (GSource *source);
void g_source_set_name_by_id (guint tag,
const char *name);
+guint g_source_add_handle (GSource *source,
+ GHandle handle,
+ GIOCondition events);
+void g_source_modify_handle (GSource *source,
+ guint tag,
+ GIOCondition new_events);
+void g_source_remove_handle (GSource *source,
+ guint tag);
+GIOCondition g_source_query_handle (GSource *source,
+ guint tag);
/* Used to implement g_source_connect_closure and internally*/
void g_source_set_callback_indirect (GSource *source,
diff --git a/glib/gpoll.h b/glib/gpoll.h
index e28bf6f..2bed9e2 100644
--- a/glib/gpoll.h
+++ b/glib/gpoll.h
@@ -102,7 +102,7 @@ struct _GPollFD
};
/**
- * ghandle:
+ * GHandle:
*
* Corresponds to the type of a file handle on the current operating
* system. On UNIX this is an integer (file descriptor). On Windows,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]