[glib/wip/gcleanup] gdbusprivate: Shutdown shared worker thread correctly



commit dd7da0eb1234f5e0f843613d003764bbec93576f
Author: Stef Walter <stefw gnome org>
Date:   Sat Nov 9 20:16:26 2013 +0100

    gdbusprivate: Shutdown shared worker thread correctly
    
    Both when idle and during cleanup.

 gio/gdbusprivate.c |   65 ++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 53 insertions(+), 12 deletions(-)
---
diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c
index 785a0c0..75886a4 100644
--- a/gio/gdbusprivate.c
+++ b/gio/gdbusprivate.c
@@ -43,6 +43,7 @@
 #include "gsocketcontrolmessage.h"
 #include "gsocketconnection.h"
 #include "gsocketoutputstream.h"
+#include "gthread.h"
 
 #ifdef G_OS_UNIX
 #include "gunixfdmessage.h"
@@ -276,6 +277,10 @@ gdbus_shared_thread_func (gpointer user_data)
 
   g_main_context_push_thread_default (data->context);
   g_main_loop_run (data->loop);
+
+  /* Process any remaining stragglers */
+  while (g_main_context_iteration (data->context, FALSE));
+
   g_main_context_pop_thread_default (data->context);
 
   release_required_types ();
@@ -285,13 +290,40 @@ gdbus_shared_thread_func (gpointer user_data)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+G_LOCK_DEFINE_STATIC (shared_thread_data);
+static gpointer shared_thread_data = NULL;
+
+static void
+_g_dbus_shared_thread_wait_and_free (SharedThreadData *data)
+{
+  g_main_loop_quit (data->loop);
+  g_thread_join (data->thread);
+  g_main_loop_unref (data->loop);
+  g_main_context_unref (data->context);
+
+  g_free (data);
+}
+
+static void
+_g_dbus_shared_thread_cleanup (void)
+{
+  SharedThreadData *data;
+
+  G_LOCK (shared_thread_data);
+  data = shared_thread_data;
+  shared_thread_data = NULL;
+  G_UNLOCK (shared_thread_data);
+
+  _g_dbus_shared_thread_wait_and_free (data);
+}
+
 static SharedThreadData *
 _g_dbus_shared_thread_ref (void)
 {
-  static gsize shared_thread_data = 0;
   SharedThreadData *ret;
 
-  if (g_once_init_enter (&shared_thread_data))
+  G_LOCK (shared_thread_data);
+  if (!shared_thread_data)
     {
       SharedThreadData *data;
 
@@ -299,16 +331,26 @@ _g_dbus_shared_thread_ref (void)
       ensure_required_types ();
 
       data = g_new0 (SharedThreadData, 1);
-      data->refcount = 0;
+      data->refcount = 1;
       
       data->context = g_main_context_new ();
       data->loop = g_main_loop_new (data->context, FALSE);
       data->thread = g_thread_new ("gdbus",
                                    gdbus_shared_thread_func,
                                    data);
-      /* We can cast between gsize and gpointer safely */
-      g_once_init_leave (&shared_thread_data, (gsize) data);
+
+      /*
+       * _g_dbus_shared_thread_wait_and_free() is called by both/either _unref
+       * and _cleanup. In some cases the latter is necessary to break a temporary
+       * ref cycle during shutdown.
+       */
+      g_cleanup_list_push (G_CLEANUP_LOCAL, (GCleanupFunc)_g_dbus_shared_thread_cleanup,
+                           NULL, G_CLEANUP_PHASE_EARLY, "_g_dbus_shared_thread_cleanup");
+
+      ret = shared_thread_data = data;
     }
+  ret = shared_thread_data;
+  G_UNLOCK (shared_thread_data);
 
   ret = (SharedThreadData*) shared_thread_data;
   g_atomic_int_inc (&ret->refcount);
@@ -318,17 +360,16 @@ _g_dbus_shared_thread_ref (void)
 static void
 _g_dbus_shared_thread_unref (SharedThreadData *data)
 {
-  /* TODO: actually destroy the shared thread here */
-#if 0
   g_assert (data != NULL);
   if (g_atomic_int_dec_and_test (&data->refcount))
     {
-      g_main_loop_quit (data->loop);
-      //g_thread_join (data->thread);
-      g_main_loop_unref (data->loop);
-      g_main_context_unref (data->context);
+      G_LOCK (shared_thread_data);
+      g_assert (shared_thread_data == data);
+      shared_thread_data = NULL;
+      G_UNLOCK (shared_thread_data);
+
+      _g_dbus_shared_thread_wait_and_free (data);
     }
-#endif
 }
 
 /* ---------------------------------------------------------------------------------------------------- */


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