Add g_clear_pointer()
authorXavier Claessens <xavier.claessens@collabora.co.uk>
Mon, 23 Apr 2012 15:57:56 +0000 (17:57 +0200)
committerXavier Claessens <xavier.claessens@collabora.co.uk>
Fri, 27 Apr 2012 07:42:29 +0000 (09:42 +0200)
Also reimplement g_clear_object() using g_clear_pointer()

https://bugzilla.gnome.org/show_bug.cgi?id=674634

docs/reference/glib/glib-sections.txt
glib/glib.symbols
glib/gmem.c
glib/gmem.h
gobject/gobject.c
gobject/gobject.h

index ef1b562..141c7bb 100644 (file)
@@ -925,6 +925,7 @@ g_try_realloc_n
 
 <SUBSECTION>
 g_free
+g_clear_pointer
 g_mem_gc_friendly
 
 <SUBSECTION>
index 6c2db0d..fdafb3e 100644 (file)
@@ -682,6 +682,7 @@ g_markup_printf_escaped
 g_markup_vprintf_escaped
 g_markup_collect_attributes
 g_free
+g_clear_pointer
 g_malloc
 g_malloc0
 g_malloc_n
index 1f01cd1..3283f2b 100644 (file)
@@ -254,6 +254,45 @@ g_free (gpointer mem)
 }
 
 /**
+ * g_clear_pointer: (skip)
+ * @pp: a pointer to a variable, struct member etc. holding a pointer
+ * @destroy: a function to which a gpointer can be passed, to destroy *@pp
+ *
+ * Clears a reference to a variable.
+ *
+ * @pp must not be %NULL.
+ *
+ * If the reference is %NULL then this function does nothing.
+ * Otherwise, the variable is destroyed using @destroy and the
+ * pointer is set to %NULL.
+ *
+ * This function is threadsafe and modifies the pointer atomically,
+ * using memory barriers where needed.
+ *
+ * A macro is also included that allows this function to be used without
+ * pointer casts.
+ *
+ * Since: 2.34
+ **/
+#undef g_clear_pointer
+void
+g_clear_pointer (gpointer      *pp,
+                 GDestroyNotify destroy)
+{
+  gpointer _p;
+
+  /* This is a little frustrating.
+   * Would be nice to have an atomic exchange (with no compare).
+   */
+  do
+    _p = g_atomic_pointer_get (pp);
+  while G_UNLIKELY (!g_atomic_pointer_compare_and_exchange (pp, _p, NULL));
+
+  if (_p)
+    destroy (_p);
+}
+
+/**
  * g_try_malloc:
  * @n_bytes: number of bytes to allocate.
  * 
index 376e466..cb250dc 100644 (file)
@@ -69,6 +69,10 @@ typedef struct _GMemVTable GMemVTable;
 
 void    g_free           (gpointer      mem);
 
+GLIB_AVAILABLE_IN_2_34
+void     g_clear_pointer  (gpointer      *pp,
+                           GDestroyNotify destroy);
+
 gpointer g_malloc         (gsize        n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
 gpointer g_malloc0        (gsize        n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
 gpointer g_realloc        (gpointer     mem,
@@ -93,6 +97,20 @@ gpointer g_try_realloc_n  (gpointer   mem,
                           gsize         n_blocks,
                           gsize         n_block_bytes) G_GNUC_WARN_UNUSED_RESULT;
 
+#define g_clear_pointer(pp, destroy) \
+  G_STMT_START {                                                               \
+    G_STATIC_ASSERT (sizeof (*(pp)) == sizeof (gpointer));                     \
+    /* Only one access, please */                                              \
+    gpointer *_pp = (gpointer *) pp;                                           \
+    gpointer _p;                                                               \
+                                                                               \
+    do                                                                         \
+      _p = g_atomic_pointer_get (_pp);                                         \
+    while G_UNLIKELY (!g_atomic_pointer_compare_and_exchange (_pp, _p, NULL)); \
+                                                                               \
+    if (_p)                                                                    \
+      ((GDestroyNotify) (destroy)) (_p);                                       \
+  } G_STMT_END
 
 /* Optimise: avoid the call to the (slower) _n function if we can
  * determine at compile-time that no overflow happens.
index 69f14a8..a18cb75 100644 (file)
@@ -3057,18 +3057,7 @@ g_object_unref (gpointer _object)
 void
 g_clear_object (volatile GObject **object_ptr)
 {
-  gpointer *ptr = (gpointer) object_ptr;
-  gpointer old;
-
-  /* This is a little frustrating.
-   * Would be nice to have an atomic exchange (with no compare).
-   */
-  do
-    old = g_atomic_pointer_get (ptr);
-  while G_UNLIKELY (!g_atomic_pointer_compare_and_exchange (ptr, old, NULL));
-
-  if (old)
-    g_object_unref (old);
+  g_clear_pointer (object_ptr, g_object_unref);
 }
 
 /**
index 3572736..d04ce2e 100644 (file)
@@ -561,19 +561,7 @@ G_STMT_START { \
     G_OBJECT_WARN_INVALID_PSPEC ((object), "property", (property_id), (pspec))
 
 void    g_clear_object (volatile GObject **object_ptr);
-#define g_clear_object(object_ptr) \
-  G_STMT_START {                                                             \
-    /* Only one access, please */                                            \
-    gpointer *_p = (gpointer) (object_ptr);                                  \
-    gpointer _o;                                                             \
-                                                                             \
-    do                                                                       \
-      _o = g_atomic_pointer_get (_p);                                        \
-    while G_UNLIKELY (!g_atomic_pointer_compare_and_exchange (_p, _o, NULL));\
-                                                                             \
-    if (_o)                                                                  \
-      g_object_unref (_o);                                                   \
-  } G_STMT_END
+#define g_clear_object(object_ptr) g_clear_pointer ((object_ptr), g_object_unref)
 
 typedef struct {
     /*<private>*/