[glib] GDBus: Unref worker from worker-thread to avoid race



commit 322e25b535a63a631f2f53439a876a4d7d9c1f87
Author: David Zeuthen <davidz redhat com>
Date:   Mon Jun 20 16:32:03 2011 -0400

    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 <davidz redhat com>

 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 fcc8cf7..aa2a16e 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 3fba622..c71a526 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);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]