mirror of
https://github.com/linux-speakup/espeakup.git
synced 2026-08-21 23:34:18 +02:00
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:
parent
a8cad20de8
commit
b7f324072f
4 changed files with 16 additions and 10 deletions
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
15
softsynth.c
15
softsynth.c
|
|
@ -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)
|
||||
|
|
|
|||
7
synth.c
7
synth.c
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue