From b39f5067e3ef125a2674fdc299c2aa9b4fe78e00 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Mon, 3 Jul 2017 21:08:02 -0400 Subject: [PATCH] test-appsrc: Test state when blocked in caps Event In GStreamer 1.12 and older, the GstBaseSrc live lock used to be held while create() virtual function was called. As appsrc pushes serialized event in that virtual function, we ended up with some deadlock while setting the state to NULL. This test simulates this situation. https://bugzilla.gnome.org/show_bug.cgi?id=783301 --- tests/check/elements/appsrc.c | 65 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/check/elements/appsrc.c b/tests/check/elements/appsrc.c index 56fe0f7..56098c2 100644 --- a/tests/check/elements/appsrc.c +++ b/tests/check/elements/appsrc.c @@ -419,6 +419,70 @@ GST_START_TEST (test_appsrc_caps_in_push_modes) GST_END_TEST; +/* This test simulates a pipeline blocked pushing caps using a blocking pad + * probe. This state is seen if the application push buffers and later change + * the caps on one stream before the other stream have prerolled. In this + * state, GStreamer 1.12 and previous would deadlock inside GstBaseSrc as + * it was holding the live lock while calling create(). AppSrc serialize the + * caps event into it's queue and then push it downstream when create() is + * called. */ + +static GstPadProbeReturn +caps_event_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + GMainLoop *loop = user_data; + + if (GST_EVENT_TYPE (info->data) == GST_EVENT_CAPS) { + g_main_loop_quit (loop); + return GST_PAD_PROBE_OK; + } + + return GST_PAD_PROBE_PASS; +} + +GST_START_TEST (test_appsrc_blocked_on_caps) +{ + GstElement *pipeline = NULL, *app = NULL; + GstPad *pad = NULL; + GstCaps *caps = NULL; + GError *error = NULL; + GMainLoop *loop; + + loop = g_main_loop_new (NULL, FALSE); + + pipeline = gst_parse_launch ("appsrc is-live=1 name=app ! fakesink", &error); + g_assert_no_error (error); + + app = gst_bin_get_by_name (GST_BIN (pipeline), "app"); + pad = gst_element_get_static_pad (app, "src"); + + gst_pad_add_probe (pad, + GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + caps_event_probe_cb, loop, NULL); + gst_object_unref (app); + gst_object_unref (pad); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + caps = gst_caps_from_string ("application/x-test"); + gst_app_src_set_caps (GST_APP_SRC (app), caps); + gst_caps_unref (caps); + + g_main_loop_run (loop); + +#if 0 + /* This would work around the issue by deblocking the source on older + * version of GStreamer */ + gst_element_send_event (app, gst_event_new_flush_start ()); +#endif + + /* As appsrc change the caps GstBaseSrc::create() virtual function, the live + * lock use to remains held and prevented the state change from happening. */ + gst_element_set_state (pipeline, GST_STATE_NULL); +} + +GST_END_TEST; + static Suite * appsrc_suite (void) { @@ -428,6 +492,7 @@ appsrc_suite (void) tcase_add_test (tc_chain, test_appsrc_non_null_caps); tcase_add_test (tc_chain, test_appsrc_set_caps_twice); tcase_add_test (tc_chain, test_appsrc_caps_in_push_modes); + tcase_add_test (tc_chain, test_appsrc_blocked_on_caps); if (RUNNING_ON_VALGRIND) tcase_add_loop_test (tc_chain, test_appsrc_block_deadlock, 0, 5); -- 2.7.4