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
This commit is contained in:
Vincent Penquerc'h 2015-02-03 17:06:43 +00:00
parent cd07101420
commit 9036dc8594

View file

@ -4853,6 +4853,7 @@ gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
{ {
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstDecodeBin *dbin = GST_DECODE_BIN (element); GstDecodeBin *dbin = GST_DECODE_BIN (element);
GstDecodeChain *chain_to_free = NULL;
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_NULL_TO_READY:
@ -4911,10 +4912,13 @@ gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
do_async_done (dbin); do_async_done (dbin);
EXPOSE_LOCK (dbin); EXPOSE_LOCK (dbin);
if (dbin->decode_chain) { 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; dbin->decode_chain = NULL;
} }
EXPOSE_UNLOCK (dbin); EXPOSE_UNLOCK (dbin);
if (chain_to_free)
gst_decode_chain_free (chain_to_free);
g_list_free_full (dbin->buffering_status, g_list_free_full (dbin->buffering_status,
(GDestroyNotify) gst_message_unref); (GDestroyNotify) gst_message_unref);
dbin->buffering_status = NULL; dbin->buffering_status = NULL;