From 87a79673b0176cecbc10a6075466ffdede9e4d12 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 11 Sep 2014 15:52:32 +0200 Subject: [PATCH] check: Add a function to check destruction of objects Add a method letting people to ensure that unreffing one object leads to its destruction, and possibly the destruction of more object (think destruction of a GstBin etc...). https://bugzilla.gnome.org/show_bug.cgi?id=736477 --- docs/libs/gstreamer-libs-sections.txt | 2 + libs/gst/check/Makefile.am | 2 + libs/gst/check/gstcheck.c | 84 +++++++++++++++++++++++++++ libs/gst/check/gstcheck.h | 3 + 4 files changed, 91 insertions(+) diff --git a/docs/libs/gstreamer-libs-sections.txt b/docs/libs/gstreamer-libs-sections.txt index a27b372a38..1b52239065 100644 --- a/docs/libs/gstreamer-libs-sections.txt +++ b/docs/libs/gstreamer-libs-sections.txt @@ -985,6 +985,8 @@ gst_check_setup_sink_pad_by_name_from_template gst_check_setup_sink_pad_from_template gst_check_setup_src_pad_by_name_from_template gst_check_setup_src_pad_from_template +gst_check_objects_destroyed_on_unref +gst_check_object_destroyed_on_unref MAIN_INIT diff --git a/libs/gst/check/Makefile.am b/libs/gst/check/Makefile.am index 138927065f..4adf53cd4f 100644 --- a/libs/gst/check/Makefile.am +++ b/libs/gst/check/Makefile.am @@ -93,6 +93,8 @@ LIBGSTCHECK_EXPORTED_FUNCS = \ gst_check_teardown_pad_by_name \ gst_check_teardown_sink_pad \ gst_check_teardown_src_pad \ + gst_check_objects_destroyed_on_unref \ + gst_check_object_destroyed_on_unref \ gst_consistency_checker_add_pad \ gst_consistency_checker_new \ gst_consistency_checker_reset \ diff --git a/libs/gst/check/gstcheck.c b/libs/gst/check/gstcheck.c index 7f1ba9ceac..fcb428ad93 100644 --- a/libs/gst/check/gstcheck.c +++ b/libs/gst/check/gstcheck.c @@ -927,3 +927,87 @@ gst_check_setup_events (GstPad * srcpad, GstElement * element, stream_id); g_free (stream_id); } + +typedef struct _DestroyedObjectStruct +{ + GObject *object; + gboolean destroyed; +} DestroyedObjectStruct; + +static void +weak_notify (DestroyedObjectStruct * destroyed, GObject ** object) +{ + destroyed->destroyed = TRUE; +} + +/** + * gst_check_objects_destroyed_on_unref: + * @object_to_unref: The #GObject to unref + * @first_object: (allow-none) The first object that should be destroyed as a + * concequence of unrefing @object_to_unref. + * @... : Additional object that should have been destroyed. + * + * Unrefs @object_to_unref and checks that is has properly been + * destroyed, also checks that the other objects passed in + * parametter have been destroyed as a concequence of + * unrefing @object_to_unref. Last variable argument should be NULL. + * + * Since: 1.6 + */ +void +gst_check_objects_destroyed_on_unref (gpointer object_to_unref, gpointer first_object, ...) +{ + GObject *object; + GList *objs = NULL, *tmp; + DestroyedObjectStruct *destroyed = g_slice_new0 (DestroyedObjectStruct); + + destroyed->object = object_to_unref; + g_object_weak_ref (object_to_unref, (GWeakNotify) weak_notify, destroyed); + objs = g_list_prepend (objs, destroyed); + + if (first_object) { + va_list varargs; + + object = first_object; + + va_start (varargs, first_object); + while (object) { + destroyed = g_slice_new0 (DestroyedObjectStruct); + destroyed->object = object; + g_object_weak_ref (object, (GWeakNotify) weak_notify, destroyed); + objs = g_list_prepend (objs, destroyed); + object = va_arg (varargs, GObject *); + } + va_end (varargs); + } + gst_object_unref (object_to_unref); + + for (tmp = objs; tmp; tmp = tmp->next) { + DestroyedObjectStruct *destroyed = tmp->data; + + if (destroyed->destroyed == FALSE) { + fail_unless (destroyed->destroyed == TRUE, + "%s_%p is not destroyed, %d refcounts left!", + GST_IS_OBJECT (destroyed->object) ? GST_OBJECT_NAME (destroyed->object) : + G_OBJECT_TYPE_NAME (destroyed), + destroyed->object, destroyed->object->ref_count); + } + g_slice_free (DestroyedObjectStruct, tmp->data); + } + g_list_free (objs); +} + +/** + * gst_check_object_destroyed_on_unref: + * @object_to_unref: The #GObject to unref + * + * Unrefs @object_to_unref and checks that is has properly been + * destroyed. + * + * Since: 1.6 + */ +void +gst_check_object_destroyed_on_unref (gpointer object_to_unref) +{ + gst_check_objects_destroyed_on_unref (object_to_unref, NULL, NULL); +} diff --git a/libs/gst/check/gstcheck.h b/libs/gst/check/gstcheck.h index 84d1d11ddd..e33e006fb8 100644 --- a/libs/gst/check/gstcheck.h +++ b/libs/gst/check/gstcheck.h @@ -107,6 +107,9 @@ void gst_check_setup_events (GstPad * srcpad, GstElement * element, void gst_check_setup_events_with_stream_id (GstPad * srcpad, GstElement * element, GstCaps * caps, GstFormat format, const gchar * stream_id); +void gst_check_objects_destroyed_on_unref (gpointer object_to_unref, gpointer first_object, ...) + G_GNUC_NULL_TERMINATED; +void gst_check_object_destroyed_on_unref (gpointer object_to_unref); #define fail_unless_message_error(msg, domain, code) \ gst_check_message_error (msg, GST_MESSAGE_ERROR, \