[glib: 3/4] gmain: Refactor idle-once and timeout-once to avoid a closure allocation




commit 6db112f9a7f5ef353a46857d9f4608ae99579541
Author: Philip Withnall <pwithnall endlessos org>
Date:   Fri May 27 13:23:21 2022 +0100

    gmain: Refactor idle-once and timeout-once to avoid a closure allocation
    
    Instead store a bit inside `GTimeoutSource` and `GIdleSource` to
    indicate that they are one-shot sources, and that their callbacks have a
    different type and should always be assumed to return `G_SOURCE_REMOVE`.
    
    This should make one-shot idle and timeout sources a teeny weeny little
    bit cheaper to set up.
    
    From a suggestion here: https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2684#note_1462917
    
    Signed-off-by: Philip Withnall <pwithnall endlessos org>

 glib/gmain.c | 94 ++++++++++++++++++++++++++----------------------------------
 1 file changed, 40 insertions(+), 54 deletions(-)
---
diff --git a/glib/gmain.c b/glib/gmain.c
index ecff188bf0..a0ade8acbb 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -336,6 +336,7 @@ struct _GMainLoop
 struct _GIdleSource
 {
   GSource  source;
+  gboolean one_shot;
 };
 
 struct _GTimeoutSource
@@ -344,6 +345,7 @@ struct _GTimeoutSource
   /* Measured in seconds if 'seconds' is TRUE, or milliseconds otherwise. */
   guint       interval;
   gboolean    seconds;
+  gboolean    one_shot;
 };
 
 struct _GChildWatchSource
@@ -4976,7 +4978,16 @@ g_timeout_dispatch (GSource     *source,
       return FALSE;
     }
 
-  again = callback (user_data);
+  if (timeout_source->one_shot)
+    {
+      GSourceOnceFunc once_callback = (GSourceOnceFunc) callback;
+      once_callback (user_data);
+      again = G_SOURCE_REMOVE;
+    }
+  else
+    {
+      again = callback (user_data);
+    }
 
   TRACE (GLIB_TIMEOUT_DISPATCH (source, source->context, callback, user_data, again));
 
