|
|
@@ -23,7 +23,6 @@ |
|
|
|
#include <assert.h> |
|
|
|
#include <errno.h> |
|
|
|
#include <pthread.h> |
|
|
|
#include <semaphore.h> |
|
|
|
#include <stdint.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <string.h> |
|
|
@@ -43,12 +42,17 @@ |
|
|
|
// my_stop_is_required, and the command fifo |
|
|
|
static pthread_mutex_t my_mutex; |
|
|
|
static int my_command_is_running = 0; |
|
|
|
static pthread_cond_t my_cond_command_is_running; |
|
|
|
static int my_stop_is_required = 0; |
|
|
|
|
|
|
|
// my_thread: reads commands from the fifo, and runs them. |
|
|
|
static pthread_t my_thread; |
|
|
|
static sem_t my_sem_start_is_required; |
|
|
|
static sem_t my_sem_stop_is_acknowledged; |
|
|
|
|
|
|
|
static pthread_cond_t my_cond_start_is_required; |
|
|
|
static int my_start_is_required = 0; |
|
|
|
|
|
|
|
static pthread_cond_t my_cond_stop_is_acknowledged; |
|
|
|
static int my_stop_is_acknowledged = 0; |
|
|
|
|
|
|
|
static void *say_thread(void *); |
|
|
|
|
|
|
@@ -69,8 +73,9 @@ void fifo_init() |
|
|
|
pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL); |
|
|
|
init(0); |
|
|
|
|
|
|
|
assert(-1 != sem_init(&my_sem_start_is_required, 0, 0)); |
|
|
|
assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0)); |
|
|
|
assert(-1 != pthread_cond_init(&my_cond_command_is_running, NULL)); |
|
|
|
assert(-1 != pthread_cond_init(&my_cond_start_is_required, NULL)); |
|
|
|
assert(-1 != pthread_cond_init(&my_cond_stop_is_acknowledged, NULL)); |
|
|
|
|
|
|
|
pthread_attr_t a_attrib; |
|
|
|
if (pthread_attr_init(&a_attrib) |
|
|
@@ -85,8 +90,11 @@ void fifo_init() |
|
|
|
pthread_attr_destroy(&a_attrib); |
|
|
|
|
|
|
|
// leave once the thread is actually started |
|
|
|
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR) |
|
|
|
assert(-1 != pthread_mutex_lock(&my_mutex)); |
|
|
|
while ((my_stop_is_acknowledged == 0) || ((pthread_cond_wait(&my_cond_stop_is_acknowledged, &my_mutex) == -1) && errno == EINTR)) |
|
|
|
continue; // Restart when interrupted by handler |
|
|
|
my_stop_is_acknowledged = 0; |
|
|
|
pthread_mutex_unlock(&my_mutex); |
|
|
|
} |
|
|
|
|
|
|
|
espeak_ng_STATUS fifo_add_command(t_espeak_command *the_command) |
|
|
@@ -99,20 +107,18 @@ espeak_ng_STATUS fifo_add_command(t_espeak_command *the_command) |
|
|
|
pthread_mutex_unlock(&my_mutex); |
|
|
|
return status; |
|
|
|
} |
|
|
|
|
|
|
|
if ((status = pthread_mutex_unlock(&my_mutex)) != ENS_OK) |
|
|
|
return status; |
|
|
|
|
|
|
|
if (!my_command_is_running) { |
|
|
|
// quit when command is actually started |
|
|
|
// (for possible forthcoming 'end of command' checks) |
|
|
|
sem_post(&my_sem_start_is_required); |
|
|
|
int val = 1; |
|
|
|
while (val > 0) { |
|
|
|
usleep(50000); // TBD: event? |
|
|
|
sem_getvalue(&my_sem_start_is_required, &val); |
|
|
|
|
|
|
|
my_start_is_required = 1; |
|
|
|
pthread_cond_signal(&my_cond_start_is_required); |
|
|
|
|
|
|
|
while (!my_command_is_running) { |
|
|
|
if((status = pthread_cond_wait(&my_cond_command_is_running, &my_mutex)) != ENS_OK && errno != EINTR) { |
|
|
|
pthread_mutex_unlock(&my_mutex); |
|
|
|
return status; |
|
|
|
} |
|
|
|
} |
|
|
|
if ((status = pthread_mutex_unlock(&my_mutex)) != ENS_OK) |
|
|
|
return status; |
|
|
|
|
|
|
|
return ENS_OK; |
|
|
|
} |
|
|
@@ -138,19 +144,17 @@ espeak_ng_STATUS fifo_add_commands(t_espeak_command *command1, t_espeak_command |
|
|
|
return status; |
|
|
|
} |
|
|
|
|
|
|
|
if ((status = pthread_mutex_unlock(&my_mutex)) != ENS_OK) |
|
|
|
return status; |
|
|
|
|
|
|
|
if (!my_command_is_running) { |
|
|
|
// quit when one command is actually started |
|
|
|
// (for possible forthcoming 'end of command' checks) |
|
|
|
sem_post(&my_sem_start_is_required); |
|
|
|
int val = 1; |
|
|
|
while (val > 0) { |
|
|
|
usleep(50000); // TBD: event? |
|
|
|
sem_getvalue(&my_sem_start_is_required, &val); |
|
|
|
my_start_is_required = 1; |
|
|
|
pthread_cond_signal(&my_cond_start_is_required); |
|
|
|
|
|
|
|
while (!my_command_is_running) { |
|
|
|
if((status = pthread_cond_wait(&my_cond_command_is_running, &my_mutex)) != ENS_OK && errno != EINTR) { |
|
|
|
pthread_mutex_unlock(&my_mutex); |
|
|
|
return status; |
|
|
|
} |
|
|
|
} |
|
|
|
if ((status = pthread_mutex_unlock(&my_mutex)) != ENS_OK) |
|
|
|
return status; |
|
|
|
|
|
|
|
return ENS_OK; |
|
|
|
} |
|
|
@@ -167,15 +171,14 @@ espeak_ng_STATUS fifo_stop() |
|
|
|
my_stop_is_required = 1; |
|
|
|
} |
|
|
|
|
|
|
|
if ((status = pthread_mutex_unlock(&my_mutex)) != ENS_OK) |
|
|
|
return status; |
|
|
|
|
|
|
|
if (a_command_is_running) { |
|
|
|
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR) |
|
|
|
while ((my_stop_is_acknowledged == 0) || ((pthread_cond_wait(&my_cond_stop_is_acknowledged, &my_mutex) == -1) && errno == EINTR)) |
|
|
|
continue; // Restart when interrupted by handler |
|
|
|
} |
|
|
|
|
|
|
|
my_stop_is_required = 0; |
|
|
|
if ((status = pthread_mutex_unlock(&my_mutex)) != ENS_OK) |
|
|
|
return status; |
|
|
|
|
|
|
|
return ENS_OK; |
|
|
|
} |
|
|
@@ -189,7 +192,7 @@ static int sleep_until_start_request_or_inactivity() |
|
|
|
{ |
|
|
|
int a_start_is_required = 0; |
|
|
|
|
|
|
|
// Wait for the start request (my_sem_start_is_required). |
|
|
|
// Wait for the start request (my_cond_start_is_required). |
|
|
|
// Besides this, if the audio stream is still busy, |
|
|
|
// check from time to time its end. |
|
|
|
// The end of the stream is confirmed by several checks |
|
|
@@ -206,8 +209,10 @@ static int sleep_until_start_request_or_inactivity() |
|
|
|
clock_gettime2(&ts); |
|
|
|
|
|
|
|
add_time_in_ms(&ts, INACTIVITY_TIMEOUT); |
|
|
|
err = pthread_mutex_lock(&my_mutex); |
|
|
|
assert(err != -1); |
|
|
|
|
|
|
|
while ((err = sem_timedwait(&my_sem_start_is_required, &ts)) == -1 |
|
|
|
while ((err = pthread_cond_timedwait(&my_cond_start_is_required, &my_mutex, &ts)) == -1 |
|
|
|
&& errno == EINTR) |
|
|
|
continue; |
|
|
|
|
|
|
@@ -216,6 +221,7 @@ static int sleep_until_start_request_or_inactivity() |
|
|
|
if (err == 0) |
|
|
|
a_start_is_required = 1; |
|
|
|
} |
|
|
|
pthread_mutex_unlock(&my_mutex); |
|
|
|
return a_start_is_required; |
|
|
|
} |
|
|
|
|
|
|
@@ -245,9 +251,17 @@ static espeak_ng_STATUS close_stream() |
|
|
|
|
|
|
|
if (a_stop_is_required) { |
|
|
|
// acknowledge the stop request |
|
|
|
a_status = sem_post(&my_sem_stop_is_acknowledged); |
|
|
|
if((a_status = pthread_mutex_lock(&my_mutex)) != ENS_OK) |
|
|
|
return a_status; |
|
|
|
|
|
|
|
my_stop_is_acknowledged = 1; |
|
|
|
a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged); |
|
|
|
if(a_status != ENS_OK) |
|
|
|
return a_status; |
|
|
|
a_status = pthread_mutex_unlock(&my_mutex); |
|
|
|
if (status == ENS_OK) |
|
|
|
status = a_status; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -259,7 +273,10 @@ static void *say_thread(void *p) |
|
|
|
(void)p; // unused |
|
|
|
|
|
|
|
// announce that thread is started |
|
|
|
sem_post(&my_sem_stop_is_acknowledged); |
|
|
|
assert(-1 != pthread_mutex_lock(&my_mutex)); |
|
|
|
my_stop_is_acknowledged = 1; |
|
|
|
assert(-1 != pthread_cond_signal(&my_cond_stop_is_acknowledged)); |
|
|
|
assert(-1 != pthread_mutex_unlock(&my_mutex)); |
|
|
|
|
|
|
|
int look_for_inactivity = 0; |
|
|
|
|
|
|
@@ -272,13 +289,20 @@ static void *say_thread(void *p) |
|
|
|
} |
|
|
|
look_for_inactivity = 1; |
|
|
|
|
|
|
|
int a_status = pthread_mutex_lock(&my_mutex); |
|
|
|
assert(!a_status); |
|
|
|
|
|
|
|
if (!a_start_is_required) { |
|
|
|
while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR) |
|
|
|
while ((my_start_is_required == 0) || ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR)) |
|
|
|
continue; // Restart when interrupted by handler |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
my_command_is_running = 1; |
|
|
|
|
|
|
|
assert(-1 != pthread_cond_broadcast(&my_cond_command_is_running)); |
|
|
|
assert(-1 != pthread_mutex_unlock(&my_mutex)); |
|
|
|
|
|
|
|
while (my_command_is_running) { |
|
|
|
int a_status = pthread_mutex_lock(&my_mutex); |
|
|
|
assert(!a_status); |
|
|
@@ -288,9 +312,7 @@ static void *say_thread(void *p) |
|
|
|
a_status = pthread_mutex_unlock(&my_mutex); |
|
|
|
my_command_is_running = 0; |
|
|
|
} else { |
|
|
|
// purge start semaphore |
|
|
|
while (0 == sem_trywait(&my_sem_start_is_required)) |
|
|
|
; |
|
|
|
my_start_is_required = 0; |
|
|
|
|
|
|
|
if (my_stop_is_required) |
|
|
|
my_command_is_running = 0; |
|
|
@@ -304,16 +326,18 @@ static void *say_thread(void *p) |
|
|
|
|
|
|
|
if (my_stop_is_required) { |
|
|
|
// no mutex required since the stop command is synchronous |
|
|
|
// and waiting for my_sem_stop_is_acknowledged |
|
|
|
// and waiting for my_cond_stop_is_acknowledged |
|
|
|
init(1); |
|
|
|
|
|
|
|
// purge start semaphore |
|
|
|
while (0 == sem_trywait(&my_sem_start_is_required)) |
|
|
|
; |
|
|
|
assert(-1 != pthread_mutex_lock(&my_mutex)); |
|
|
|
my_start_is_required = 0; |
|
|
|
|
|
|
|
// acknowledge the stop request |
|
|
|
int a_status = sem_post(&my_sem_stop_is_acknowledged); |
|
|
|
my_stop_is_acknowledged = 1; |
|
|
|
int a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged); |
|
|
|
assert(a_status != -1); |
|
|
|
pthread_mutex_unlock(&my_mutex); |
|
|
|
|
|
|
|
} |
|
|
|
// and wait for the next start |
|
|
|
} |
|
|
@@ -404,8 +428,8 @@ void fifo_terminate() |
|
|
|
pthread_cancel(my_thread); |
|
|
|
pthread_join(my_thread, NULL); |
|
|
|
pthread_mutex_destroy(&my_mutex); |
|
|
|
sem_destroy(&my_sem_start_is_required); |
|
|
|
sem_destroy(&my_sem_stop_is_acknowledged); |
|
|
|
pthread_cond_destroy(&my_cond_start_is_required); |
|
|
|
pthread_cond_destroy(&my_cond_stop_is_acknowledged); |
|
|
|
|
|
|
|
init(0); // purge fifo |
|
|
|
} |