[glib/wip/gcleanup: 22/79] GThread posix: add impl structs to cleanup list



commit 330616424da71506a5b399fa19fb879ebded3ac2
Author: Ryan Lortie <desrt desrt ca>
Date:   Sun Mar 24 22:19:14 2013 -0400

    GThread posix: add impl structs to cleanup list
    
    There are two ways of using the structs like GMutex, GCond, etc.
    
    The first is to explicitly _init() and _clear() them.  This is when you
    use them as part of another structure.  This case is not interesting for
    gcleanup.
    
    The other is to have them in static storage (zero-filled) and just use
    them for the first time.  This is the difficult case, because we don't
    ever free the impl in that case.
    
    In the first case, the impl is created and set in the _init() function.
    We can therfore tell that we are in the second case if we get to the
    get_impl() function and the impl is not there yet.  In that case, add it
    to the cleanup list.
    
    There are probably people that allocate a GMutex as part of a
    zero-filled structure and use it, then call g_mutex_clear() on it.  This
    is technically a violation of the API and these users will crash with
    G_DEBUG=cleanup, but that's a good thing because it will cause them to
    fix their code.
    
    All threading primitives are cleaned up on the graveyard shift, so that
    they can be used by other cleanup functions is libglib.
    
    Because GPrivate has a callback, and we need to run that callback for
    the main thread, we schedule two cleanups for it. The cleanup needs
    to run in the cleanup scope where the GPrivate callback is defined,
    so adapt G_PRIVATE_INIT to do this.
    
    Tweaked by: Stef Walter <stefw redhat com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=711744

 glib/deprecated/gthread-deprecated.c |   13 +++++++++++
 glib/gthread-posix.c                 |   39 +++++++++++++++++++++++++++++----
 glib/gthread.h                       |   11 +++++++-
 3 files changed, 56 insertions(+), 7 deletions(-)
---
diff --git a/glib/deprecated/gthread-deprecated.c b/glib/deprecated/gthread-deprecated.c
index 89dba4d..e592e24 100644
--- a/glib/deprecated/gthread-deprecated.c
+++ b/glib/deprecated/gthread-deprecated.c
@@ -1429,6 +1429,13 @@ g_static_private_set (GStaticPrivate *private_key,
   node->owner = private_key;
 }
 
+static void
+cleanup_free_indices (void)
+{
+  g_slist_free (g_thread_free_indices);
+  g_thread_free_indices = NULL;
+}
+
 /**
  * g_static_private_free:
  * @private_key: a #GStaticPrivate to be freed
@@ -1443,6 +1450,7 @@ g_static_private_set (GStaticPrivate *private_key,
 void
 g_static_private_free (GStaticPrivate *private_key)
 {
+  static gboolean cleanup_pushed = FALSE;
   guint idx = private_key->index;
 
   if (!idx)
@@ -1455,6 +1463,11 @@ g_static_private_free (GStaticPrivate *private_key)
    * the same index.
    */
   G_LOCK (g_thread);
+  if (!cleanup_pushed)
+    {
+      G_CLEANUP_FUNC_IN_PHASE (cleanup_free_indices, G_CLEANUP_PHASE_GRAVEYARD);
+      cleanup_pushed = TRUE;
+    }
   g_thread_free_indices = g_slist_prepend (g_thread_free_indices,
                                            GUINT_TO_POINTER (idx));
   G_UNLOCK (g_thread);
diff --git a/glib/gthread-posix.c b/glib/gthread-posix.c
index d9ae636..7dd14ff 100644
--- a/glib/gthread-posix.c
+++ b/glib/gthread-posix.c
@@ -47,6 +47,7 @@
 #include "gslice.h"
 #include "gmessages.h"
 #include "gstrfuncs.h"
+#include "gcleanup.h"
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -126,7 +127,9 @@ g_mutex_get_impl (GMutex *mutex)
   if G_UNLIKELY (impl == NULL)
     {
       impl = g_mutex_impl_new ();
-      if (!g_atomic_pointer_compare_and_exchange (&mutex->p, NULL, impl))
+      if (g_atomic_pointer_compare_and_exchange (&mutex->p, NULL, impl))
+        G_CLEANUP_IN_PHASE (impl, g_mutex_impl_free, G_CLEANUP_PHASE_GRAVEYARD);
+      else
         g_mutex_impl_free (impl);
       impl = mutex->p;
     }
