Commit 6d670e7c authored by Martin Steghöfer's avatar Martin Steghöfer Committed by Thomas Daede

Fix synchronization issue

The following interleaving can cause problems:
The interrupt for SIGINT could set sig_request.cancel right after the consumer thread
checks it ("buf->cancel_flag || sig_request.cancel"), but before the consumer
thread enters the mutex in order to wait for more data ("COND_WAIT"). If the producer
thread reacts to the new situation immediately by exiting (which it can do because the
consumer thread hasn't entered the mutex yet), the consumer thread initiates a COND_WAIT
that might never be fulfilled because the producer thread is gone. The producer's intention
to kill the consumer using buffer_thread_kill doesn't work because it was executed after
the consumer's check for buf->cancel_flag and before the consumer's COND_WAIT.

Fix the problem by putting the cancelation flag checks in the same mutex lock zone as
the "COND_WAIT".
parent 34d88b00
......@@ -210,12 +210,14 @@ void *buffer_thread_func (void *arg)
never be unset. */
while ( !(buf->eos && buf->curfill == 0) && !buf->abort_write) {
LOCK_MUTEX (buf->mutex);
DEBUG("Check for cancelation");
if (buf->cancel_flag || sig_request.cancel)
DEBUG("Check for something to play");
/* Block until we can play something */
LOCK_MUTEX (buf->mutex);
if (buf->prebuffering ||
buf->paused ||
(buf->curfill < buf->audio_chunk_size && !buf->eos)) {
......@@ -224,13 +226,14 @@ void *buffer_thread_func (void *arg)
COND_WAIT(buf->playback_cond, buf->mutex);
DEBUG("Check for cancelation");
if (buf->cancel_flag || sig_request.cancel)
DEBUG("Ready to play");
if (buf->cancel_flag || sig_request.cancel)
/* Don't need to lock buffer while running actions since position
won't change. We clear out any actions before we compute the
dequeue size so we don't consider actions that need to
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment