Commit 00285b75 authored by Xavier Claessens's avatar Xavier Claessens

Add g_clear_pointer()

Also reimplement g_clear_object() using g_clear_pointer()

https://bugzilla.gnome.org/show_bug.cgi?id=674634
parent 3f816dc5
......@@ -925,6 +925,7 @@ g_try_realloc_n
<SUBSECTION>
g_free
g_clear_pointer
g_mem_gc_friendly
<SUBSECTION>
......
......@@ -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
......
......@@ -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.
......
......@@ -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.
......
......@@ -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);
}
/**
......
......@@ -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>*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment