From: Anton Lindqvist Date: Fri, 3 Dec 2021 19:45:51 +0000 (+0100) Subject: avoid recursive mutex acquisition in sndio backend X-Git-Tag: 4.1-rc1~24^2~365^2^2 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F1362%2Fhead;p=thirdparty%2Fshairport-sync.git avoid recursive mutex acquisition in sndio backend Ending a RTSP session while running on OpenBSD using sndio backend causes the following crash: #0 thrkill () #1 0x000005208224403e in _libc_abort #2 0x00000520821b77be in _rthread_mutex_trylock #3 _rthread_mutex_timedlock #4 0x0000051e0d54e2c0 in stop () #5 0x0000051e0d544e85 in player_thread_cleanup_handler #6 0x0000052082243126 in _libc_pthread_exit #7 0x000005209a158700 in sigthr_handler #8 #9 _thread_sys_poll () #10 0x000005208223533e in _libc_poll_cancel #11 0x00000520df54c9a0 in sio_psleep #12 0x00000520df54cc1f in sio_write #13 0x0000051e0d54e27a in play #14 0x0000051e0d547fc0 in player_thread_func #15 0x000005209a158cc1 in _rthread_start #16 0x000005208223565a in __tfork_thread The player thread is blocking inside sio_write() -> poll(2) while the thread is being terminated. The stop routine tied to the same backend is invoked through player_thread_cleanup_handler() which tries to acquire the mutex which it already acquired before invoking sio_write(). Avoiding blocking writes would require switching to async I/O which is quite an undertaking. The fact that there's only one `struct sio_hdl *' instance in the compilation unit sort of implies there can only be one player thread at a time. Therefore fix the crash by only trying to acquire the mutex and continue as usual if it's already acquired. --- diff --git a/audio_sndio.c b/audio_sndio.c index f8582c8a..6ada40ad 100644 --- a/audio_sndio.c +++ b/audio_sndio.c @@ -239,11 +239,19 @@ static int play(void *buf, int frames) { } static void stop() { - pthread_mutex_lock(&sndio_mutex); + int gotlock = 1; + + // The player thread could already be waiting in sio_write() during + // termination implying that the same thread already have acquired the mutex. + if (pthread_mutex_trylock(&sndio_mutex)) + gotlock = 0; + if (!sio_stop(hdl)) die("sndio: unable to stop"); written = played = 0; - pthread_mutex_unlock(&sndio_mutex); + + if (gotlock) + pthread_mutex_unlock(&sndio_mutex); } static void onmove_cb(__attribute__((unused)) void *arg, int delta) {