thread: simplify 'free' process
authorRyan Lortie <desrt@desrt.ca>
Thu, 13 Oct 2011 04:18:17 +0000 (00:18 -0400)
committerRyan Lortie <desrt@desrt.ca>
Thu, 13 Oct 2011 04:18:17 +0000 (00:18 -0400)
GThread is freed using some very slightly confusing logic: if the thread
was created 'joinable', then the structure is freed after the join()
call succeeds (since we know the thread has exited).  If the thread was
not created 'joinable' then the free is when the thread quits (since we
know 'join' will not be called later).

Move to a straight ref-counting system: 1 ref owned by the thread and 1
extra ref if the thread is joinable.  Both thread quit and joining will
decrease the refcount by 1.

glib/gthread.c
glib/gthreadprivate.h

index 210d1254a4e0ed866b6ca5524ad0380c2ff7a455..29b102d9502b1c0172efa475998ef242495abbb4 100644 (file)
@@ -667,25 +667,25 @@ void
 /* GThread {{{1 -------------------------------------------------------- */
 
 static void
-g_thread_cleanup (gpointer data)
+g_thread_unref (GThread *thread)
 {
-  if (data)
-    {
-      GRealThread* thread = data;
+  GRealThread *real = (GRealThread *) thread;
 
-      /* We only free the thread structure if it isn't joinable.
-       * If it is, the structure is freed in g_thread_join()
-       */
-      if (!thread->thread.joinable)
-        {
-          if (thread->ours)
-            g_system_thread_free (thread);
-          else
-            g_slice_free (GRealThread, thread);
-        }
+  if (g_atomic_int_dec_and_test (&real->ref_count))
+    {
+      if (real->ours)
+        g_system_thread_free (real);
+      else
+        g_slice_free (GRealThread, real);
     }
 }
 
+static void
+g_thread_cleanup (gpointer data)
+{
+  g_thread_unref (data);
+}
+
 gpointer
 g_thread_proxy (gpointer data)
 {
@@ -812,6 +812,7 @@ g_thread_new_internal (const gchar   *name,
   thread = g_system_thread_new (proxy, stack_size, error);
   if (thread)
     {
+      thread->ref_count = joinable ? 2 : 1;
       thread->ours = TRUE;
       thread->thread.joinable = joinable;
       thread->thread.func = func;
@@ -888,14 +889,7 @@ g_thread_join (GThread *thread)
   /* Just to make sure, this isn't used any more */
   thread->joinable = 0;
 
-  /* the thread structure for non-joinable threads is freed upon
-   * thread end. We free the memory here. This will leave a loose end,
-   * if a joinable thread is not joined.
-   */
-  if (real->ours)
-    g_system_thread_free (real);
-  else
-    g_slice_free (GRealThread, real);
+  g_thread_unref (thread);
 
   return retval;
 }
@@ -920,6 +914,8 @@ g_thread_self (void)
        * that are not created by GLib.
        */
       thread = g_slice_new0 (GRealThread);
+      thread->ref_count = 1;
+
       g_private_set (&g_thread_specific_private, thread);
     }
 
index bd634bd964186d047fc16c454eccd98682b6ece1..27c40f21f93d46468a4629be5fe0399c85c6a24b 100644 (file)
@@ -59,6 +59,7 @@ struct  _GRealThread
 {
   GThread thread;
 
+  gint ref_count;
   gboolean ours;
   const gchar *name;
   gpointer retval;