From 322e25b535a63a631f2f53439a876a4d7d9c1f87 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Mon, 20 Jun 2011 16:32:03 -0400 Subject: [PATCH] GDBus: Unref worker from worker-thread to avoid race ... otherwise we might end up using the worker after it has been freed. Reported by Dan Winship and Colin Walters. This fix uncovered a bug in the /gdbus/nonce-tcp test case so "fix" that as well to use a better way of having one thread wait for another (using quotes for the word "fix" since it's pretty hackish to busy-wait in one thread to wait for another). Signed-off-by: David Zeuthen --- gio/gdbusprivate.c | 21 ++++++++++++++++++++- gio/tests/gdbus-peer.c | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index fcc8cf788..aa2a16e81 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -1401,6 +1401,15 @@ _g_dbus_worker_new (GIOStream *stream, /* ---------------------------------------------------------------------------------------------------- */ +/* called in private thread shared by all GDBusConnection instances (without read-lock held) */ +static gboolean +unref_in_idle_cb (gpointer user_data) +{ + GDBusWorker *worker = user_data; + _g_dbus_worker_unref (worker); + return FALSE; +} + /* This can be called from any thread - frees worker. Note that * callbacks might still happen if called from another thread than the * worker - use your own synchronization primitive in the callbacks. @@ -1408,9 +1417,19 @@ _g_dbus_worker_new (GIOStream *stream, void _g_dbus_worker_stop (GDBusWorker *worker) { + GSource *idle_source; + worker->stopped = TRUE; g_cancellable_cancel (worker->cancellable); - _g_dbus_worker_unref (worker); + + idle_source = g_idle_source_new (); + g_source_set_priority (idle_source, G_PRIORITY_DEFAULT); + g_source_set_callback (idle_source, + unref_in_idle_cb, + _g_dbus_worker_ref (worker), + (GDestroyNotify) _g_dbus_worker_unref); + g_source_attach (idle_source, worker->shared_thread_data->context); + g_source_unref (idle_source); } /* ---------------------------------------------------------------------------------------------------- */ diff --git a/gio/tests/gdbus-peer.c b/gio/tests/gdbus-peer.c index 3fba622c3..c71a52698 100644 --- a/gio/tests/gdbus-peer.c +++ b/gio/tests/gdbus-peer.c @@ -1206,7 +1206,7 @@ test_nonce_tcp (void) g_assert_no_error (error); g_assert (c != NULL); while (data.current_connections->len < 1) - g_main_loop_run (loop); + g_thread_yield (); g_assert_cmpint (data.current_connections->len, ==, 1); g_assert_cmpint (data.num_connection_attempts, ==, 1); g_assert (g_dbus_connection_get_unique_name (c) == NULL); -- 2.34.1