funnel: Fix racy state change
authorStian Selnes <stian@pexip.com>
Mon, 21 Sep 2015 11:58:51 +0000 (13:58 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Thu, 24 Sep 2015 10:14:57 +0000 (12:14 +0200)
Iterator may need to be resynced, for instance if pads are released
during state change.

got_eos should be protected by the object lock of the element, not of
the pad, as is the case throughout the rest of the funnel code.

https://bugzilla.gnome.org/show_bug.cgi?id=755343

plugins/elements/gstfunnel.c
tests/check/elements/funnel.c

index 80ba3a48e5cdd368190d3b3254d27891b7a12f17..bf45db58dbfef723918d07321a4a442d6e36d9da 100644 (file)
@@ -429,10 +429,11 @@ reset_pad (const GValue * data, gpointer user_data)
 {
   GstPad *pad = g_value_get_object (data);
   GstFunnelPad *fpad = GST_FUNNEL_PAD_CAST (pad);
+  GstFunnel *funnel = user_data;
 
-  GST_OBJECT_LOCK (pad);
+  GST_OBJECT_LOCK (funnel);
   fpad->got_eos = FALSE;
-  GST_OBJECT_UNLOCK (pad);
+  GST_OBJECT_UNLOCK (funnel);
 }
 
 static GstStateChangeReturn
@@ -451,9 +452,10 @@ gst_funnel_change_state (GstElement * element, GstStateChange transition)
       GstIteratorResult res;
 
       do {
-        res = gst_iterator_foreach (iter, reset_pad, NULL);
+        res = gst_iterator_foreach (iter, reset_pad, element);
+        if (res == GST_ITERATOR_RESYNC)
+          gst_iterator_resync (iter);
       } while (res == GST_ITERATOR_RESYNC);
-
       gst_iterator_free (iter);
 
       if (res == GST_ITERATOR_ERROR)
index 313dd4866613a05d7f585c86f2660cd74e8774c0..fa64a3a4960d1ca4916acd0a74ae210429a37ea4 100644 (file)
@@ -23,6 +23,7 @@
 # include <config.h>
 #endif
 
+#include <gst/check/gstharness.h>
 #include <gst/check/gstcheck.h>
 
 struct TestData
@@ -372,6 +373,42 @@ GST_START_TEST (test_funnel_gap_event)
 
 GST_END_TEST;
 
+GST_START_TEST (test_funnel_stress)
+{
+  GstHarness *h0 = gst_harness_new_with_padnames ("funnel", "sink_0", "src");
+  GstHarness *h1 = gst_harness_new_with_element (h0->element, "sink_1", NULL);
+  GstHarnessThread *state, *req, *push0, *push1;
+  GstPadTemplate *templ = gst_element_class_get_pad_template (
+      GST_ELEMENT_GET_CLASS (h0->element), "sink_%u");
+  GstCaps *caps = gst_caps_from_string ("testcaps");
+  GstBuffer *buf = gst_buffer_new ();
+  GstSegment segment;
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+
+  state = gst_harness_stress_statechange_start (h0);
+  req = gst_harness_stress_requestpad_start (h0, templ, NULL, NULL, TRUE);
+  push0 = gst_harness_stress_push_buffer_start (h0, caps, &segment, buf);
+  push1 = gst_harness_stress_push_buffer_start (h1, caps, &segment, buf);
+
+  gst_caps_unref (caps);
+  gst_buffer_unref (buf);
+
+  /* test-length */
+  g_usleep (G_USEC_PER_SEC * 1);
+
+  gst_harness_stress_thread_stop (push1);
+  gst_harness_stress_thread_stop (push0);
+  gst_harness_stress_thread_stop (req);
+  gst_harness_stress_thread_stop (state);
+
+  gst_harness_teardown (h1);
+  gst_harness_teardown (h0);
+}
+
+GST_END_TEST;
+
+
 static Suite *
 funnel_suite (void)
 {
@@ -382,6 +419,7 @@ funnel_suite (void)
   tcase_add_test (tc_chain, test_funnel_simple);
   tcase_add_test (tc_chain, test_funnel_eos);
   tcase_add_test (tc_chain, test_funnel_gap_event);
+  tcase_add_test (tc_chain, test_funnel_stress);
   suite_add_tcase (s, tc_chain);
 
   return s;