[glib/wip/oholy/gunixmountmonitor-thread-safe: 1/4] gunixmounts: Make GUnixMountMonitor thread-safe



commit 972b9776596627a5953792122c1f939556956bc3
Author: Ondrej Holy <oholy redhat com>
Date:   Mon Feb 10 16:00:42 2020 +0100

    gunixmounts: Make GUnixMountMonitor thread-safe
    
    The Nautilus test suite often crashes with "GLib-FATAL-CRITICAL:
    g_source_is_destroyed: assertion 'g_atomic_int_get (&source->ref_count)
    > 0' failed" if it is started with "GIO_USE_VOLUME_MONITOR=unix". This
    is because GUnixMountMonitor is simultaneously used from multiple
    threads over GLocalFile and GVolumeMonitor APIs. Let's add guards for
    proc_mounts_watch_source and mount_poller_time variables to prevent
    those crashes.
    
    Fixes: https://gitlab.gnome.org/GNOME/glib/issues/2030

 gio/gunixmounts.c | 36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)
---
diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c
index cbf2ee99e..b716f22e4 100644
--- a/gio/gunixmounts.c
+++ b/gio/gunixmounts.c
@@ -152,7 +152,11 @@ static GList *_g_get_unix_mounts (void);
 static GList *_g_get_unix_mount_points (void);
 static gboolean proc_mounts_watch_is_running (void);
 
+G_LOCK_DEFINE_STATIC (proc_mounts_source);
+
+/* Protected by proc_mounts_source lock */
 static guint64 mount_poller_time = 0;
+static GSource *proc_mounts_watch_source;
 
 #ifdef HAVE_SYS_MNTTAB_H
 #define MNTOPT_RO      "ro"
@@ -1485,18 +1489,21 @@ get_mounts_timestamp (void)
 {
   const char *monitor_file;
   struct stat buf;
+  guint64 timestamp = 0;
+
+  G_LOCK (proc_mounts_source);
 
   monitor_file = get_mtab_monitor_file ();
   /* Don't return mtime for /proc/ files */
   if (monitor_file && !g_str_has_prefix (monitor_file, "/proc/"))
     {
       if (stat (monitor_file, &buf) == 0)
-        return (guint64)buf.st_mtime;
+        timestamp = buf.st_mtime;
     }
   else if (proc_mounts_watch_is_running ())
     {
       /* it's being monitored by poll, so return mount_poller_time */
-      return mount_poller_time;
+      timestamp = mount_poller_time;
     }
   else
     {
@@ -1505,9 +1512,12 @@ get_mounts_timestamp (void)
        * return TRUE so any application caches depending on it (like eg.
        * the one in GIO) get invalidated and don't hold possibly outdated
        * data - see Bug 787731 */
-     return (guint64) g_get_monotonic_time ();
+     timestamp = g_get_monotonic_time ();
     }
-  return 0;
+
+  G_UNLOCK (proc_mounts_source);
+
+  return timestamp;
 }
 
 static guint64
@@ -1704,10 +1714,10 @@ G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT)
 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 guint                  mtab_file_changed_id;
 
+/* Called with proc_mounts_source lock held. */
 static gboolean
 proc_mounts_watch_is_running (void)
 {
@@ -1768,7 +1778,10 @@ proc_mounts_changed (GIOChannel   *channel,
 {
   if (cond & G_IO_ERR)
     {
+      G_LOCK (proc_mounts_source);
       mount_poller_time = (guint64) g_get_monotonic_time ();
+      G_UNLOCK (proc_mounts_source);
+
       g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
     }
 
@@ -1802,7 +1815,10 @@ mount_change_poller (gpointer user_data)
 
   if (has_changed)
     {
+      G_LOCK (proc_mounts_source);
       mount_poller_time = (guint64) g_get_monotonic_time ();
+      G_UNLOCK (proc_mounts_source);
+
       g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
     }
 
@@ -1819,11 +1835,13 @@ mount_monitor_stop (void)
       g_object_unref (fstab_monitor);
     }
 
+  G_LOCK (proc_mounts_source);
   if (proc_mounts_watch_source != NULL)
     {
       g_source_destroy (proc_mounts_watch_source);
       proc_mounts_watch_source = NULL;
     }
+  G_UNLOCK (proc_mounts_source);
 
   if (mtab_monitor)
     {
@@ -1869,6 +1887,8 @@ mount_monitor_start (void)
             }
           else
             {
+              G_LOCK (proc_mounts_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,
@@ -1877,6 +1897,8 @@ mount_monitor_start (void)
                                g_main_context_get_thread_default ());
               g_source_unref (proc_mounts_watch_source);
               g_io_channel_unref (proc_mounts_channel);
+
+              G_UNLOCK (proc_mounts_source);
             }
         }
       else
@@ -1889,6 +1911,8 @@ mount_monitor_start (void)
     }
   else
     {
+      G_LOCK (proc_mounts_source);
+
       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 ();
@@ -1898,6 +1922,8 @@ mount_monitor_start (void)
       g_source_attach (proc_mounts_watch_source,
                        g_main_context_get_thread_default ());
       g_source_unref (proc_mounts_watch_source);
+
+      G_UNLOCK (proc_mounts_source);
     }
 }
 


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