GNOME Bugzilla – Bug 614650
GStreamer crash when using playbin2 and about_to_finish signal
Last modified: 2012-02-19 15:54:26 UTC
Created attachment 157742 [details] test case When using the about_to_finish signal of playbin2, the program randomly crash if it is busy (ie: a few seconds without running the mainloop) when the about_to_finish signal is fired by gstreamer. I could reproduce the problem in the attached test case, give it 2 files as arguments, it will skip toward the end of the first one, and then count to a very high number to make it busy. Most of the time, the program will randomly crash when the about_to_finish signal is fired. When it does not crash, you can see that the "about to finish" message is printed while the program was counting to a high number, which means the perl callback was called from a gstreamer thread.
Created attachment 158929 [details] [review] Fix a threading bug in dGPERL_CLOSURE_MARSHAL_ARGS Previously, dGPERL_CLOSURE_MARSHAL_ARGS used the dSP macro to declare the stack pointer. But dSP involves accessing the my_perl pointer which might be invalid if we've been called from a thread other than the main one. To avoid this, manually declare SV **sp first and let GPERL_CLOSURE_MARSHAL_INIT initialize it after it has set up my_perl via PERL_SET_CONTEXT. This fixes the bug with your example program on my system. Quentin, can you verify this?
Sadly, it still crashes for me. Both with the test-case and in my program. I tested it with the perl from mandriva 2010 : perl-5.10.1 (Compile-time options: MULTIPLICITY PERL_DONT_CREATE_GVSV PERL_IMPLICIT_CONTEXT PERL_MALLOC_WRAP USE_ITHREADS USE_LARGE_FILES USE_PERLIO USE_REENTRANT_API) and with a brand new perl-5.12.0 (Compile-time options: PERL_DONT_CREATE_GVSV PERL_MALLOC_WRAP USE_LARGE_FILES USE_PERLIO USE_PERL_ATOF)
How does it crash exactly, i.e. what do gdb and valgrind say? $ gdb perl > r test.pl ... segfault ... > bt $ valgrind --tool=memcheck --num-callers=50 perl test.pl
Created attachment 159490 [details] a few examples of backtraces made with the patch above (Fix a threading bug in dGPERL_CLOSURE_MARSHAL_ARGS) it crashes ~50 % of the times
Created attachment 159491 [details] valgrind output output of "valgrind --tool=memcheck --num-callers=50" (also made with the patch) I added the output of a case where it did not crash, for comparison.
OK, this turned out to be way more intricate than expected. Basically, the problem is, as I'm sure you know already, that the about_to_finish signal handler is called from a new thread. And we're not prepared to handle this. See bug 620099 for my current stab at this. If you want to test this, make sure you pass the callback reference by name, like this: $player->signal_connect(about_to_finish => "main::about_to_finish", $file2); Passing code references (i.e., \&about_to_finish) between threads is not supported (by us, but also by perl).
As an experiment, can you try having the callback call g_idle_add() to defer execution of the callback action to the main loop? The simple approach would be sub about_to_finish { Glib::Idle->add (sub { ...}); } but i suspect that will crash for the same reasons. So, you might actually want to use a C/XS thunk to experiment. For example: $player->signal_connect (about_to_finish => 'thunk_to_mainloop', $file2); where 'thunk_to_mainloop' is the name of an XSub that calls g_idle_add() under the hook to ask the main loop to invoke a function. This way you get the code executed on a thread that we do know about.
I've now implemented muppet's suggestion in attachment 187851 [details] [review] to bug 620099. It sort of fixes the problem. "Sort of" because it does not fix the test case as-is. The timeout source \&count needs to be disabled (or, at least, its duration needs to be shortened) for the new approach to work: with it still in place, the main loop is blocked from processing the about-to-finish invocation in time. Is that still good enough for your purposes, Quentin?