GNOME Bugzilla – Bug 702697
adder: Seek while paused causes deadlock
Last modified: 2015-07-11 20:57:23 UTC
Created attachment 247292 [details] Python script demonstrating problem. "adder" has a deadlock in `gst_adder_sink_event` if you seek while paused. This (with input-selector) works fine: ./playbin-adder-seek.py 'https://dl.dropboxusercontent.com/s/aggvr6ch12oqy76/test.mkv?token_hash=AAG9qwEgF7qNdaxHIHzSwX0pGENusbixzL_xfHL2UOLhlA&dl=1' But this (with adder) locks up when I pause then seek: ./playbin-adder-seek.py --use-adder 'https://dl.dropboxusercontent.com/s/aggvr6ch12oqy76/test.mkv?token_hash=AAG9qwEgF7qNdaxHIHzSwX0pGENusbixzL_xfHL2UOLhlA&dl=1' (If this link doesn't work for some reason, you can get the file I'm using here: https://www.dropbox.com/s/aggvr6ch12oqy76/test.mkv) It works fine if I'm not paused. The example file just sets the state to PAUSED, then tries to seek every second. Backtrace:
+ Trace 232108
Oh, and sometimes it works a couple times before locking up, so definitely some sort of race condition.
`GST_COLLECT_PADS_STREAM_LOCK` is sometimes called in `gst_collect_pads_event` before it gets called in `gst_adder_sink_event`, but they should be in the same thread, right? Changing `gst_adder_sink_event` to not do that lock seems to work, but I'm guessing it's not correct: case GST_EVENT_FLUSH_START: /* ensure that we will send a flush stop */ adder->flush_stop_pending = TRUE; res = gst_collect_pads_event_default (pads, pad, event, discard); event = NULL; break;
Here's a backtrace with all of the threads:
+ Trace 232109
Thread 10 (Thread 0x7fffd66a3700 (LWP 18819))
Thread 1 (Thread 0x7ffff7fd2700 (LWP 14594))
It looks like thread 8 is holding the lock for some reason..
The other lock is at line 2019 in `gst_collect_pads_chain`.
Releasing the lock before `ret = gst_collect_pads_check_collected (pads);` and then getting it back again after seems to fix the problem too, but again, I don't know what the correct behaviour is here since I'm completely unfamiliar with these elements :\
This function in gstadder.c is pretty suspicious. It's sending flush_stop events for some reason? static gboolean forward_event_func (const GValue * val, GValue * ret, EventData * data) { GstPad *pad = g_value_get_object (val); GstEvent *event = data->event; GstPad *peer; gst_event_ref (event); GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event)); peer = gst_pad_get_peer (pad); /* collect pad might have been set flushing, * so bypass core checking that and send directly to peer */ if (!peer || !gst_pad_send_event (peer, event)) { if (!peer) gst_event_unref (event); GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.", event, GST_EVENT_TYPE_NAME (event)); /* quick hack to unflush the pads, ideally we need a way to just unflush * this single collect pad */ if (data->flush) gst_pad_send_event (pad, gst_event_new_flush_stop (TRUE)); } else { g_value_set_boolean (ret, TRUE); GST_LOG_OBJECT (pad, "Sent event %p (%s).", event, GST_EVENT_TYPE_NAME (event)); } if (peer) gst_object_unref (peer); /* continue on other pads, even if one failed */ return TRUE; }
I'm working on a new element called audiomixer that fixes some of these things and also implements synchronized mixing (which adder does not do at all currently). I agree that the code in adder at many places is quite suspicious :)
Let's close this as WONTFIX, since adder is generally quite dodgy and I don't expect this will get fixed, ever (if it's even possible to fix). The new audiomixer element should handle this correctly. I'm having problems with your script, so didn't test.