[glib/wip/mount-watcher: 10/24] GContextSpecificGroup: support for complex signals



commit 34680b75275e331b9efa122c7d37ae8e6222c48d
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Jan 8 21:49:34 2015 -0500

    GContextSpecificGroup: support for complex signals
    
    Add support for non-VOID__VOID signals to GContextSpecificGroup.
    
    We keep the VOID__VOID case as a special optimised case by usual the
    usual bit-stealing tricks.

 gio/gappinfo.c              |    2 +-
 gio/gcontextspecificgroup.c |  122 +++++++++++++++++++++++++++++++++++++++----
 gio/gcontextspecificgroup.h |    4 +-
 gio/gunixmounts.c           |    8 ++--
 4 files changed, 120 insertions(+), 16 deletions(-)
---
diff --git a/gio/gappinfo.c b/gio/gappinfo.c
index fe2fa3d..4d97243 100644
--- a/gio/gappinfo.c
+++ b/gio/gappinfo.c
@@ -1131,5 +1131,5 @@ g_app_info_monitor_get (void)
 void
 g_app_info_monitor_fire (void)
 {
-  g_context_specific_group_emit (&g_app_info_monitor_group, g_app_info_monitor_changed_signal);
+  g_context_specific_group_emit (&g_app_info_monitor_group, g_app_info_monitor_changed_signal, 0);
 }
diff --git a/gio/gcontextspecificgroup.c b/gio/gcontextspecificgroup.c
index ff44578..a96d049 100644
--- a/gio/gcontextspecificgroup.c
+++ b/gio/gcontextspecificgroup.c
@@ -22,8 +22,97 @@
 #include "gcontextspecificgroup.h"
 
 #include <glib-object.h>
+#include <gobject/gvaluecollector.h>
 #include "glib-private.h"
 
