Commit 548c165a authored by Allison Karlitskaya's avatar Allison Karlitskaya

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
parent ae38d2bf
......@@ -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);
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment