summaryrefslogtreecommitdiff
path: root/gobject
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2010-11-08 16:42:32 -0500
committerRyan Lortie <desrt@desrt.ca>2010-11-08 18:21:51 -0500
commit1a1fc130ece13a442dcacaba1db9108089cead38 (patch)
treeaa341a06c6ad3fa58852be2b7d7435c01b96481c /gobject
parent78bc8bec4f44a48e5e538f1f9ac9b9e43a9fc833 (diff)
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.
Diffstat (limited to 'gobject')
-rw-r--r--gobject/gobject.c38
-rw-r--r--gobject/gobject.h15
-rw-r--r--gobject/gobject.symbols1
-rw-r--r--gobject/tests/.gitignore1
-rw-r--r--gobject/tests/Makefile.am3
-rw-r--r--gobject/tests/reference.c35
6 files changed, 92 insertions, 1 deletions
diff --git a/gobject/gobject.c b/gobject/gobject.c
index 49eff4d6d..e6f19da74 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -2729,6 +2729,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
* @quark: A #GQuark, naming the user data pointer
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 <glib-object.h>
+
+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 ();
+}