mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-16 19:25:18 +00:00
valgrind unit tests as check-local; add gst_deinit
Original commit message from CVS: valgrind unit tests as check-local; add gst_deinit
This commit is contained in:
parent
aff85422dc
commit
a59215bb4e
18 changed files with 523 additions and 139 deletions
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
|||
2005-07-11 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* 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 <thomas at apestaart dot org>
|
||||
|
||||
* docs/gst/tmpl/gstbasesrc.sgml:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
68
check/gst.supp
Normal file
68
check/gst.supp
Normal file
|
@ -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
|
||||
|
||||
{
|
||||
<tls>
|
||||
Memcheck:Leak
|
||||
fun:calloc
|
||||
fun:_dl_allocate_tls
|
||||
fun:pthread_create@@GLIBC_2.1
|
||||
}
|
||||
|
||||
{
|
||||
<pthread strstr>
|
||||
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
|
||||
|
||||
{
|
||||
<g_type_init>
|
||||
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
|
||||
{
|
||||
<registry>
|
||||
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
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* GStreamer
|
||||
*
|
||||
* unit test for GstData
|
||||
* unit test for GstMiniObject
|
||||
*
|
||||
* Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
*
|
||||
* 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);
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
19
gst/gst.c
19
gst/gst.c
|
@ -806,6 +806,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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -131,36 +131,34 @@ gst_system_clock_dispose (GObject * object)
|
|||
{
|
||||
GstClock *clock = (GstClock *) object;
|
||||
|
||||
/* there are subclasses of GstSystemClock running around... */
|
||||
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);
|
||||
|
||||
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) {
|
||||
g_warning ("disposing systemclock!");
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
_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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
68
tests/check/gst.supp
Normal file
68
tests/check/gst.supp
Normal file
|
@ -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
|
||||
|
||||
{
|
||||
<tls>
|
||||
Memcheck:Leak
|
||||
fun:calloc
|
||||
fun:_dl_allocate_tls
|
||||
fun:pthread_create@@GLIBC_2.1
|
||||
}
|
||||
|
||||
{
|
||||
<pthread strstr>
|
||||
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
|
||||
|
||||
{
|
||||
<g_type_init>
|
||||
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
|
||||
{
|
||||
<registry>
|
||||
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
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* GStreamer
|
||||
*
|
||||
* unit test for GstData
|
||||
* unit test for GstMiniObject
|
||||
*
|
||||
* Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
*
|
||||
* 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);
|
|
@ -648,6 +648,7 @@ end:
|
|||
fprintf (stderr, _("FREEING pipeline ...\n"));
|
||||
gst_object_unref (pipeline);
|
||||
|
||||
gst_deinit ();
|
||||
if (trace)
|
||||
gst_alloc_trace_print_live ();
|
||||
|
||||
|
|
Loading…
Reference in a new issue