[glib] Make GUnixMountMonitor per-context



commit 548c165a9f8386af29e8bb8243d8923e0f315c2e
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Jan 8 01:35:33 2015 -0500

    Make GUnixMountMonitor per-context
    
    GUnixMountMonitor was not threadsafe before.  It was a global singleton
    which emitted signals in the first thread that happened to construct it.
    
    Move it to a per-context singleton model where each GMainContext gets
    its own GUnixMountMonitor.  Monitor for the changes from the GLib worker
    thread and dispatch the results to each context with an active monitor.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=742599

 gio/gunixmounts.c |  261 +++++++++++++++++++++++++++--------------------------
 1 files changed, 131 insertions(+), 130 deletions(-)
---
diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c
index 4e4f794..93fae3b 100644
--- a/gio/gunixmounts.c
+++ b/gio/gunixmounts.c
@@ -68,6 +68,7 @@
 #include "gfilemonitor.h"
 #include "glibintl.h"
 #include "gthemedicon.h"
+#include "gcontextspecificgroup.h"
 
 
 #ifdef HAVE_MNTENT_H
@@ -1274,124 +1275,50 @@ static guint signals[LAST_SIGNAL];
 struct _GUnixMountMonitor {
   GObject parent;
 
-  GFileMonitor *fstab_monitor;
-  GFileMonitor *mtab_monitor;
-
-  GList *mount_poller_mounts;
-
-  GSource *proc_mounts_watch_source;
+  GMainContext *context;
 };
 
 struct _GUnixMountMonitorClass {
   GObjectClass parent_class;
 };
 
-static GUnixMountMonitor *the_mount_monitor = NULL;
 
 G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT);
 
-static void
-g_unix_mount_monitor_finalize (GObject *object)
-{
-  GUnixMountMonitor *monitor;
-  
-  monitor = G_UNIX_MOUNT_MONITOR (object);
-
-  if (monitor->fstab_monitor)
-    {
-      g_file_monitor_cancel (monitor->fstab_monitor);
-      g_object_unref (monitor->fstab_monitor);
-    }
-  
-  if (monitor->proc_mounts_watch_source != NULL)
-    g_source_destroy (monitor->proc_mounts_watch_source);
-
-  if (monitor->mtab_monitor)
-    {
-      g_file_monitor_cancel (monitor->mtab_monitor);
-      g_object_unref (monitor->mtab_monitor);
-    }
-
-  g_list_free_full (monitor->mount_poller_mounts, (GDestroyNotify)g_unix_mount_free);
-
-  the_mount_monitor = NULL;
-
-  G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
-}
-
-
-static void
-g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  gobject_class->finalize = g_unix_mount_monitor_finalize;
- 
-  /**
-   * GUnixMountMonitor::mounts-changed:
-   * @monitor: the object on which the signal is emitted
-   * 
-   * Emitted when the unix mounts have changed.
-   */ 
-  signals[MOUNTS_CHANGED] =
-    g_signal_new ("mounts-changed",
-                 G_TYPE_FROM_CLASS (klass),
-                 G_SIGNAL_RUN_LAST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-
-  /**
-   * GUnixMountMonitor::mountpoints-changed:
-   * @monitor: the object on which the signal is emitted
-   * 
-   * Emitted when the unix mount points have changed.
-   */
-  signals[MOUNTPOINTS_CHANGED] =
-    g_signal_new ("mountpoints-changed",
-                 G_TYPE_FROM_CLASS (klass),
-                 G_SIGNAL_RUN_LAST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-}
+static GContextSpecificGroup  mount_monitor_group;
+static GFileMonitor          *fstab_monitor;
+static GFileMonitor          *mtab_monitor;
+static GSource               *proc_mounts_watch_source;
+static GList                 *mount_poller_mounts;
 
 static void
 fstab_file_changed (GFileMonitor      *monitor,
-                   GFile             *file,
-                   GFile             *other_file,
-                   GFileMonitorEvent  event_type,
-                   gpointer           user_data)
+                    GFile             *file,
+                    GFile             *other_file,
+                    GFileMonitorEvent  event_type,
+                    gpointer           user_data)
 {
-  GUnixMountMonitor *mount_monitor;
-
   if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
       event_type != G_FILE_MONITOR_EVENT_CREATED &&
       event_type != G_FILE_MONITOR_EVENT_DELETED)
     return;
 
