From 00285b7517a63a243a5b61b738de5eea957ae767 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 23 Apr 2012 17:57:56 +0200 Subject: [PATCH] Add g_clear_pointer() Also reimplement g_clear_object() using g_clear_pointer() https://bugzilla.gnome.org/show_bug.cgi?id=674634 --- docs/reference/glib/glib-sections.txt | 1 + glib/glib.symbols | 1 + glib/gmem.c | 39 +++++++++++++++++++++++++++ glib/gmem.h | 18 +++++++++++++ gobject/gobject.c | 13 +-------- gobject/gobject.h | 14 +--------- 6 files changed, 61 insertions(+), 25 deletions(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index ef1b5625e..141c7bb72 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -925,6 +925,7 @@ g_try_realloc_n g_free +g_clear_pointer g_mem_gc_friendly diff --git a/glib/glib.symbols b/glib/glib.symbols index 6c2db0da6..fdafb3e75 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -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 diff --git a/glib/gmem.c b/glib/gmem.c index 1f01cd1e3..3283f2be5 100644 --- a/glib/gmem.c +++ b/glib/gmem.c @@ -253,6 +253,45 @@ g_free (gpointer mem) TRACE(GLIB_MEM_FREE((void*) 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. diff --git a/glib/gmem.h b/glib/gmem.h index 376e466e9..cb250dc76 100644 --- a/glib/gmem.h +++ b/glib/gmem.h @@ -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. diff --git a/gobject/gobject.c b/gobject/gobject.c index 69f14a82e..a18cb75fd 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -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); } /** diff --git a/gobject/gobject.h b/gobject/gobject.h index 35727365d..d04ce2ebf 100644 --- a/gobject/gobject.h +++ b/gobject/gobject.h @@ -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 { /**/