+#include <string.h>
+
+typedef struct
+{
+  gint   ref_count;
+  guint  signal_id;
+  GQuark detail;
+  guint  n_params;
+  GValue params[1];
+} GContextSpecificEmission;
+
+static GContextSpecificEmission *
+g_context_specific_emission_newv (guint   signal_id,
+                                  GQuark  detail,
+                                  va_list ap)
+{
+  GContextSpecificEmission *emission;
+  GSignalQuery query;
+  guint i;
+
+  g_signal_query (signal_id, &query);
+
+  if (query.n_params == 0 && detail == 0)
+    return GUINT_TO_POINTER (signal_id * 2 + 1);
+
+  emission = g_malloc (G_STRUCT_OFFSET (GContextSpecificEmission, params[query.n_params]));
+  emission->ref_count = 1;
+  emission->signal_id = signal_id;
+  emission->detail = detail;
+  emission->n_params = query.n_params;
+
+  for (i = 0; i < query.n_params; i++)
+    {
+      gchar *error;
+
+      G_VALUE_COLLECT_INIT (&emission->params[i], query.param_types[i], ap, 0, &error);
+      if (error)
+        g_error ("g_contect_specific_emission_newv: %s", error);
+    }
+
+  return emission;
+}
+
+static GContextSpecificEmission *
+g_context_specific_emission_ref (GContextSpecificEmission *emission)
+{
+  if (~GPOINTER_TO_UINT (emission) & 1)
+    g_atomic_int_inc (&emission->ref_count);
+
+  return emission;
+}
+
+static void
+g_context_specific_emission_unref (GContextSpecificEmission *emission)
+{
+  if (~GPOINTER_TO_UINT (emission) & 1)
+    {
+      if (g_atomic_int_dec_and_test (&emission->ref_count))
+        {
+          guint i;
+
+          for (i = 0; i < emission->n_params; i++)
+            g_value_reset (&emission->params[i]);
+
+          g_free (emission);
+        }
+    }
+}
+
+static void
+g_context_specific_emission_emit_on_instance (GContextSpecificEmission *emission,
+                                              gpointer                  instance)
+{
+  if (~GPOINTER_TO_UINT (emission) & 1)
+    {
+      GValue *instance_and_params;
+
+      instance_and_params = g_newa (GValue, 1 + emission->n_params);
+      instance_and_params[0].g_type = G_TYPE_FROM_INSTANCE (instance);
+      instance_and_params[0].data[0].v_pointer = instance;
+      memcpy (instance_and_params + 1, emission->params, sizeof (GValue) * emission->n_params);
+
+      g_signal_emitv (instance_and_params, emission->signal_id, emission->detail, NULL);
+    }
+  else
+    g_signal_emit (instance, GPOINTER_TO_UINT (emission) / 2, 0);
+}
+
 typedef struct
 {
   GSource   source;
@@ -39,19 +128,20 @@ g_context_specific_source_dispatch (GSource     *source,
                                     gpointer     user_data)
 {
   GContextSpecificSource *css = (GContextSpecificSource *) source;
-  guint signal_id;
+  GContextSpecificEmission *emission;
 
   g_mutex_lock (&css->lock);
 
   g_assert (!g_queue_is_empty (&css->pending));
-  signal_id = GPOINTER_TO_UINT (g_queue_pop_head (&css->pending));
+  emission = g_queue_pop_head (&css->pending);
 
   if (g_queue_is_empty (&css->pending))
     g_source_set_ready_time (source, -1);
 
   g_mutex_unlock (&css->lock);
 
-  g_signal_emit (css->instance, signal_id, 0);
+  g_context_specific_emission_emit_on_instance (emission, css->instance);
+  g_context_specific_emission_unref (emission);
 
   return TRUE;
 }
@@ -61,8 +151,11 @@ g_context_specific_source_finalize (GSource *source)
 {
   GContextSpecificSource *css = (GContextSpecificSource *) source;
 
-  g_mutex_clear (&css->lock);
+  while (!g_queue_is_empty (&css->pending))
+    g_context_specific_emission_unref (g_queue_pop_head (&css->pending));
+
   g_queue_clear (&css->pending);
+  g_mutex_clear (&css->lock);
 }
 
 static GContextSpecificSource *
@@ -182,17 +275,23 @@ g_context_specific_group_remove (GContextSpecificGroup *group,
 
 void
 g_context_specific_group_emit (GContextSpecificGroup *group,
-                               guint                  signal_id)
+                               guint                  signal_id,
+                               GQuark                 detail,
+                               ...)
 {
+  GContextSpecificEmission *emission;
+  va_list ap;
+
+  va_start (ap, detail);
+  emission = g_context_specific_emission_newv (signal_id, detail, ap);
+  va_end (ap);
+
   g_mutex_lock (&group->lock);
 
   if (group->table)
     {
       GHashTableIter iter;
       gpointer value;
-      gpointer ptr;
-
-      ptr = GUINT_TO_POINTER (signal_id);
 
       g_hash_table_iter_init (&iter, group->table);
       while (g_hash_table_iter_next (&iter, NULL, &value))
@@ -201,8 +300,9 @@ g_context_specific_group_emit (GContextSpecificGroup *group,
 
           g_mutex_lock (&css->lock);
 
-          g_queue_remove (&css->pending, ptr);
-          g_queue_push_tail (&css->pending, ptr);
+          /* this will find repeat instances of void handlers */
+          if (!g_queue_find (&css->pending, emission))
+            g_queue_push_tail (&css->pending, g_context_specific_emission_ref (emission));
 
           g_source_set_ready_time ((GSource *) css, 0);
 
@@ -211,4 +311,6 @@ g_context_specific_group_emit (GContextSpecificGroup *group,
     }
 
   g_mutex_unlock (&group->lock);
+
+  g_context_specific_emission_unref (emission);
 }
diff --git a/gio/gcontextspecificgroup.h b/gio/gcontextspecificgroup.h
index bd2ea5d..5f538d4 100644
--- a/gio/gcontextspecificgroup.h
+++ b/gio/gcontextspecificgroup.h
@@ -42,6 +42,8 @@ g_context_specific_group_remove (GContextSpecificGroup *group,
 
 void
 g_context_specific_group_emit (GContextSpecificGroup *group,
-                               guint                  signal_id);
+                               guint                  signal_id,
+                               GQuark                 detail,
+                               ...);
 
 #endif /* __G_CONTEXT_SPECIFIC_GROUP_H__ */
diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c
index 518bc44..bef3f50 100644
--- a/gio/gunixmounts.c
+++ b/gio/gunixmounts.c
@@ -1303,7 +1303,7 @@ fstab_file_changed (GFileMonitor      *monitor,
       event_type != G_FILE_MONITOR_EVENT_DELETED)
     return;
 
-  g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
+  g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED], 0);
 }
 
 static void
@@ -1318,7 +1318,7 @@ mtab_file_changed (GFileMonitor      *monitor,
       event_type != G_FILE_MONITOR_EVENT_DELETED)
     return;
 
-  g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
+  g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED], 0);
 }
 
 static gboolean
@@ -1327,7 +1327,7 @@ proc_mounts_changed (GIOChannel   *channel,
                      gpointer      user_data)
 {
   if (cond & G_IO_ERR)
-    g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
+    g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED], 0);
 
   return TRUE;
 }
@@ -1360,7 +1360,7 @@ mount_change_poller (gpointer user_data)
   if (has_changed)
     {
       mount_poller_time = (guint64) g_get_monotonic_time ();
-      g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
+      g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED], 0);
     }
 
   return TRUE;


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