Ticket #166 (closed defect: fixed)

Opened 2 years ago

Last modified 20 months ago

Various asserts in pulseaudio that result in mplayer crash

Reported by: Stax Owned by: lennart
Milestone: 0.9.11 Component: libpulse
Keywords: Cc:

Description

I'm getting errors which crash mplayer's ao_pulse sometimes. Both seem to happen on stopping playback, making switching to next file in playlist impossible. They are

mplayer: pulse/mainloop.c:287: mainloop_defer_enable: Assertion `e->mainloop->n_enabled_defer_events > 0' failed.

It produces segfault and leaves core file, here is trace:

(gdb) where
#0  0x00000037766571db in glDeleteProgramsNV () from /usr/lib64/libGL.so.1
#1  0x000000000049c9e7 in uninitGl () at vo_gl.c:360
#2  0x000000000049ca0a in uninit () at vo_gl.c:774
#3  0x000000000045ae02 in uninit_player (mask=3787) at mplayer.c:615
#4  0x000000000045b27d in exit_player_with_rc (how=0x0, rc=1) at mplayer.c:669
#5  <signal handler called>
#6  0x000000376ac30ec5 in raise () from /lib64/libc.so.6
#7  0x000000376ac32970 in abort () from /lib64/libc.so.6
#8  0x000000376ac2a11f in __assert_fail () from /lib64/libc.so.6
#9  0x000000394b417761 in close () from /usr/lib64/libpulse.so.0
#10 0x000000394b42a930 in close () from /usr/lib64/libpulse.so.0
#11 0x000000394b4174b9 in pa_mainloop_dispatch () from /usr/lib64/libpulse.so.0
#12 0x000000394b4175f6 in pa_mainloop_iterate () from /usr/lib64/libpulse.so.0
#13 0x000000394b417680 in pa_mainloop_run () from /usr/lib64/libpulse.so.0
#14 0x000000394b41d79d in close () from /usr/lib64/libpulse.so.0
#15 0x000000394b431d2d in close () from /usr/lib64/libpulse.so.0
#16 0x000000376b806407 in start_thread () from /lib64/libpthread.so.0
#17 0x000000376acd4b0d in clone () from /lib64/libc.so.6
(gdb) 

And another one: mplayer: pulsecore/queue.c:67: pa_queue_free: Assertion `q->length == 0' failed.

This one leaves no trace, just crashes, but reports that it happens in uninit function, which looks like this:

static void uninit(int immed) {
    if (stream && !immed) {
            pa_threaded_mainloop_lock(mainloop);
            waitop(pa_stream_drain(stream, success_cb, NULL));
    }

    if (mainloop)
        pa_threaded_mainloop_stop(mainloop);

    if (stream) {
        pa_stream_disconnect(stream);
        pa_stream_unref(stream);
        stream = NULL;
    }

    if (context) {
        pa_context_disconnect(context);
        pa_context_unref(context);
        context = NULL;
    }

    if (mainloop) {
        pa_threaded_mainloop_free(mainloop);
        mainloop = NULL;
    }
}

Change History

Changed 2 years ago by Stax

One more assertion, this one in the middle of playing (after it mplayer crashes and playing stops though). No trace.

mplayer: pulsecore/queue.c:85: pa_queue_push: Assertion `q->front' failed.

Changed 2 years ago by Frank Mehnert

There is a bug in the ao_pulse.c code in the mplayer repository. The pa_stream_write() call has to be protected by the mainloop lock from the mainloop. The reason is that pa_stream_write() is not called from a mainloop callback. However, I'm not entirely sure about pa_stream_trigger. Perhaps the main developers could have a short note here. The attached patch works fine for me:

--- ao_pulse.c  (revision 25386)
+++ ao_pulse.c  (working copy)
@@ -251,11 +251,16 @@
 /** Play the specified data to the pulseaudio server */
 static int play(void* data, int len, int flags) {
     if (len) {
-        if (pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) {
+        int rc;
+        pa_threaded_mainloop_lock(mainloop);
+        rc = pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE);
+        pa_threaded_mainloop_unlock(mainloop);
+        if (rc < 0) {
             GENERIC_ERR_MSG(context, "pa_stream_write() failed");
             return -1;
         }
     } else {
+        pa_threaded_mainloop_lock(mainloop);
         pa_operation *o = pa_stream_trigger(stream, NULL, NULL);
         if (!o) {
             GENERIC_ERR_MSG(context, "pa_stream_trigger() failed");
@@ -263,6 +268,7 @@
         }
         /* We don't wait for this operation to complete */
         pa_operation_unref(o);
+        pa_threaded_mainloop_unlock(mainloop);
     }
     return len;
 }

Changed 2 years ago by lennart

If any of the pa_context_xxx() or pa_stream_xxx() functions are called from a different thread than the main loop thread while it is running than this has to be protected with _lock() and _unlock().

Hence, yes, you do have a race condition here. A bug in MPlayer, not in PA.

Changed 20 months ago by lennart

  • milestone set to 0.9.11

This has been fixed a while back in Mplayer upstream.

Changed 20 months ago by lennart

  • status changed from new to closed
  • resolution set to fixed
Note: See TracTickets for help on using tickets.