@@ -4988,13 +4999,15 @@ g_timeout_dispatch (GSource     *source,
 
 static GSource *
 timeout_source_new (guint    interval,
-                    gboolean seconds)
+                    gboolean seconds,
+                    gboolean one_shot)
 {
   GSource *source = g_source_new (&g_timeout_funcs, sizeof (GTimeoutSource));
   GTimeoutSource *timeout_source = (GTimeoutSource *)source;
 
   timeout_source->interval = interval;
   timeout_source->seconds = seconds;
+  timeout_source->one_shot = one_shot;
 
   g_timeout_set_expiration (timeout_source, g_get_monotonic_time ());
 
@@ -5019,7 +5032,7 @@ timeout_source_new (guint    interval,
 GSource *
 g_timeout_source_new (guint interval)
 {
-  return timeout_source_new (interval, FALSE);
+  return timeout_source_new (interval, FALSE, FALSE);
 }
 
 /**
@@ -5045,13 +5058,14 @@ g_timeout_source_new (guint interval)
 GSource *
 g_timeout_source_new_seconds (guint interval)
 {
-  return timeout_source_new (interval, TRUE);
+  return timeout_source_new (interval, TRUE, FALSE);
 }
 
 static guint
 timeout_add_full (gint           priority,
                   guint          interval,
                   gboolean       seconds,
+                  gboolean       one_shot,
                   GSourceFunc    function,
                   gpointer       data,
                   GDestroyNotify notify)
@@ -5061,7 +5075,7 @@ timeout_add_full (gint           priority,
 
   g_return_val_if_fail (function != NULL, 0);
 
-  source = timeout_source_new (interval, seconds);
+  source = timeout_source_new (interval, seconds, one_shot);
 
   if (priority != G_PRIORITY_DEFAULT)
     g_source_set_priority (source, priority);
@@ -5120,7 +5134,7 @@ g_timeout_add_full (gint           priority,
                    gpointer       data,
                    GDestroyNotify notify)
 {
-  return timeout_add_full (priority, interval, FALSE, function, data, notify);
+  return timeout_add_full (priority, interval, FALSE, FALSE, function, data, notify);
 }
 
 /**
@@ -5174,27 +5188,6 @@ g_timeout_add (guint32        interval,
                             interval, function, data, NULL);
 }
 
-typedef struct {
-  GSourceOnceFunc function;
-  gpointer data;
-} OnceData;
-
-static void
-once_data_free (gpointer data)
-{
-  g_free (data);
-}
-
-static gboolean
-once_function (gpointer data)
-{
-  OnceData *once_data = data;
-
-  once_data->function (once_data->data);
-
-  return G_SOURCE_REMOVE;
-}
-
 /**
  * g_timeout_add_once:
  * @interval: the time after which the function will be called, in
@@ -5219,19 +5212,7 @@ g_timeout_add_once (guint32         interval,
                     GSourceOnceFunc function,
                     gpointer        data)
 {
-  OnceData *once_data;
-
-  g_return_val_if_fail (function != NULL, 0);
-
-  once_data = g_new (OnceData, 1);
-  once_data->function = function;
-  once_data->data = data;
-
-  return g_timeout_add_full (G_PRIORITY_DEFAULT,
-                             interval,
-                             once_function,
-                             once_data,
-                             once_data_free);
+  return timeout_add_full (G_PRIORITY_DEFAULT, interval, FALSE, TRUE, (GSourceFunc) function, data, NULL);
 }
 
 /**
@@ -6002,6 +5983,7 @@ g_idle_dispatch (GSource    *source,
                 GSourceFunc callback,
                 gpointer    user_data)
 {
+  GIdleSource *idle_source = (GIdleSource *)source;
   gboolean again;
 
   if (!callback)
@@ -6011,7 +5993,16 @@ g_idle_dispatch (GSource    *source,
       return FALSE;
     }
 
-  again = callback (user_data);
+  if (idle_source->one_shot)
+    {
+      GSourceOnceFunc once_callback = (GSourceOnceFunc) callback;
+      once_callback (user_data);
+      again = G_SOURCE_REMOVE;
+    }
+  else
+    {
+      again = callback (user_data);
+    }
 
   TRACE (GLIB_IDLE_DISPATCH (source, source->context, callback, user_data, again));
 
@@ -6019,7 +6010,7 @@ g_idle_dispatch (GSource    *source,
 }
 
 static GSource *
-idle_source_new (void)
+idle_source_new (gboolean one_shot)
 {
   GSource *source;
   GIdleSource *idle_source;
@@ -6027,6 +6018,8 @@ idle_source_new (void)
   source = g_source_new (&g_idle_funcs, sizeof (GIdleSource));
   idle_source = (GIdleSource *) source;
 
+  idle_source->one_shot = one_shot;
+
   g_source_set_priority (source, G_PRIORITY_DEFAULT_IDLE);
 
   /* Set a default name on the source, just in case the caller does not. */
@@ -6051,11 +6044,12 @@ idle_source_new (void)
 GSource *
 g_idle_source_new (void)
 {
-  return idle_source_new ();
+  return idle_source_new (FALSE);
 }
 
 static guint
 idle_add_full (gint           priority,
+               gboolean       one_shot,
                GSourceFunc    function,
                gpointer       data,
                GDestroyNotify notify)
@@ -6065,7 +6059,7 @@ idle_add_full (gint           priority,
 
   g_return_val_if_fail (function != NULL, 0);
 
-  source = idle_source_new ();
+  source = idle_source_new (one_shot);
 
   if (priority != G_PRIORITY_DEFAULT_IDLE)
     g_source_set_priority (source, priority);
@@ -6111,7 +6105,7 @@ g_idle_add_full (gint           priority,
                 gpointer       data,
                 GDestroyNotify notify)
 {
-  return idle_add_full (priority, function, data, notify);
+  return idle_add_full (priority, FALSE, function, data, notify);
 }
 
 /**
@@ -6165,15 +6159,7 @@ guint
 g_idle_add_once (GSourceOnceFunc function,
                  gpointer        data)
 {
-  OnceData *once_data;
-
-  g_return_val_if_fail (function != NULL, 0);
-
-  once_data = g_new (OnceData, 1);
-  once_data->function = function;
-  once_data->data = data;
-
-  return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, once_function, once_data, once_data_free);
+  return idle_add_full (G_PRIORITY_DEFAULT_IDLE, TRUE, (GSourceFunc) function, data, NULL);
 }
 
 /**


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