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
This commit is contained in:
Thibault Saunier 2014-09-11 15:52:32 +02:00
parent d3de22d802
commit 87a79673b0
4 changed files with 91 additions and 0 deletions

View file

@ -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
<SUBSECTION Private>
MAIN_INIT

View file

@ -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 \

View file

@ -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);
}

View file

@ -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, \