@@ -298,7 +301,9 @@ g_rec_mutex_get_impl (GRecMutex *rec_mutex)
   if G_UNLIKELY (impl == NULL)
     {
       impl = g_rec_mutex_impl_new ();
-      if (!g_atomic_pointer_compare_and_exchange (&rec_mutex->p, NULL, impl))
+      if (g_atomic_pointer_compare_and_exchange (&rec_mutex->p, NULL, impl))
+        G_CLEANUP_IN_PHASE (impl, g_rec_mutex_impl_free, G_CLEANUP_PHASE_GRAVEYARD);
+      else
         g_rec_mutex_impl_free (impl);
       impl = rec_mutex->p;
     }
@@ -458,7 +463,9 @@ g_rw_lock_get_impl (GRWLock *lock)
   if G_UNLIKELY (impl == NULL)
     {
       impl = g_rw_lock_impl_new ();
-      if (!g_atomic_pointer_compare_and_exchange (&lock->p, NULL, impl))
+      if (g_atomic_pointer_compare_and_exchange (&lock->p, NULL, impl))
+        G_CLEANUP_IN_PHASE (impl, g_rw_lock_impl_free, G_CLEANUP_PHASE_GRAVEYARD);
+      else
         g_rw_lock_impl_free (impl);
       impl = lock->p;
     }
@@ -675,7 +682,9 @@ g_cond_get_impl (GCond *cond)
   if G_UNLIKELY (impl == NULL)
     {
       impl = g_cond_impl_new ();
-      if (!g_atomic_pointer_compare_and_exchange (&cond->p, NULL, impl))
+      if (g_atomic_pointer_compare_and_exchange (&cond->p, NULL, impl))
+        G_CLEANUP_IN_PHASE (impl, g_cond_impl_free, G_CLEANUP_PHASE_GRAVEYARD);
+      else
         g_cond_impl_free (impl);
       impl = cond->p;
     }
@@ -985,6 +994,21 @@ g_private_impl_free (pthread_key_t *key)
   free (key);
 }
 
+static void
+g_private_cleanup (GPrivate *key)
+{
+  pthread_key_t *impl = g_atomic_pointer_get (&key->p);
+  gpointer old;
+  gint status;
+
+  old = pthread_getspecific (*impl);
+  if (old && key->notify)
+    key->notify (old);
+
+  if G_UNLIKELY ((status = pthread_setspecific (*impl, NULL)) != 0)
+    g_thread_abort (status, "pthread_setspecific");
+}
+
 static pthread_key_t *
 g_private_get_impl (GPrivate *key)
 {
@@ -993,7 +1017,12 @@ g_private_get_impl (GPrivate *key)
   if G_UNLIKELY (impl == NULL)
     {
       impl = g_private_impl_new (key->notify);
-      if (!g_atomic_pointer_compare_and_exchange (&key->p, NULL, impl))
+      if (g_atomic_pointer_compare_and_exchange (&key->p, NULL, impl))
+        {
+          G_CLEANUP_IN_PHASE (key, g_private_cleanup, G_CLEANUP_PHASE_LATE);
+          G_CLEANUP_IN_PHASE (impl, g_private_impl_free, G_CLEANUP_PHASE_GRAVEYARD);
+        }
+      else
         {
           g_private_impl_free (impl);
           impl = key->p;
diff --git a/glib/gthread.h b/glib/gthread.h
index 43c7891..5e8430a 100644
--- a/glib/gthread.h
+++ b/glib/gthread.h
@@ -32,6 +32,7 @@
 #endif
 
 #include <glib/gatomic.h>
+#include <glib/gcleanup.h>
 #include <glib/gerror.h>
 
 G_BEGIN_DECLS
@@ -84,13 +85,19 @@ struct _GRecMutex
   guint i[2];
 };
 
-#define G_PRIVATE_INIT(notify) { NULL, (notify), { NULL, NULL } }
+#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_40
+#define G_PRIVATE_INIT(notify) { NULL, (notify), G_CLEANUP_SCOPE, { NULL } }
+#else
+#define G_PRIVATE_INIT(notify) { NULL, (notify), NULL, { NULL } }
+#endif
+
 struct _GPrivate
 {
   /*< private >*/
   gpointer       p;
   GDestroyNotify notify;
-  gpointer future[2];
+  gpointer       cleanup;
+  gpointer future[1];
 };
 
 typedef enum


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