[glib] GSource: new API g_source_set_ready_time()



commit 768574635dcb69e91a2b749467ef3c75ed16579f
Author: Ryan Lortie <desrt desrt ca>
Date:   Mon Jan 14 16:51:51 2013 -0500

    GSource: new API g_source_set_ready_time()
    
    Add an API to mark a GSource to automatically become ready at the
    specified monotonic time.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=657729

 docs/reference/glib/glib-sections.txt |    2 +
 glib/glib.symbols                     |    2 +
 glib/gmain.c                          |  109 +++++++++++++++++++++++++++++++++
 glib/gmain.h                          |    9 +++-
 4 files changed, 121 insertions(+), 1 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index e12a855..e851942 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -528,6 +528,8 @@ g_source_get_context
 g_source_set_callback
 GSourceFunc
 g_source_set_callback_indirect
+g_source_set_ready_time
+g_source_get_ready_time
 g_source_add_poll
 g_source_remove_poll
 g_source_add_child_source
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 724e8d9..b8f39b0 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -638,6 +638,7 @@ g_source_get_current_time
 g_source_get_id
 g_source_get_name
 g_source_get_priority
+g_source_get_ready_time
 g_source_new
 g_source_ref
 g_source_remove
@@ -653,6 +654,7 @@ g_source_set_name
 g_source_set_name_by_id
 g_source_is_destroyed
 g_source_set_priority
+g_source_set_ready_time
 g_source_unref
 g_idle_add
 g_idle_add_full
diff --git a/glib/gmain.c b/glib/gmain.c
index 071694c..b294459 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -317,6 +317,8 @@ struct _GSourcePrivate
 {
   GSList *child_sources;
   GSource *parent_source;
+
+  gint64 ready_time;
 };
 
 typedef struct _GSourceIter
@@ -853,6 +855,8 @@ g_source_new (GSourceFuncs *source_funcs,
 
   source->flags = G_HOOK_FLAG_ACTIVE;
 
+  source->priv->ready_time = -1;
+
   /* NULL/0 initialization for all other fields */
   
   return source;
@@ -1698,6 +1702,73 @@ g_source_get_priority (GSource *source)
 }
 
 /**
+ * g_source_set_ready_time:
+ * @source: a #GSource
+ * @ready_time: the monotonic time at which the source will be ready,
+ *              0 for "immediately", -1 for "never"
+ *
+ * Sets a #GSource to be dispatched when the given monotonic time is
+ * reached (or passed).  If the monotonic time is in the past (as it
+ * always will be if @ready_time is 0) then the source will be
+ * dispatched immediately.
+ *
+ * If @ready_time is -1 then the source is never woken up on the basis
+ * of the passage of time.
+ *
+ * Dispatching the source does not reset the ready time.  You should do
+ * so yourself, from the source dispatch function.
+ *
+ * Since: 2.36
+ **/
+void
+g_source_set_ready_time (GSource *source,
+                         gint64   ready_time)
+{
+  GMainContext *context;
+
+  g_return_if_fail (source != NULL);
+  g_return_if_fail (source->ref_count > 0);
+
+  if (source->priv->ready_time == ready_time)
+    return;
+
+  context = source->context;
+
+  if (context)
+    LOCK_CONTEXT (context);
+
+  source->priv->ready_time = ready_time;
+
+  if (context)
+    {
+      /* Quite likely that we need to change the timeout on the poll */
+      if (!SOURCE_BLOCKED (source))
+        g_wakeup_signal (context->wakeup);
+      UNLOCK_CONTEXT (context);
+    }
+}
+
+/**
+ * g_source_get_ready_time:
+ * @source: a #GSource
+ *
+ * Gets the "ready time" of @source, as set by
+ * g_source_set_ready_time().
+ *
+ * Any time before the current monotonic time (including 0) is an
+ * indication that the source will fire immediately.
+ *
+ * Returns: the monotonic ready time, -1 for "never"
+ **/
+gint64
+g_source_get_ready_time (GSource *source)
+{
+  g_return_val_if_fail (source != NULL, -1);
+
+  return source->priv->ready_time;
+}
+
+/**
  * g_source_set_can_recurse:
  * @source: a #GSource
  * @can_recurse: whether recursion is allowed for this source
@@ -3066,6 +3137,31 @@ g_main_context_prepare (GMainContext *context,
               result = FALSE;
             }
 
+          if (result == FALSE && source->priv->ready_time != -1)
+            {
+              if (!context->time_is_fresh)
+                {
+                  context->time = g_get_monotonic_time ();
+                  context->time_is_fresh = TRUE;
+                }
+
+              if (source->priv->ready_time <= context->time)
+                {
+                  source_timeout = 0;
+                  result = TRUE;
+                }
+              else
+                {
+                  gint timeout;
+
+                  /* rounding down will lead to spinning, so always round up */
+                  timeout = (source->priv->ready_time - context->time + 999) / 1000;
+
+                  if (source_timeout < 0 || timeout < source_timeout)
+                    source_timeout = timeout;
+                }
+            }
+
 	  if (result)
 	    {
 	      GSource *ready_source = source;
@@ -3243,6 +3339,7 @@ g_main_context_check (GMainContext *context,
 
           if (check)
             {
+              /* If the check function is set, call it. */
               context->in_check_or_prepare++;
               UNLOCK_CONTEXT (context);
 
@@ -3254,6 +3351,18 @@ g_main_context_check (GMainContext *context,
           else
             result = FALSE;
 
+          if (result == FALSE && source->priv->ready_time != -1)
+            {
+              if (!context->time_is_fresh)
+                {
+                  context->time = g_get_monotonic_time ();
+                  context->time_is_fresh = TRUE;
+                }
+
+              if (source->priv->ready_time <= context->time)
+                result = TRUE;
+            }
+
 	  if (result)
 	    {
 	      GSource *ready_source = source;
diff --git a/glib/gmain.h b/glib/gmain.h
index 04cf2f8..e8d64f4 100644
--- a/glib/gmain.h
+++ b/glib/gmain.h
@@ -88,7 +88,9 @@ typedef struct _GSourceCallbackFuncs    GSourceCallbackFuncs;
  *     be -1 if all sources returned -1, or it will be the minimum of all the
  *     @timeout_ values returned which were >= 0.  Since 2.36 this may
  *     be %NULL, in which case the effect is as if the function always
- *     returns %FALSE with a timeout of -1.
+ *     returns %FALSE with a timeout of -1.  If @prepare returns a
+ *     timeout and the source also has a 'ready time' set then the
+ *     nearer of the two will be used.
  * @check: Called after all the file descriptors are polled. The source
  *     should return %TRUE if it is ready to be dispatched. Note that some
  *     time may have passed since the previous prepare function was called,
@@ -462,6 +464,11 @@ GLIB_AVAILABLE_IN_ALL
 void                 g_source_set_name_by_id (guint           tag,
                                               const char     *name);
 
+GLIB_AVAILABLE_IN_2_36
+void                 g_source_set_ready_time (GSource        *source,
+                                              gint64          ready_time);
+GLIB_AVAILABLE_IN_2_36
+gint64               g_source_get_ready_time (GSource        *source);
 
 /* Used to implement g_source_connect_closure and internally*/
 GLIB_AVAILABLE_IN_ALL



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]