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.
This commit is contained in:
Ryan Lortie 2011-12-07 20:39:23 -05:00
parent 7af08e1fc0
commit 14900d37f4
2 changed files with 32 additions and 25 deletions

View File

@ -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);

View File

@ -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]);