From 4dbf73d88bf5ab2da154ac2f537aa28a67c5f8b6 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 25 Mar 2009 17:07:15 +0100 Subject: output: protect audio_output.open with the mutex There was a deadlock between the output thread and the player thread: when the output thread failed (and closed itself) while the player thread worked with the audio_output object, MPD could crash. --- src/output_all.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'src/output_all.c') diff --git a/src/output_all.c b/src/output_all.c index bf9202060..2e7d3a720 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -169,6 +169,19 @@ static void audio_output_wait_all(void) notify_wait(&audio_output_client_notify); } +static void +audio_output_reset_reopen(struct audio_output *ao) +{ + g_mutex_lock(ao->mutex); + + if (!ao->open && ao->fail_timer != NULL) { + g_timer_destroy(ao->fail_timer); + ao->fail_timer = NULL; + } + + g_mutex_unlock(ao->mutex); +} + /** * Resets the "reopen" flag on all audio devices. MPD should * immediately retry to open the device instead of waiting for the @@ -180,10 +193,7 @@ audio_output_all_reset_reopen(void) for (unsigned i = 0; i < num_audio_outputs; ++i) { struct audio_output *ao = &audio_outputs[i]; - if (!ao->open && ao->fail_timer != NULL) { - g_timer_destroy(ao->fail_timer); - ao->fail_timer = NULL; - } + audio_output_reset_reopen(ao); } } @@ -289,6 +299,9 @@ static bool chunk_is_consumed_in(const struct audio_output *ao, const struct music_chunk *chunk) { + if (!ao->open) + return true; + if (ao->chunk == NULL) return false; @@ -312,9 +325,6 @@ chunk_is_consumed(const struct music_chunk *chunk) const struct audio_output *ao = &audio_outputs[i]; bool consumed; - if (!ao->open) - continue; - g_mutex_lock(ao->mutex); consumed = chunk_is_consumed_in(ao, chunk); g_mutex_unlock(ao->mutex); @@ -339,14 +349,15 @@ clear_tail_chunk(G_GNUC_UNUSED const struct music_chunk *chunk, bool *locked) for (unsigned i = 0; i < num_audio_outputs; ++i) { struct audio_output *ao = &audio_outputs[i]; - locked[i] = ao->open; - - if (!locked[i]) - continue; - /* this mutex will be unlocked by the caller when it's ready */ g_mutex_lock(ao->mutex); + locked[i] = ao->open; + + if (!locked[i]) { + g_mutex_unlock(ao->mutex); + continue; + } assert(ao->chunk == chunk); assert(ao->chunk_finished); -- cgit v1.2.3