From 14900d37f46ecab99deb4fd97822f1f2ec105c40 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Wed, 7 Dec 2011 20:39:23 -0500 Subject: [PATCH] action exporter: clarify threading situation Exporting can only be done relative to a particular given main context and all interaction with the action group must be on that same context. Fix up the implementation so that the user can specify that context with the normal (thread default) mechanism and document the limitation on the API. Adjust the testcase to adhere to the documentation limitations. It passes now. --- gio/gactiongroupexporter.c | 16 +++++++++++++-- gio/tests/actions.c | 41 +++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/gio/gactiongroupexporter.c b/gio/gactiongroupexporter.c index 136928cb7..ef8f18a65 100644 --- a/gio/gactiongroupexporter.c +++ b/gio/gactiongroupexporter.c @@ -216,6 +216,7 @@ typedef struct { GActionGroup *action_group; GDBusConnection *connection; + GMainContext *context; gchar *object_path; GHashTable *pending_changes; GSource *pending_source; @@ -329,7 +330,7 @@ g_action_group_exporter_set_events (GActionGroupExporter *exporter, source = g_idle_source_new (); exporter->pending_source = source; g_source_set_callback (source, g_action_group_exporter_dispatch_events, exporter, NULL); - g_source_attach (source, NULL); + g_source_attach (source, exporter->context); g_source_unref (source); } @@ -566,6 +567,7 @@ g_action_group_exporter_free (gpointer user_data) if (exporter->pending_source) g_source_destroy (exporter->pending_source); + g_main_context_unref (exporter->context); g_object_unref (exporter->connection); g_object_unref (exporter->action_group); g_free (exporter->object_path); @@ -585,7 +587,7 @@ g_action_group_exporter_free (gpointer user_data) * The implemented D-Bus API should be considered private. It is * subject to change in the future. * - * A given * object path can only have one action group exported on it. + * A given object path can only have one action group exported on it. * If this constraint is violated, the export will fail and 0 will be * returned (with @error set accordingly). * @@ -593,6 +595,15 @@ g_action_group_exporter_free (gpointer user_data) * g_dbus_connection_unexport_action_group() with the return value of * this function. * + * The thread default main context is taken at the time of this call. + * All incoming action activations and state change requests are + * reported from this context. Any changes on the action group that + * cause it to emit signals must also come from this same context. + * Since incoming action activations and state change requests are + * rather likely to cause changes on the action group, this effectively + * limits a given action group to being exported from only one main + * context. + * * Returns: the ID of the export (never zero), or 0 in case of failure * * Since: 2.32 @@ -633,6 +644,7 @@ g_dbus_connection_export_action_group (GDBusConnection *connection, return 0; } + exporter->context = g_main_context_ref_thread_default (); exporter->pending_changes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); exporter->pending_source = NULL; exporter->action_group = g_object_ref (action_group); diff --git a/gio/tests/actions.c b/gio/tests/actions.c index c9244382f..63ffe4855 100644 --- a/gio/tests/actions.c +++ b/gio/tests/actions.c @@ -624,33 +624,22 @@ test_dbus_export (void) g_object_unref (bus); } -static gpointer -do_activate (gpointer data) -{ - GSimpleActionGroup *group = data; - gint i; - GAction *action; - - for (i = 0; i < 1000000; i++) - { - action = g_simple_action_group_lookup (group, "a"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - !g_action_get_enabled (action)); - } - - return NULL; -} - static gpointer do_export (gpointer data) { GActionGroup *group = data; + GMainContext *ctx; gint i; GError *error = NULL; guint id; GDBusConnection *bus; + GAction *action; gchar *path; + ctx = g_main_context_new (); + + g_main_context_push_thread_default (ctx); + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); path = g_strdup_printf("/%p", data); @@ -658,12 +647,23 @@ do_export (gpointer data) { id = g_dbus_connection_export_action_group (bus, path, G_ACTION_GROUP (group), &error); g_assert_no_error (error); + + action = g_simple_action_group_lookup (G_SIMPLE_ACTION_GROUP (group), "a"); + g_simple_action_set_enabled (G_SIMPLE_ACTION (action), + !g_action_get_enabled (action)); + g_dbus_connection_unexport_action_group (bus, id); + + while (g_main_context_iteration (ctx, FALSE)); } g_free (path); g_object_unref (bus); + g_main_context_pop_thread_default (ctx); + + g_main_context_unref (ctx); + return NULL; } @@ -671,7 +671,6 @@ static void test_dbus_threaded (void) { GSimpleActionGroup *group[10]; - GThread *call[10]; GThread *export[10]; static GActionEntry entries[] = { { "a", activate_action, NULL, NULL, NULL }, @@ -683,15 +682,11 @@ test_dbus_threaded (void) { group[i] = g_simple_action_group_new (); g_simple_action_group_add_entries (group[i], entries, G_N_ELEMENTS (entries), NULL); - call[i] = g_thread_new ("call", do_activate, group[i]); export[i] = g_thread_new ("export", do_export, group[i]); } for (i = 0; i < 10; i++) - { - g_thread_join (call[i]); - g_thread_join (export[i]); - } + g_thread_join (export[i]); for (i = 0; i < 10; i++) g_object_unref (group[i]);