From 1a1fc130ece13a442dcacaba1db9108089cead38 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Mon, 8 Nov 2010 16:42:32 -0500 Subject: New function: g_clear_object() By analogy to g_clear_error, takes a pass-by-reference GObject reference and, if non-%NULL, unrefs it and sets it equal to %NULL. Bug #620263. --- gobject/gobject.c | 38 ++++++++++++++++++++++++++++++++++++++ gobject/gobject.h | 15 +++++++++++++++ gobject/gobject.symbols | 1 + gobject/tests/.gitignore | 1 + gobject/tests/Makefile.am | 3 ++- gobject/tests/reference.c | 35 +++++++++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 gobject/tests/reference.c (limited to 'gobject') diff --git a/gobject/gobject.c b/gobject/gobject.c index 49eff4d6d..e6f19da74 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -2728,6 +2728,44 @@ g_object_unref (gpointer _object) } } +/** + * g_clear_object: + * @object_ptr: a pointer to a #GObject reference + * + * Clears a reference to a #GObject. + * + * @object_ptr must not be %NULL. + * + * If the reference is %NULL then this function does nothing. + * Otherwise, the reference count of the object is decreased 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.28 + **/ +#undef g_clear_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_object_get_qdata: * @object: The GObject to get a stored user data pointer from diff --git a/gobject/gobject.h b/gobject/gobject.h index c969b8f50..971f365a6 100644 --- a/gobject/gobject.h +++ b/gobject/gobject.h @@ -562,6 +562,21 @@ G_STMT_START { \ #define G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec) \ 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 + G_END_DECLS #endif /* __G_OBJECT_H__ */ diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols index c80293f82..9be4f2e82 100644 --- a/gobject/gobject.symbols +++ b/gobject/gobject.symbols @@ -186,6 +186,7 @@ g_value_get_object g_value_set_object g_value_dup_object g_value_take_object +g_clear_object #ifndef G_DISABLE_DEPRECATED g_value_set_object_take_ownership g_object_compat_control diff --git a/gobject/tests/.gitignore b/gobject/tests/.gitignore index ba9d6c837..cd58ce54f 100644 --- a/gobject/tests/.gitignore +++ b/gobject/tests/.gitignore @@ -1,4 +1,5 @@ binding dynamictests properties +reference threadtests diff --git a/gobject/tests/Makefile.am b/gobject/tests/Makefile.am index 8b1394dd9..eec8c5e8c 100644 --- a/gobject/tests/Makefile.am +++ b/gobject/tests/Makefile.am @@ -5,7 +5,7 @@ INCLUDES = -g $(gobject_INCLUDES) $(GLIB_DEBUG_FLAGS) noinst_PROGRAMS = $(TEST_PROGS) libgobject_LDADD = ../libgobject-2.0.la $(top_builddir)/gthread/libgthread-2.0.la $(top_builddir)/glib/libglib-2.0.la -TEST_PROGS += threadtests dynamictests binding properties +TEST_PROGS += threadtests dynamictests binding properties reference threadtests_SOURCES = threadtests.c threadtests_LDADD = $(libgobject_LDADD) dynamictests_SOURCES = dynamictests.c @@ -14,3 +14,4 @@ binding_SOURCES = binding.c binding_LDADD = $(libgobject_LDADD) properties_SOURCES = properties.c properties_LDADD = $(libgobject_LDADD) +reference_LDADD = $(libgobject_LDADD) diff --git a/gobject/tests/reference.c b/gobject/tests/reference.c new file mode 100644 index 000000000..38354a16e --- /dev/null +++ b/gobject/tests/reference.c @@ -0,0 +1,35 @@ +#include + +static void +test_clear (void) +{ + GObject *o = NULL; + GObject *tmp; + + g_clear_object (&o); + g_assert (o == NULL); + + tmp = g_object_new (G_TYPE_OBJECT, NULL); + g_assert_cmpint (tmp->ref_count, ==, 1); + o = g_object_ref (tmp); + g_assert (o != NULL); + + g_assert_cmpint (tmp->ref_count, ==, 2); + g_clear_object (&o); + g_assert_cmpint (tmp->ref_count, ==, 1); + g_assert (o == NULL); + + g_object_unref (tmp); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_type_init (); + + g_test_add_func ("/object/clear", test_clear); + + return g_test_run (); +} -- cgit v1.2.3