-  mount_monitor = user_data;
-  g_signal_emit (mount_monitor, signals[MOUNTPOINTS_CHANGED], 0);
+  g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
 }
 
 static void
 mtab_file_changed (GFileMonitor      *monitor,
-                  GFile             *file,
-                  GFile             *other_file,
-                  GFileMonitorEvent  event_type,
-                  gpointer           user_data)
+                   GFile             *file,
+                   GFile             *other_file,
+                   GFileMonitorEvent  event_type,
+                   gpointer           user_data)
 {
-  GUnixMountMonitor *mount_monitor;
-
   if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
       event_type != G_FILE_MONITOR_EVENT_CREATED &&
       event_type != G_FILE_MONITOR_EVENT_DELETED)
     return;
-  
-  mount_monitor = user_data;
-  g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
+
+  g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
 }
 
 static gboolean
@@ -1399,23 +1326,21 @@ proc_mounts_changed (GIOChannel   *channel,
                      GIOCondition  cond,
                      gpointer      user_data)
 {
-  GUnixMountMonitor *mount_monitor = G_UNIX_MOUNT_MONITOR (user_data);
   if (cond & G_IO_ERR)
-    g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
+    g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
+
   return TRUE;
 }
 
 static gboolean
 mount_change_poller (gpointer user_data)
 {
-  GUnixMountMonitor *mount_monitor;
   GList *current_mounts, *new_it, *old_it;
   gboolean has_changed = FALSE;
 
-  mount_monitor = user_data;
   current_mounts = _g_get_unix_mounts ();
 
-  for ( new_it = current_mounts, old_it = mount_monitor->mount_poller_mounts;
+  for ( new_it = current_mounts, old_it = mount_poller_mounts;
         new_it != NULL && old_it != NULL;
         new_it = g_list_next (new_it), old_it = g_list_next (old_it) )
     {
@@ -1428,34 +1353,55 @@ mount_change_poller (gpointer user_data)
   if (!(new_it == NULL && old_it == NULL))
     has_changed = TRUE;
 
-  g_list_free_full (mount_monitor->mount_poller_mounts,
-                    (GDestroyNotify)g_unix_mount_free);
+  g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_free);
 
-  mount_monitor->mount_poller_mounts = current_mounts;
+  mount_poller_mounts = current_mounts;
 
   if (has_changed)
     {
-      mount_poller_time = (guint64)g_get_monotonic_time ();
-      g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
+      mount_poller_time = (guint64) g_get_monotonic_time ();
+      g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
     }
 
   return TRUE;
 }
 
+
 static void
-g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
+mount_monitor_stop (void)
+{
+  if (fstab_monitor)
+    {
+      g_file_monitor_cancel (fstab_monitor);
+      g_object_unref (fstab_monitor);
+    }
+
+  if (proc_mounts_watch_source != NULL)
+    g_source_destroy (proc_mounts_watch_source);
+
+  if (mtab_monitor)
+    {
+      g_file_monitor_cancel (mtab_monitor);
+      g_object_unref (mtab_monitor);
+    }
+
+  g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_free);
+}
+
+static void
+mount_monitor_start (void)
 {
   GFile *file;
-    
+
   if (get_fstab_file () != NULL)
     {
       file = g_file_new_for_path (get_fstab_file ());
-      monitor->fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
+      fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
       g_object_unref (file);
-      
-      g_signal_connect (monitor->fstab_monitor, "changed", (GCallback)fstab_file_changed, monitor);
+
+      g_signal_connect (fstab_monitor, "changed", (GCallback)fstab_file_changed, NULL);
     }
-  
+
   if (get_mtab_monitor_file () != NULL)
     {
       const gchar *mtab_path;
@@ -1477,39 +1423,93 @@ g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
             }
           else
             {
-              monitor->proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
-              g_source_set_callback (monitor->proc_mounts_watch_source,
+              proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
+              g_source_set_callback (proc_mounts_watch_source,
                                      (GSourceFunc) proc_mounts_changed,
-                                     monitor,
-                                     NULL);
-              g_source_attach (monitor->proc_mounts_watch_source,
+                                     NULL, NULL);
+              g_source_attach (proc_mounts_watch_source,
                                g_main_context_get_thread_default ());
-              g_source_unref (monitor->proc_mounts_watch_source);
+              g_source_unref (proc_mounts_watch_source);
               g_io_channel_unref (proc_mounts_channel);
             }
         }
       else
         {
           file = g_file_new_for_path (mtab_path);
-          monitor->mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
+          mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
           g_object_unref (file);
-          g_signal_connect (monitor->mtab_monitor, "changed", (GCallback)mtab_file_changed, monitor);
+          g_signal_connect (mtab_monitor, "changed", (GCallback)mtab_file_changed, NULL);
         }
     }
   else
     {
-      monitor->proc_mounts_watch_source = g_timeout_source_new_seconds (3);
-      monitor->mount_poller_mounts = _g_get_unix_mounts ();
+      proc_mounts_watch_source = g_timeout_source_new_seconds (3);
+      mount_poller_mounts = _g_get_unix_mounts ();
       mount_poller_time = (guint64)g_get_monotonic_time ();
-      g_source_set_callback (monitor->proc_mounts_watch_source,
-                             (GSourceFunc)mount_change_poller,
-                             monitor, NULL);
-      g_source_attach (monitor->proc_mounts_watch_source,
+      g_source_set_callback (proc_mounts_watch_source,
+                             mount_change_poller,
+                             NULL, NULL);
+      g_source_attach (proc_mounts_watch_source,
                        g_main_context_get_thread_default ());
-      g_source_unref (monitor->proc_mounts_watch_source);
+      g_source_unref (proc_mounts_watch_source);
     }
 }
 
