From 9036dc85940c1decb5c12ee253a6657b9cf70a2b Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 3 Feb 2015 17:06:43 +0000 Subject: [PATCH] decodebin: possible fix for deadlock when spamming "next song" There was a deadlock between a thread changing decodebin/demuxer state from PAUSED to READY, and another thread pushing data when starting. From the stack trace at https://bug741355.bugzilla-attachments.gnome.org/attachment.cgi?id=292471, I deduce the following is happening, though I did not reproduce the problem so I'm not sure this patch fixes it. The streaming thread (thread 2 in that stack trace) takes the demuxer's sink pad's stream lock in gst_ogg_demux_perform_seek_pull and will activate a new chain. This ends up causing the expose lock being taken in _pad_added_cb in decodebin. Meanwhile, a state changed is triggered on thread 1, which takes the expose lock in decodebin in gst_decode_bin_change_state, then frees the previous chain, which ends up calling gst_pad_stop_task on the demuxer's task, which in turn takes the demuxer's sink pad's stream lock, deadlocking as both threads are now waiting for each other. https://bugzilla.gnome.org/show_bug.cgi?id=741355 --- gst/playback/gstdecodebin2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index 00e5132888..87dd5ddce2 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -4853,6 +4853,7 @@ gst_decode_bin_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstDecodeBin *dbin = GST_DECODE_BIN (element); + GstDecodeChain *chain_to_free = NULL; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: @@ -4911,10 +4912,13 @@ gst_decode_bin_change_state (GstElement * element, GstStateChange transition) do_async_done (dbin); EXPOSE_LOCK (dbin); if (dbin->decode_chain) { - gst_decode_chain_free (dbin->decode_chain); + chain_to_free = dbin->decode_chain; + gst_decode_chain_free_internal (dbin->decode_chain, TRUE); dbin->decode_chain = NULL; } EXPOSE_UNLOCK (dbin); + if (chain_to_free) + gst_decode_chain_free (chain_to_free); g_list_free_full (dbin->buffering_status, (GDestroyNotify) gst_message_unref); dbin->buffering_status = NULL;