summaryrefslogtreecommitdiff
path: root/gio
diff options
context:
space:
mode:
authorPhilip Withnall <withnall@endlessm.com>2020-02-21 12:07:53 +0000
committerPhilip Withnall <withnall@endlessm.com>2020-02-24 09:01:03 +0000
commitaf6dbece870a38dcce89ef55922ecfa085925823 (patch)
tree42974ad5808891c9e86a7b44109d0bf2c57c91e6 /gio
parentac274b400577131d7f52320d14077410b607b76e (diff)
tests: Wait until unwatching the gdbus-testserver name has completed
Previously, the code in `ensure_gdbus_testserver_up()` created a proxy object and watched its `name-owner` to see when the `com.example.TestService` name appeared. This ended up subscribing to three signals (one of them for name ownership, and two unused for properties of the proxy), and was racy. In particular, the `name-owner` property could be set before all D-Bus messages had been processed — it could have been derived from getting the owner of the name, for example. This left unprocessed messages hanging around in the `context`, but that context was never iterated again, which essentially leaked the references held by those messages. That included a reference to the `GDBusConnection`. The first part of the fix is to simplify the code to use `g_bus_watch_name_on_connection()`, so there’s only one signal subscription to worry about. The second part of the fix is to use the `GDestroyNotify` callback for the watch data to be notified of when all D-Bus traffic has been processed and the signal unsubscription is complete. At this point, it’s guaranteed that there are no idle callbacks pending in the `GMainContext`, since the `GDestroyNotify` callback is the last one invoked on the `GMainContext`. Essentially, this commit uses the `GDestroyNotify` callback as a synchronisation message between the D-Bus worker thread and the thread calling `ensure_gdbus_testserver_up()`. Signed-off-by: Philip Withnall <withnall@endlessm.com> Fixes: #1515
Diffstat (limited to 'gio')
-rw-r--r--gio/tests/gdbus-tests.c65
1 files changed, 44 insertions, 21 deletions
diff --git a/gio/tests/gdbus-tests.c b/gio/tests/gdbus-tests.c
index 66f16e02f..bed0d24f7 100644
--- a/gio/tests/gdbus-tests.c
+++ b/gio/tests/gdbus-tests.c
@@ -86,26 +86,52 @@ _give_up (gpointer data)
g_return_val_if_reached (TRUE);
}
+typedef struct
+{
+ GMainContext *context;
+ gboolean name_appeared;
+ gboolean unwatch_complete;
+} WatchData;
+
+static void
+name_appeared_cb (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ WatchData *data = user_data;
+
+ g_assert (name_owner != NULL);
+ data->name_appeared = TRUE;
+ g_main_context_wakeup (data->context);
+}
+
+static void
+watch_free_cb (gpointer user_data)
+{
+ WatchData *data = user_data;
+
+ data->unwatch_complete = TRUE;
+ g_main_context_wakeup (data->context);
+}
+
void
ensure_gdbus_testserver_up (GDBusConnection *connection,
GMainContext *context)
{
- gchar *name_owner;
GSource *timeout_source = NULL;
- GDBusProxy *proxy;
- GError *error = NULL;
+ guint watch_id;
+ WatchData data = { context, FALSE, FALSE };
g_main_context_push_thread_default (context);
- proxy = g_dbus_proxy_new_sync (connection,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL, /* GDBusInterfaceInfo */
- "com.example.TestService", /* name */
- "/com/example/TestObject", /* object path */
- "com.example.Frob", /* interface */
- NULL, /* GCancellable */
- &error);
- g_assert_no_error (error);
+ watch_id = g_bus_watch_name_on_connection (connection,
+ "com.example.TestService",
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ name_appeared_cb,
+ NULL,
+ &data,
+ watch_free_cb);
timeout_source = g_timeout_source_new_seconds (60);
g_source_set_callback (timeout_source, _give_up,
@@ -113,20 +139,17 @@ ensure_gdbus_testserver_up (GDBusConnection *connection,
NULL);
g_source_attach (timeout_source, context);
- while (TRUE)
- {
- name_owner = g_dbus_proxy_get_name_owner (proxy);
+ while (!data.name_appeared)
+ g_main_context_iteration (context, TRUE);
- if (name_owner != NULL)
- break;
+ g_bus_unwatch_name (watch_id);
+ watch_id = 0;
- g_main_context_iteration (context, TRUE);
- }
+ while (!data.unwatch_complete)
+ g_main_context_iteration (context, TRUE);
g_source_destroy (timeout_source);
g_source_unref (timeout_source);
- g_free (name_owner);
- g_object_unref (proxy);
g_main_context_pop_thread_default (context);
}