+static void
+g_unix_mount_monitor_finalize (GObject *object)
+{
+  GUnixMountMonitor *monitor;
+
+  monitor = G_UNIX_MOUNT_MONITOR (object);
+
+  g_context_specific_group_remove (&mount_monitor_group, monitor->context, monitor, mount_monitor_stop);
+
+  G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
+}
+
+static void
+g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = g_unix_mount_monitor_finalize;
+ 
+  /**
+   * GUnixMountMonitor::mounts-changed:
+   * @monitor: the object on which the signal is emitted
+   * 
+   * Emitted when the unix mounts have changed.
+   */ 
+  signals[MOUNTS_CHANGED] =
+    g_signal_new ("mounts-changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST,
+                 0,
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
+  /**
+   * GUnixMountMonitor::mountpoints-changed:
+   * @monitor: the object on which the signal is emitted
+   * 
+   * Emitted when the unix mount points have changed.
+   */
+  signals[MOUNTPOINTS_CHANGED] =
+    g_signal_new ("mountpoints-changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST,
+                 0,
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+}
+
+static void
+g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
+{
+}
+
 /**
  * g_unix_mount_monitor_set_rate_limit:
  * @mount_monitor: a #GUnixMountMonitor
@@ -1537,12 +1537,16 @@ g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
 /**
  * g_unix_mount_monitor_get:
  *
- * Gets the #GUnixMountMonitor.
+ * Gets the #GUnixMountMonitor for the current thread-default main
+ * context.
  *
  * The mount monitor can be used to monitor for changes to the list of
  * mounted filesystems as well as the list of mount points (ie: fstab
  * entries).
  *
+ * You must only call g_object_unref() on the return value from under
+ * the same main context as you called this function.
+ *
  * Returns: (transfer full): the #GUnixMountMonitor.
  *
  * Since: 2.44
@@ -1550,13 +1554,10 @@ g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
 GUnixMountMonitor *
 g_unix_mount_monitor_get (void)
 {
-  if (the_mount_monitor == NULL)
-    {
-      the_mount_monitor = g_object_new (G_TYPE_UNIX_MOUNT_MONITOR, NULL);
-      return the_mount_monitor;
-    }
-  
-  return g_object_ref (the_mount_monitor);
+  return g_context_specific_group_get (&mount_monitor_group,
+                                       G_TYPE_UNIX_MOUNT_MONITOR,
+                                       G_STRUCT_OFFSET(GUnixMountMonitor, context),
+                                       mount_monitor_start);
 }
 
 /**


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