From: Thomas Vander Stichele Date: Mon, 11 Jul 2005 15:10:40 +0000 (+0000) Subject: valgrind unit tests as check-local; add gst_deinit X-Git-Tag: RELEASE-0_9_2~256 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a59215bb4e7c27a92ba56c2d171387486a26a5d7;p=platform%2Fupstream%2Fgstreamer.git valgrind unit tests as check-local; add gst_deinit Original commit message from CVS: valgrind unit tests as check-local; add gst_deinit --- diff --git a/ChangeLog b/ChangeLog index 545df6d..20efd9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,32 @@ 2005-07-11 Thomas Vander Stichele + * configure.ac: + check for valgrind binary + some fixes + * check/gst.supp: + valgrind suppressions for the tests + * check/Makefile.am: + add a valgrind: target that valgrinds the unit tests + * check/gst/gst.c: (GST_START_TEST), (gst_suite): + * check/gst/gstbin.c: (pop_messages), (GST_START_TEST): + * check/gst/gstbuffer.c: (GST_START_TEST), (gst_test_suite): + * check/gst/gstghostpad.c: + added some cleanup + * check/gst/gstdata.c: + removed + * check/gst/gstminiobject.c: (GST_START_TEST), (thread_ref), + (thread_unref), (gst_mini_object_suite), (main): + added + * gst/gst.c: (gst_deinit): + * gst/gst.h: + add a method to clean up. + * gst/gstsystemclock.c: (gst_system_clock_dispose), + (gst_system_clock_obtain): + allow for disposing the system clock. + * tools/gst-launch.c: (main): + deinit + +2005-07-11 Thomas Vander Stichele + * docs/gst/tmpl/gstbasesrc.sgml: * docs/gst/tmpl/gstfakesrc.sgml: * gst/base/gstbasesrc.c: (gst_base_src_class_init), diff --git a/check/Makefile.am b/check/Makefile.am index 9b8f907..919561c 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -15,6 +15,8 @@ install-pluginLTLIBRARIES: # ths core dumps of some machines have PIDs appended CLEANFILES = core.* test-registry.xml +EXTRA_DIST = gst.supp + clean-local: for i in `find . -name ".libs" -type d`; do \ rm -rf $$i; \ @@ -32,6 +34,7 @@ TESTS = $(top_builddir)/tools/gst-register \ gst/gstghostpad \ gst/gstiterator \ gst/gstmessage \ + gst/gstminiobject \ gst/gstobject \ gst/gstpad \ gst/gstsystemclock \ @@ -60,3 +63,59 @@ gst_libs_gdp_SOURCES = \ $(top_srcdir)/libs/gst/dataprotocol/dataprotocol.c # remove GST_ENABLE_NEW when dataprotocol has been declared API-stable gst_libs_gdp_CFLAGS = $(AM_CFLAGS) -DGST_ENABLE_NEW + +# valgrind testing + +# these just need fixing, period +TESTS_TO_FIX = \ + gst/gstghostpad \ + gst/gstiterator \ + gst/gstmessage \ + gst/gstpad \ + gst/gstsystemclock \ + gst/gststructure \ + gst/gsttag \ + gst/gstvalue \ + elements/gstfakesrc \ + pipelines/cleanup \ + pipelines/simple_launch_lines \ + gst-libs/gdp + +# these need fixing because the threads cause segfaults under valgrind +TESTS_THREADED = \ + gst/gstminiobject \ + gst/gstobject + +VALGRIND_TESTS_DISABLE = \ + $(top_builddir)/tools/gst-register \ + $(TESTS_THREADED) \ + $(TESTS_TO_FIX) + +if HAVE_VALGRIND +check-local: + make valgrind +else +check-local: + true +endif + +valgrind: + @echo "Valgrinding tests ..." + $(TESTS_ENVIRONMENT) $(top_builddir)/tools/gst-register + @failed=0; \ + for t in $(filter-out $(VALGRIND_TESTS_DISABLE),$(TESTS)); do \ + $(TESTS_ENVIRONMENT) \ + CK_FORK=no \ + libtool --mode=execute \ + $(VALGRIND_PATH) -q --suppressions=$(srcdir)/gst.supp \ + --leak-check=yes $$t; \ + if test "$$?" -ne 0; then \ + echo "Valgrind error for test $$t"; \ + failed=`expr $$failed + 1`; \ + fi; \ + done; \ + if test "$$failed" -ne 0; then \ + echo "$$failed tests had leaks under valgrind"; \ + false; \ + fi + diff --git a/check/gst.supp b/check/gst.supp new file mode 100644 index 0000000..6dec7da --- /dev/null +++ b/check/gst.supp @@ -0,0 +1,68 @@ +### this file contains suppressions for valgrind when running +### the gstreamer unit tests +### it might be useful for wider use as well + + +### glibc suppressions + +# glibc does not deallocate thread-local storage + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 +} + +{ + + Memcheck:Cond + fun:strstr + fun:__pthread_initialize_minimal + obj:/lib/libpthread-*.so + obj:/lib/libpthread-*.so + fun:call_init + fun:_dl_init + obj:/lib/ld-*.so +} + +### glib suppressions + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + obj:/usr/lib/libgobject-2.0.so.* + obj:/usr/lib/libgobject-2.0.so.* + fun:g_type_init_with_debug_flags + fun:g_type_init + fun:init_pre + fun:init_popt_callback + obj:/usr/lib/libpopt.so.* + obj:/usr/lib/libpopt.so.* + fun:poptGetContext + fun:gst_init_check_with_popt_table +} + +### GStreamer suppressions + +# ds is saying he's rewriting the registry anyway +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:read_string + fun:load_plugin + fun:gst_xml_registry_load + fun:gst_registry_load + fun:_registry_load_func + fun:g_list_foreach + fun:gst_registry_pool_load_all + fun:init_post + fun:init_popt_callback +} + diff --git a/check/gst/gst.c b/check/gst/gst.c index dbcefec..11ae64a 100644 --- a/check/gst/gst.c +++ b/check/gst/gst.c @@ -31,6 +31,30 @@ GST_START_TEST (test_init) GST_END_TEST; +GST_START_TEST (test_deinit) +{ + gst_init (NULL, NULL); + + gst_deinit (); +} + +GST_END_TEST; + +GST_START_TEST (test_deinit_sysclock) +{ + GstClock *clock; + + gst_init (NULL, NULL); + + clock = gst_system_clock_obtain (); + gst_object_unref (clock); + + gst_deinit (); +} + +GST_END_TEST; + + Suite * gst_suite (void) { @@ -39,6 +63,8 @@ gst_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_init); + tcase_add_test (tc_chain, test_deinit); + tcase_add_test (tc_chain, test_deinit_sysclock); return s; } diff --git a/check/gst/gstbuffer.c b/check/gst/gstbuffer.c index 8d32f54..44cb812 100644 --- a/check/gst/gstbuffer.c +++ b/check/gst/gstbuffer.c @@ -28,6 +28,7 @@ GST_START_TEST (test_subbuffer) int rc; buffer = gst_buffer_new_and_alloc (4); + memset (GST_BUFFER_DATA (buffer), 0, 4); sub = gst_buffer_create_sub (buffer, 1, 2); @@ -38,6 +39,9 @@ GST_START_TEST (test_subbuffer) rc = GST_MINI_OBJECT_REFCOUNT_VALUE (buffer); fail_unless (rc == 2, "parent refcount is %d instead of 3", rc); + + /* clean up */ + gst_buffer_unref (sub); gst_buffer_unref (buffer); } @@ -62,6 +66,11 @@ GST_START_TEST (test_is_span_fast) fail_if (gst_buffer_is_span_fast (sub1, sub2) == FALSE, "two subbuffers next to each other should be span_fast"); + + /* clean up */ + gst_buffer_unref (sub1); + gst_buffer_unref (sub2); + gst_buffer_unref (buffer); } GST_END_TEST Suite * gst_test_suite (void) diff --git a/check/gst/gstghostpad.c b/check/gst/gstghostpad.c index dd0f47a..174cf3a 100644 --- a/check/gst/gstghostpad.c +++ b/check/gst/gstghostpad.c @@ -124,7 +124,10 @@ GST_START_TEST (test_ghost_pads) gst_object_unref (gisink); assert_gstrefcount (fsink, 1); } -GST_END_TEST Suite * + +GST_END_TEST; + +Suite * gst_ghost_pad_suite (void) { Suite *s = suite_create ("GstGhostPad"); diff --git a/check/gst/gstdata.c b/check/gst/gstminiobject.c similarity index 53% rename from check/gst/gstdata.c rename to check/gst/gstminiobject.c index 8aefcb1..7513f34 100644 --- a/check/gst/gstdata.c +++ b/check/gst/gstminiobject.c @@ -1,8 +1,8 @@ /* GStreamer * - * unit test for GstData + * unit test for GstMiniObject * - * Copyright (C) <2004> Thomas Vander Stichele + * Copyright (C) <2005> Thomas Vander Stichele * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,7 +28,7 @@ GST_START_TEST (test_copy) buffer = gst_buffer_new_and_alloc (4); - copy = GST_BUFFER (gst_data_copy (GST_DATA (buffer))); + copy = GST_BUFFER (gst_mini_object_copy (GST_MINI_OBJECT (buffer))); fail_if (copy == NULL, "Copy of buffer returned NULL"); fail_unless (GST_BUFFER_SIZE (copy) == 4, @@ -39,70 +39,71 @@ GST_END_TEST GST_START_TEST (test_is_writable) { GstBuffer *buffer; - GstData *data; + GstMiniObject *mobj; buffer = gst_buffer_new_and_alloc (4); - data = GST_DATA (buffer); + mobj = GST_MINI_OBJECT (buffer); - fail_unless (gst_data_is_writable (data), + fail_unless (gst_mini_object_is_writable (mobj), "A buffer with one ref should be writable"); - GST_DATA_FLAG_SET (data, GST_DATA_READONLY); - fail_if (gst_data_is_writable (data), + GST_MINI_OBJECT_FLAG_SET (mobj, GST_MINI_OBJECT_FLAG_READONLY); + fail_if (gst_mini_object_is_writable (mobj), "A buffer with READONLY set should not be writable"); - GST_DATA_FLAG_UNSET (data, GST_DATA_READONLY); - fail_unless (gst_data_is_writable (data), + GST_MINI_OBJECT_FLAG_UNSET (mobj, GST_MINI_OBJECT_FLAG_READONLY); + fail_unless (gst_mini_object_is_writable (mobj), "A buffer with one ref and READONLY not set should be writable"); - fail_if (gst_data_ref (data) == NULL, "Could not ref the data"); + fail_if (gst_mini_object_ref (mobj) == NULL, "Could not ref the mobj"); - fail_if (gst_data_is_writable (data), + fail_if (gst_mini_object_is_writable (mobj), "A buffer with two refs should not be writable"); } GST_END_TEST -GST_START_TEST (test_copy_on_write) +GST_START_TEST (test_make_writable) { GstBuffer *buffer; - GstData *data, *data2, *data3; + GstMiniObject *mobj, *mobj2, *mobj3; buffer = gst_buffer_new_and_alloc (4); - data = GST_DATA (buffer); + mobj = GST_MINI_OBJECT (buffer); - data2 = gst_data_copy_on_write (data); - fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer"); - fail_unless (data == data2, - "copy_on_write returned a copy for a buffer with refcount 1"); + mobj2 = gst_mini_object_make_writable (mobj); + fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer"); + fail_unless (mobj == mobj2, + "make_writable returned a copy for a buffer with refcount 1"); - data2 = gst_data_ref (data); - data3 = gst_data_copy_on_write (data); - fail_unless (GST_IS_BUFFER (data3), "copy_on_write did not return a buffer"); - fail_if (data == data3, - "copy_on_write returned same object for a buffer with refcount > 1"); + mobj2 = gst_mini_object_ref (mobj); + mobj3 = gst_mini_object_make_writable (mobj); + fail_unless (GST_IS_BUFFER (mobj3), "make_writable did not return a buffer"); + fail_if (mobj == mobj3, + "make_writable returned same object for a buffer with refcount > 1"); - fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1, - "refcount of original data object should be back to 1"); + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1, + "refcount of original mobj object should be back to 1"); - data2 = gst_data_copy_on_write (data); - fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer"); - fail_unless (data == data2, - "copy_on_write returned a copy for a buffer with refcount 1"); + mobj2 = gst_mini_object_make_writable (mobj); + fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer"); + fail_unless (mobj == mobj2, + "make_writable returned a copy for a buffer with refcount 1"); } GST_END_TEST gint num_threads = 10; gint refs_per_thread = 10000; -/* test thread-safe refcounting of GstData */ +/* test thread-safe refcounting of GstMiniObject */ void -thread_ref (GstData * data) +thread_ref (GstMiniObject * mobj) { int j; THREAD_START (); for (j = 0; j < refs_per_thread; ++j) { - fail_if (gst_data_ref (data) == NULL, "Could not ref data from thread"); + fail_if (gst_mini_object_ref (mobj) == NULL, + "Could not ref mobj from thread"); if (j % num_threads == 0) THREAD_SWITCH (); @@ -113,30 +114,31 @@ thread_ref (GstData * data) GST_START_TEST (test_ref_threaded) { GstBuffer *buffer; - GstData *data; + GstMiniObject *mobj; gint expected; buffer = gst_buffer_new_and_alloc (4); - data = GST_DATA (buffer); + mobj = GST_MINI_OBJECT (buffer); - MAIN_START_THREADS (num_threads, thread_ref, data); + MAIN_START_THREADS (num_threads, thread_ref, mobj); MAIN_STOP_THREADS (); expected = num_threads * refs_per_thread + 1; - fail_unless (GST_DATA_REFCOUNT_VALUE (data) == expected, - "Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), expected); + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == expected, + "Refcount of mobj is %d != %d", GST_MINI_OBJECT_REFCOUNT_VALUE (mobj), + expected); } GST_END_TEST void -thread_unref (GstData * data) +thread_unref (GstMiniObject * mobj) { int j; THREAD_START (); for (j = 0; j < refs_per_thread; ++j) { - gst_data_unref (data); + gst_mini_object_unref (mobj); if (j % num_threads == 0) THREAD_SWITCH (); @@ -146,28 +148,30 @@ thread_unref (GstData * data) GST_START_TEST (test_unref_threaded) { GstBuffer *buffer; - GstData *data; + GstMiniObject *mobj; + int i; buffer = gst_buffer_new_and_alloc (4); - data = GST_DATA (buffer); + mobj = GST_MINI_OBJECT (buffer); - gst_data_ref_by_count (data, num_threads * refs_per_thread); + for (i = 0; i < num_threads * refs_per_thread; ++i) + gst_mini_object_ref (mobj); - MAIN_START_THREADS (num_threads, thread_unref, data); + MAIN_START_THREADS (num_threads, thread_unref, mobj); MAIN_STOP_THREADS (); - fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1, - "Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), 1); + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1, + "Refcount of mobj is %d != %d", GST_MINI_OBJECT_REFCOUNT_VALUE (mobj), 1); /* final unref */ - gst_data_unref (data); + gst_mini_object_unref (mobj); } GST_END_TEST Suite * -gst_data_suite (void) +gst_mini_object_suite (void) { - Suite *s = suite_create ("GstData"); + Suite *s = suite_create ("GstMiniObject"); TCase *tc_chain = tcase_create ("general"); /* turn off timeout */ @@ -176,7 +180,7 @@ gst_data_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_copy); tcase_add_test (tc_chain, test_is_writable); - tcase_add_test (tc_chain, test_copy_on_write); + tcase_add_test (tc_chain, test_make_writable); tcase_add_test (tc_chain, test_ref_threaded); tcase_add_test (tc_chain, test_unref_threaded); return s; @@ -187,7 +191,7 @@ main (int argc, char **argv) { int nf; - Suite *s = gst_data_suite (); + Suite *s = gst_mini_object_suite (); SRunner *sr = srunner_create (s); gst_check_init (&argc, &argv); diff --git a/configure.ac b/configure.ac index 453b59e..a9237e3 100644 --- a/configure.ac +++ b/configure.ac @@ -445,6 +445,9 @@ fi AC_SUBST(VALGRIND_CFLAGS) AC_SUBST(VALGRIND_LIBS) +AC_PATH_PROG(VALGRIND_PATH, valgrind, no) +AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") + dnl ################################################ dnl # Set defines according to variables set above # dnl ################################################ @@ -498,8 +501,8 @@ dnl ############################# dnl These should be "USE_*" instead of "HAVE_*", but some packages expect dnl HAVE_ and it is likely to be easier to stick with the old name -AM_CONDITIONAL(EXPERIMENTAL, test "$EXPERIMENTAL" = "$xyes") -AM_CONDITIONAL(BROKEN, test "$BROKEN" = "$xyes") +AM_CONDITIONAL(EXPERIMENTAL, test "x$EXPERIMENTAL" = "yes") +AM_CONDITIONAL(BROKEN, test "x$BROKEN" = "yes") AM_CONDITIONAL(PLUGINS_USE_BUILDDIR, test "x$PLUGINS_USE_BUILDDIR" = "xyes") diff --git a/gst/gst.c b/gst/gst.c index 7c3e496..4c52f0c 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -807,6 +807,25 @@ init_popt_callback (poptContext context, enum poptCallbackReason reason, } /** + * gst_deinit: + * + * Clean up. + * Call only once, before exiting. + * After this call GStreamer should not be used anymore. + */ +void +gst_deinit (void) +{ + GstClock *clock; + + clock = gst_system_clock_obtain (); + gst_object_unref (clock); + gst_object_unref (clock); + + gst_initialized = FALSE; +} + +/** * gst_version: * @major: pointer to a guint to store the major version number * @minor: pointer to a guint to store the minor version number diff --git a/gst/gst.h b/gst/gst.h index 6545c54..93ff048 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -99,6 +99,7 @@ gboolean gst_init_check_with_popt_table (int *argc, char **argv[], *popt_options); const GstPoptOption * gst_init_get_popt_table (void); +void gst_deinit (void); G_END_DECLS diff --git a/gst/gstsystemclock.c b/gst/gstsystemclock.c index 7c51d63..1366233 100644 --- a/gst/gstsystemclock.c +++ b/gst/gstsystemclock.c @@ -131,36 +131,34 @@ gst_system_clock_dispose (GObject * object) { GstClock *clock = (GstClock *) object; - /* there are subclasses of GstSystemClock running around... */ - if (_the_system_clock == clock) { - g_warning ("disposing systemclock!"); + GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock); + GList *entries; - /* no parent dispose here, this is bad enough already */ - } else { - GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock); - GList *entries; - - /* else we have to stop the thread */ - GST_LOCK (clock); - sysclock->stopping = TRUE; - /* unschedule all entries */ - for (entries = clock->entries; entries; entries = g_list_next (entries)) { - GstClockEntry *entry = (GstClockEntry *) entries->data; - - GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry); - entry->status = GST_CLOCK_UNSCHEDULED; - } - g_list_free (clock->entries); - clock->entries = NULL; - GST_CLOCK_BROADCAST (clock); - GST_UNLOCK (clock); + /* else we have to stop the thread */ + GST_LOCK (clock); + sysclock->stopping = TRUE; + /* unschedule all entries */ + for (entries = clock->entries; entries; entries = g_list_next (entries)) { + GstClockEntry *entry = (GstClockEntry *) entries->data; - if (sysclock->thread) - g_thread_join (sysclock->thread); - sysclock->thread = NULL; - GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread"); + GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry); + entry->status = GST_CLOCK_UNSCHEDULED; + } + g_list_free (clock->entries); + clock->entries = NULL; + GST_CLOCK_BROADCAST (clock); + GST_UNLOCK (clock); - G_OBJECT_CLASS (parent_class)->dispose (object); + if (sysclock->thread) + g_thread_join (sysclock->thread); + sysclock->thread = NULL; + GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread"); + + G_OBJECT_CLASS (parent_class)->dispose (object); + + if (_the_system_clock == clock) { + _the_system_clock = NULL; + GST_CAT_DEBUG (GST_CAT_CLOCK, "disposed system clock"); } } @@ -168,7 +166,7 @@ gst_system_clock_dispose (GObject * object) * gst_system_clock_obtain: * * Get a handle to the default system clock. The refcount of the - * clock will be increased so you need to unref the clock after + * clock will be increased so you need to unref the clock after * usage. * * Returns: the default clock. @@ -185,9 +183,6 @@ gst_system_clock_obtain (void) if (clock == NULL) { GST_CAT_DEBUG (GST_CAT_CLOCK, "creating new static system clock"); - /* FIXME: the only way to clean this up is to have a gst_exit() - * function; until then, the program will always end with the sysclock - * at refcount 1 */ clock = g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", "GstSystemClock", NULL); diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 9b8f907..919561c 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -15,6 +15,8 @@ install-pluginLTLIBRARIES: # ths core dumps of some machines have PIDs appended CLEANFILES = core.* test-registry.xml +EXTRA_DIST = gst.supp + clean-local: for i in `find . -name ".libs" -type d`; do \ rm -rf $$i; \ @@ -32,6 +34,7 @@ TESTS = $(top_builddir)/tools/gst-register \ gst/gstghostpad \ gst/gstiterator \ gst/gstmessage \ + gst/gstminiobject \ gst/gstobject \ gst/gstpad \ gst/gstsystemclock \ @@ -60,3 +63,59 @@ gst_libs_gdp_SOURCES = \ $(top_srcdir)/libs/gst/dataprotocol/dataprotocol.c # remove GST_ENABLE_NEW when dataprotocol has been declared API-stable gst_libs_gdp_CFLAGS = $(AM_CFLAGS) -DGST_ENABLE_NEW + +# valgrind testing + +# these just need fixing, period +TESTS_TO_FIX = \ + gst/gstghostpad \ + gst/gstiterator \ + gst/gstmessage \ + gst/gstpad \ + gst/gstsystemclock \ + gst/gststructure \ + gst/gsttag \ + gst/gstvalue \ + elements/gstfakesrc \ + pipelines/cleanup \ + pipelines/simple_launch_lines \ + gst-libs/gdp + +# these need fixing because the threads cause segfaults under valgrind +TESTS_THREADED = \ + gst/gstminiobject \ + gst/gstobject + +VALGRIND_TESTS_DISABLE = \ + $(top_builddir)/tools/gst-register \ + $(TESTS_THREADED) \ + $(TESTS_TO_FIX) + +if HAVE_VALGRIND +check-local: + make valgrind +else +check-local: + true +endif + +valgrind: + @echo "Valgrinding tests ..." + $(TESTS_ENVIRONMENT) $(top_builddir)/tools/gst-register + @failed=0; \ + for t in $(filter-out $(VALGRIND_TESTS_DISABLE),$(TESTS)); do \ + $(TESTS_ENVIRONMENT) \ + CK_FORK=no \ + libtool --mode=execute \ + $(VALGRIND_PATH) -q --suppressions=$(srcdir)/gst.supp \ + --leak-check=yes $$t; \ + if test "$$?" -ne 0; then \ + echo "Valgrind error for test $$t"; \ + failed=`expr $$failed + 1`; \ + fi; \ + done; \ + if test "$$failed" -ne 0; then \ + echo "$$failed tests had leaks under valgrind"; \ + false; \ + fi + diff --git a/tests/check/gst.supp b/tests/check/gst.supp new file mode 100644 index 0000000..6dec7da --- /dev/null +++ b/tests/check/gst.supp @@ -0,0 +1,68 @@ +### this file contains suppressions for valgrind when running +### the gstreamer unit tests +### it might be useful for wider use as well + + +### glibc suppressions + +# glibc does not deallocate thread-local storage + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 +} + +{ + + Memcheck:Cond + fun:strstr + fun:__pthread_initialize_minimal + obj:/lib/libpthread-*.so + obj:/lib/libpthread-*.so + fun:call_init + fun:_dl_init + obj:/lib/ld-*.so +} + +### glib suppressions + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + obj:/usr/lib/libgobject-2.0.so.* + obj:/usr/lib/libgobject-2.0.so.* + fun:g_type_init_with_debug_flags + fun:g_type_init + fun:init_pre + fun:init_popt_callback + obj:/usr/lib/libpopt.so.* + obj:/usr/lib/libpopt.so.* + fun:poptGetContext + fun:gst_init_check_with_popt_table +} + +### GStreamer suppressions + +# ds is saying he's rewriting the registry anyway +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:read_string + fun:load_plugin + fun:gst_xml_registry_load + fun:gst_registry_load + fun:_registry_load_func + fun:g_list_foreach + fun:gst_registry_pool_load_all + fun:init_post + fun:init_popt_callback +} + diff --git a/tests/check/gst/gst.c b/tests/check/gst/gst.c index dbcefec..11ae64a 100644 --- a/tests/check/gst/gst.c +++ b/tests/check/gst/gst.c @@ -31,6 +31,30 @@ GST_START_TEST (test_init) GST_END_TEST; +GST_START_TEST (test_deinit) +{ + gst_init (NULL, NULL); + + gst_deinit (); +} + +GST_END_TEST; + +GST_START_TEST (test_deinit_sysclock) +{ + GstClock *clock; + + gst_init (NULL, NULL); + + clock = gst_system_clock_obtain (); + gst_object_unref (clock); + + gst_deinit (); +} + +GST_END_TEST; + + Suite * gst_suite (void) { @@ -39,6 +63,8 @@ gst_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_init); + tcase_add_test (tc_chain, test_deinit); + tcase_add_test (tc_chain, test_deinit_sysclock); return s; } diff --git a/tests/check/gst/gstbuffer.c b/tests/check/gst/gstbuffer.c index 8d32f54..44cb812 100644 --- a/tests/check/gst/gstbuffer.c +++ b/tests/check/gst/gstbuffer.c @@ -28,6 +28,7 @@ GST_START_TEST (test_subbuffer) int rc; buffer = gst_buffer_new_and_alloc (4); + memset (GST_BUFFER_DATA (buffer), 0, 4); sub = gst_buffer_create_sub (buffer, 1, 2); @@ -38,6 +39,9 @@ GST_START_TEST (test_subbuffer) rc = GST_MINI_OBJECT_REFCOUNT_VALUE (buffer); fail_unless (rc == 2, "parent refcount is %d instead of 3", rc); + + /* clean up */ + gst_buffer_unref (sub); gst_buffer_unref (buffer); } @@ -62,6 +66,11 @@ GST_START_TEST (test_is_span_fast) fail_if (gst_buffer_is_span_fast (sub1, sub2) == FALSE, "two subbuffers next to each other should be span_fast"); + + /* clean up */ + gst_buffer_unref (sub1); + gst_buffer_unref (sub2); + gst_buffer_unref (buffer); } GST_END_TEST Suite * gst_test_suite (void) diff --git a/tests/check/gst/gstghostpad.c b/tests/check/gst/gstghostpad.c index dd0f47a..174cf3a 100644 --- a/tests/check/gst/gstghostpad.c +++ b/tests/check/gst/gstghostpad.c @@ -124,7 +124,10 @@ GST_START_TEST (test_ghost_pads) gst_object_unref (gisink); assert_gstrefcount (fsink, 1); } -GST_END_TEST Suite * + +GST_END_TEST; + +Suite * gst_ghost_pad_suite (void) { Suite *s = suite_create ("GstGhostPad"); diff --git a/tests/check/gst/gstdata.c b/tests/check/gst/gstminiobject.c similarity index 53% rename from tests/check/gst/gstdata.c rename to tests/check/gst/gstminiobject.c index 8aefcb1..7513f34 100644 --- a/tests/check/gst/gstdata.c +++ b/tests/check/gst/gstminiobject.c @@ -1,8 +1,8 @@ /* GStreamer * - * unit test for GstData + * unit test for GstMiniObject * - * Copyright (C) <2004> Thomas Vander Stichele + * Copyright (C) <2005> Thomas Vander Stichele * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,7 +28,7 @@ GST_START_TEST (test_copy) buffer = gst_buffer_new_and_alloc (4); - copy = GST_BUFFER (gst_data_copy (GST_DATA (buffer))); + copy = GST_BUFFER (gst_mini_object_copy (GST_MINI_OBJECT (buffer))); fail_if (copy == NULL, "Copy of buffer returned NULL"); fail_unless (GST_BUFFER_SIZE (copy) == 4, @@ -39,70 +39,71 @@ GST_END_TEST GST_START_TEST (test_is_writable) { GstBuffer *buffer; - GstData *data; + GstMiniObject *mobj; buffer = gst_buffer_new_and_alloc (4); - data = GST_DATA (buffer); + mobj = GST_MINI_OBJECT (buffer); - fail_unless (gst_data_is_writable (data), + fail_unless (gst_mini_object_is_writable (mobj), "A buffer with one ref should be writable"); - GST_DATA_FLAG_SET (data, GST_DATA_READONLY); - fail_if (gst_data_is_writable (data), + GST_MINI_OBJECT_FLAG_SET (mobj, GST_MINI_OBJECT_FLAG_READONLY); + fail_if (gst_mini_object_is_writable (mobj), "A buffer with READONLY set should not be writable"); - GST_DATA_FLAG_UNSET (data, GST_DATA_READONLY); - fail_unless (gst_data_is_writable (data), + GST_MINI_OBJECT_FLAG_UNSET (mobj, GST_MINI_OBJECT_FLAG_READONLY); + fail_unless (gst_mini_object_is_writable (mobj), "A buffer with one ref and READONLY not set should be writable"); - fail_if (gst_data_ref (data) == NULL, "Could not ref the data"); + fail_if (gst_mini_object_ref (mobj) == NULL, "Could not ref the mobj"); - fail_if (gst_data_is_writable (data), + fail_if (gst_mini_object_is_writable (mobj), "A buffer with two refs should not be writable"); } GST_END_TEST -GST_START_TEST (test_copy_on_write) +GST_START_TEST (test_make_writable) { GstBuffer *buffer; - GstData *data, *data2, *data3; + GstMiniObject *mobj, *mobj2, *mobj3; buffer = gst_buffer_new_and_alloc (4); - data = GST_DATA (buffer); + mobj = GST_MINI_OBJECT (buffer); - data2 = gst_data_copy_on_write (data); - fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer"); - fail_unless (data == data2, - "copy_on_write returned a copy for a buffer with refcount 1"); + mobj2 = gst_mini_object_make_writable (mobj); + fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer"); + fail_unless (mobj == mobj2, + "make_writable returned a copy for a buffer with refcount 1"); - data2 = gst_data_ref (data); - data3 = gst_data_copy_on_write (data); - fail_unless (GST_IS_BUFFER (data3), "copy_on_write did not return a buffer"); - fail_if (data == data3, - "copy_on_write returned same object for a buffer with refcount > 1"); + mobj2 = gst_mini_object_ref (mobj); + mobj3 = gst_mini_object_make_writable (mobj); + fail_unless (GST_IS_BUFFER (mobj3), "make_writable did not return a buffer"); + fail_if (mobj == mobj3, + "make_writable returned same object for a buffer with refcount > 1"); - fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1, - "refcount of original data object should be back to 1"); + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1, + "refcount of original mobj object should be back to 1"); - data2 = gst_data_copy_on_write (data); - fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer"); - fail_unless (data == data2, - "copy_on_write returned a copy for a buffer with refcount 1"); + mobj2 = gst_mini_object_make_writable (mobj); + fail_unless (GST_IS_BUFFER (mobj2), "make_writable did not return a buffer"); + fail_unless (mobj == mobj2, + "make_writable returned a copy for a buffer with refcount 1"); } GST_END_TEST gint num_threads = 10; gint refs_per_thread = 10000; -/* test thread-safe refcounting of GstData */ +/* test thread-safe refcounting of GstMiniObject */ void -thread_ref (GstData * data) +thread_ref (GstMiniObject * mobj) { int j; THREAD_START (); for (j = 0; j < refs_per_thread; ++j) { - fail_if (gst_data_ref (data) == NULL, "Could not ref data from thread"); + fail_if (gst_mini_object_ref (mobj) == NULL, + "Could not ref mobj from thread"); if (j % num_threads == 0) THREAD_SWITCH (); @@ -113,30 +114,31 @@ thread_ref (GstData * data) GST_START_TEST (test_ref_threaded) { GstBuffer *buffer; - GstData *data; + GstMiniObject *mobj; gint expected; buffer = gst_buffer_new_and_alloc (4); - data = GST_DATA (buffer); + mobj = GST_MINI_OBJECT (buffer); - MAIN_START_THREADS (num_threads, thread_ref, data); + MAIN_START_THREADS (num_threads, thread_ref, mobj); MAIN_STOP_THREADS (); expected = num_threads * refs_per_thread + 1; - fail_unless (GST_DATA_REFCOUNT_VALUE (data) == expected, - "Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), expected); + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == expected, + "Refcount of mobj is %d != %d", GST_MINI_OBJECT_REFCOUNT_VALUE (mobj), + expected); } GST_END_TEST void -thread_unref (GstData * data) +thread_unref (GstMiniObject * mobj) { int j; THREAD_START (); for (j = 0; j < refs_per_thread; ++j) { - gst_data_unref (data); + gst_mini_object_unref (mobj); if (j % num_threads == 0) THREAD_SWITCH (); @@ -146,28 +148,30 @@ thread_unref (GstData * data) GST_START_TEST (test_unref_threaded) { GstBuffer *buffer; - GstData *data; + GstMiniObject *mobj; + int i; buffer = gst_buffer_new_and_alloc (4); - data = GST_DATA (buffer); + mobj = GST_MINI_OBJECT (buffer); - gst_data_ref_by_count (data, num_threads * refs_per_thread); + for (i = 0; i < num_threads * refs_per_thread; ++i) + gst_mini_object_ref (mobj); - MAIN_START_THREADS (num_threads, thread_unref, data); + MAIN_START_THREADS (num_threads, thread_unref, mobj); MAIN_STOP_THREADS (); - fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1, - "Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), 1); + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (mobj) == 1, + "Refcount of mobj is %d != %d", GST_MINI_OBJECT_REFCOUNT_VALUE (mobj), 1); /* final unref */ - gst_data_unref (data); + gst_mini_object_unref (mobj); } GST_END_TEST Suite * -gst_data_suite (void) +gst_mini_object_suite (void) { - Suite *s = suite_create ("GstData"); + Suite *s = suite_create ("GstMiniObject"); TCase *tc_chain = tcase_create ("general"); /* turn off timeout */ @@ -176,7 +180,7 @@ gst_data_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_copy); tcase_add_test (tc_chain, test_is_writable); - tcase_add_test (tc_chain, test_copy_on_write); + tcase_add_test (tc_chain, test_make_writable); tcase_add_test (tc_chain, test_ref_threaded); tcase_add_test (tc_chain, test_unref_threaded); return s; @@ -187,7 +191,7 @@ main (int argc, char **argv) { int nf; - Suite *s = gst_data_suite (); + Suite *s = gst_mini_object_suite (); SRunner *sr = srunner_create (s); gst_check_init (&argc, &argv); diff --git a/tools/gst-launch.c b/tools/gst-launch.c index 19fbe5b..4e038d7 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -648,6 +648,7 @@ end: fprintf (stderr, _("FREEING pipeline ...\n")); gst_object_unref (pipeline); + gst_deinit (); if (trace) gst_alloc_trace_print_live ();