valgrind unit tests as check-local; add gst_deinit
authorThomas Vander Stichele <thomas@apestaart.org>
Mon, 11 Jul 2005 15:10:40 +0000 (15:10 +0000)
committerThomas Vander Stichele <thomas@apestaart.org>
Mon, 11 Jul 2005 15:10:40 +0000 (15:10 +0000)
Original commit message from CVS:
valgrind unit tests as check-local; add gst_deinit

18 files changed:
ChangeLog
check/Makefile.am
check/gst.supp [new file with mode: 0644]
check/gst/gst.c
check/gst/gstbuffer.c
check/gst/gstghostpad.c
check/gst/gstminiobject.c [moved from check/gst/gstdata.c with 53% similarity]
configure.ac
gst/gst.c
gst/gst.h
gst/gstsystemclock.c
tests/check/Makefile.am
tests/check/gst.supp [new file with mode: 0644]
tests/check/gst/gst.c
tests/check/gst/gstbuffer.c
tests/check/gst/gstghostpad.c
tests/check/gst/gstminiobject.c [moved from tests/check/gst/gstdata.c with 53% similarity]
tools/gst-launch.c

index 545df6d..20efd9f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,32 @@
 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:
        * docs/gst/tmpl/gstfakesrc.sgml:
        * gst/base/gstbasesrc.c: (gst_base_src_class_init),
index 9b8f907..919561c 100644 (file)
@@ -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 (file)
index 0000000..6dec7da
--- /dev/null
@@ -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
+}
+
index dbcefec..11ae64a 100644 (file)
@@ -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;
 }
index 8d32f54..44cb812 100644 (file)
@@ -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)
index dd0f47a..174cf3a 100644 (file)
@@ -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");
similarity index 53%
rename from check/gst/gstdata.c
rename to check/gst/gstminiobject.c
index 8aefcb1..7513f34 100644 (file)
@@ -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);
index 453b59e..a9237e3 100644 (file)
@@ -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")
 
 
index 7c3e496..4c52f0c 100644 (file)
--- 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
index 6545c54..93ff048 100644 (file)
--- 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
 
index 7c51d63..1366233 100644 (file)
@@ -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);
 
index 9b8f907..919561c 100644 (file)
@@ -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 (file)
index 0000000..6dec7da
--- /dev/null
@@ -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
+}
+
index dbcefec..11ae64a 100644 (file)
@@ -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;
 }
index 8d32f54..44cb812 100644 (file)
@@ -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)
index dd0f47a..174cf3a 100644 (file)
@@ -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");
similarity index 53%
rename from tests/check/gst/gstdata.c
rename to tests/check/gst/gstminiobject.c
index 8aefcb1..7513f34 100644 (file)
@@ -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);
index 19fbe5b..4e038d7 100644 (file)
@@ -648,6 +648,7 @@ end:
   fprintf (stderr, _("FREEING pipeline ...\n"));
   gst_object_unref (pipeline);
 
+  gst_deinit ();
   if (trace)
     gst_alloc_trace_print_live ();