summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gio/gdelayedsettingsbackend.c16
-rw-r--r--gio/gsettingsbackend.c87
-rw-r--r--gio/gsettingsbackendinternal.h2
3 files changed, 33 insertions, 72 deletions
diff --git a/gio/gdelayedsettingsbackend.c b/gio/gdelayedsettingsbackend.c
index bb3195abe..dce1d7d78 100644
--- a/gio/gdelayedsettingsbackend.c
+++ b/gio/gdelayedsettingsbackend.c
@@ -70,21 +70,7 @@ g_delayed_settings_backend_notify_unapplied (GDelayedSettingsBackend *delayed)
g_static_mutex_unlock (&delayed->priv->lock);
if (target != NULL)
- {
- if (g_settings_backend_get_active_context () != target_context)
- {
- GSource *source;
-
- source = g_idle_source_new ();
- g_source_set_priority (source, G_PRIORITY_DEFAULT);
- g_source_set_callback (source, invoke_notify_unapplied,
- target, g_object_unref);
- g_source_attach (source, target_context);
- g_source_unref (source);
- }
- else
- invoke_notify_unapplied (target);
- }
+ g_main_context_invoke (target_context, invoke_notify_unapplied, target);
}
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index bde0336d5..475d05540 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -119,26 +119,6 @@ is_path (const gchar *path)
return TRUE;
}
-GMainContext *
-g_settings_backend_get_active_context (void)
-{
- GMainContext *context;
- GSource *source;
-
- if ((source = g_main_current_source ()))
- context = g_source_get_context (source);
-
- else
- {
- context = g_main_context_get_thread_default ();
-
- if (context == NULL)
- context = g_main_context_default ();
- }
-
- return context;
-}
-
struct _GSettingsBackendWatch
{
GObject *target;
@@ -316,20 +296,7 @@ g_settings_backend_dispatch_signal (GSettingsBackend *backend,
GBoxedFreeFunc data1_free,
gpointer data2)
{
- GMainContext *context, *here_and_now;
- GSettingsBackendWatch *watch;
-
- /* We need to hold the mutex here (to prevent a node from being
- * deleted as we are traversing the list). Since we should not
- * re-enter user code while holding this mutex, we create a
- * one-time-use GMainContext and populate it with the events that we
- * would have called directly. We dispatch these events after
- * releasing the lock. Note that the GObject reference is acquired on
- * the target while holding the mutex and the mutex needs to be held
- * as part of the destruction of any GSettings instance (via the weak
- * reference handling). This is the key to the safety of the whole
- * setup.
- */
+ GSettingsBackendWatch *suffix, *watch, *next;
if (data1_copy == NULL)
data1_copy = pointer_id;
@@ -337,19 +304,34 @@ g_settings_backend_dispatch_signal (GSettingsBackend *backend,
if (data1_free == NULL)
data1_free = pointer_ignore;
- context = g_settings_backend_get_active_context ();
- here_and_now = g_main_context_new ();
-
- /* traverse the (immutable while holding lock) list */
+ /* We're in a little bit of a tricky situation here. We need to hold
+ * a lock while traversing the list, but we don't want to hold the
+ * lock while calling back into user code.
+ *
+ * Since we're not holding the lock while we call user code, we can't
+ * render the list immutable. We can, however, store a pointer to a
+ * given suffix of the list and render that suffix immutable.
+ *
+ * Adds will never modify the suffix since adds always come in the
+ * form of prepends. We can also prevent removes from modifying the
+ * suffix since removes only happen in response to the last reference
+ * count dropping -- so just add a reference to everything in the
+ * suffix.
+ */
g_static_mutex_lock (&backend->priv->lock);
- for (watch = backend->priv->watches; watch; watch = watch->next)
+ suffix = backend->priv->watches;
+ for (watch = suffix; watch; watch = watch->next)
+ g_object_ref (watch->target);
+ g_static_mutex_unlock (&backend->priv->lock);
+
+ /* The suffix is now immutable, so this is safe. */
+ for (watch = suffix; watch; watch = next)
{
GSettingsBackendClosure *closure;
- GSource *source;
closure = g_slice_new (GSettingsBackendClosure);
closure->backend = g_object_ref (backend);
- closure->target = g_object_ref (watch->target);
+ closure->target = watch->target; /* we took our ref above */
closure->function = G_STRUCT_MEMBER (void *, watch->vtable,
function_offset);
closure->name = g_strdup (name);
@@ -357,23 +339,18 @@ g_settings_backend_dispatch_signal (GSettingsBackend *backend,
closure->data1_free = data1_free;
closure->data2 = data2;
- source = g_idle_source_new ();
- g_source_set_priority (source, G_PRIORITY_DEFAULT);
- g_source_set_callback (source,
- g_settings_backend_invoke_closure,
- closure, NULL);
+ /* we do this here because 'watch' may not live to the end of this
+ * iteration of the loop (since we may unref the target below).
+ */
+ next = watch->next;
- if (watch->context && watch->context != context)
- g_source_attach (source, watch->context);
+ if (watch->context)
+ g_main_context_invoke (watch->context,
+ g_settings_backend_invoke_closure,
+ closure);
else
- g_source_attach (source, here_and_now);
-
- g_source_unref (source);
+ g_settings_backend_invoke_closure (closure);
}
- g_static_mutex_unlock (&backend->priv->lock);
-
- while (g_main_context_iteration (here_and_now, FALSE));
- g_main_context_unref (here_and_now);
}
/**
diff --git a/gio/gsettingsbackendinternal.h b/gio/gsettingsbackendinternal.h
index 68a61a8f3..a6711cb7f 100644
--- a/gio/gsettingsbackendinternal.h
+++ b/gio/gsettingsbackendinternal.h
@@ -92,8 +92,6 @@ G_GNUC_INTERNAL
GPermission * g_settings_backend_get_permission (GSettingsBackend *backend,
const gchar *path);
G_GNUC_INTERNAL
-GMainContext * g_settings_backend_get_active_context (void);
-G_GNUC_INTERNAL
GSettingsBackend * g_settings_backend_get_default (void);
G_GNUC_INTERNAL
void g_settings_backend_sync_default (void);