Fix concurrency bugs.

1. Don't lock or unlock queue_guard during queue_clear.
It is locked when queue_clear is called, and it should remain so.
2. Protect runner_must_stop with queue_guard in
the request_espeak_stop function.
The following condition should always hold: queue_guard is locked while
testing or modifying runner_must_stop.
3. Rename stop_guard to acknowledge_guard.  This is a more
descriptive name.  This mutex simply protects the acknowledgement of
the stop request from being lost.
4. Remove the pthread_mutex_lock from the top of queue_process_entry,
because queue_guard is already locked when the function is called.
This commit is contained in:
Christopher Brannon 2009-06-25 11:38:46 -05:00 committed by William Hubbs
commit b7f324072f
4 changed files with 16 additions and 10 deletions

View file

@ -42,7 +42,7 @@ espeak_AUDIO_OUTPUT audio_mode;
pthread_cond_t runner_awake = PTHREAD_COND_INITIALIZER;
pthread_cond_t stop_acknowledged = PTHREAD_COND_INITIALIZER;
pthread_mutex_t queue_guard = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t stop_guard = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t acknowledge_guard = PTHREAD_MUTEX_INITIALIZER;
int espeakup_is_running(void)
{

View file

@ -88,6 +88,6 @@ extern espeak_AUDIO_OUTPUT audio_mode;
extern pthread_cond_t runner_awake;
extern pthread_cond_t stop_acknowledged;
extern pthread_mutex_t queue_guard;
extern pthread_mutex_t stop_guard;
extern pthread_mutex_t acknowledge_guard;
#endif

View file

@ -167,11 +167,20 @@ static void process_buffer(struct synth_t *s, char *buf, ssize_t length)
static void request_espeak_stop(void)
{
pthread_mutex_lock(&stop_guard);
pthread_mutex_lock(&acknowledge_guard);
pthread_mutex_lock(&queue_guard);
runner_must_stop = 1;
pthread_mutex_unlock(&queue_guard);
pthread_cond_signal(&runner_awake); /* Wake runner, if necessary. */
pthread_cond_wait(&stop_acknowledged, &stop_guard);
pthread_mutex_unlock(&stop_guard);
/*
* Runner will see runner_must_stop == 1 next time it locks
* queue_guard, or when it awakens.
* It will lock acknowledge_guard, acknowledge the stop, and signal
* the reader, which will awaken.
*/
pthread_cond_wait(&stop_acknowledged, &acknowledge_guard);
pthread_mutex_unlock(&acknowledge_guard);
}
void *softsynth_thread(void *arg)

View file

@ -148,7 +148,6 @@ static void queue_process_entry(struct synth_t *s)
espeak_ERROR error;
struct espeak_entry_t *current;
pthread_mutex_lock(&queue_guard);
current = (struct espeak_entry_t *) queue_peek();
pthread_mutex_unlock(&queue_guard);
if (current) {
@ -198,14 +197,12 @@ static void queue_clear()
{
struct espeak_entry_t *current;
pthread_mutex_lock(&queue_guard);
current = (struct espeak_entry_t *) queue_peek();
while (current) {
free_entry(current);
queue_remove();
current = (struct espeak_entry_t *) queue_peek();
}
pthread_mutex_unlock(&queue_guard);
}
/* espeak_thread is the "main" function of our secondary (queue-processing)
@ -267,11 +264,11 @@ void *espeak_thread(void *arg)
}
if (runner_must_stop) {
pthread_mutex_lock(&stop_guard);
pthread_mutex_lock(&acknowledge_guard);
queue_clear();
stop_speech();
runner_must_stop = 0;
pthread_mutex_unlock(&stop_guard);
pthread_mutex_unlock(&acknowledge_guard);
pthread_cond_signal(&stop_acknowledged);
}
}