mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-06 15:12:24 +00:00
Avoid using pthread_cancel
If a thread is cancelled while it holds a mutex, other threads waiting for the mutex will never be woken, even if destroying the mutex, thus leading to a deadlock. Better just make the thread loops have a proper exit case than risking the tricky semantic of pthread_cancel.
This commit is contained in:
@@ -43,6 +43,7 @@ static pthread_cond_t my_cond_stop_is_required;
|
|||||||
static bool my_stop_is_required = false;
|
static bool my_stop_is_required = false;
|
||||||
static pthread_cond_t my_cond_stop_is_acknowledged;
|
static pthread_cond_t my_cond_stop_is_acknowledged;
|
||||||
static bool my_stop_is_acknowledged = false;
|
static bool my_stop_is_acknowledged = false;
|
||||||
|
static bool my_terminate_is_required = 0;
|
||||||
// my_thread: polls the audio duration and compares it to the duration of the first event.
|
// my_thread: polls the audio duration and compares it to the duration of the first event.
|
||||||
static pthread_t my_thread;
|
static pthread_t my_thread;
|
||||||
static bool thread_inited;
|
static bool thread_inited;
|
||||||
@@ -253,13 +254,13 @@ static void *polling_thread(void *p)
|
|||||||
{
|
{
|
||||||
(void)p; // unused
|
(void)p; // unused
|
||||||
|
|
||||||
while (1) {
|
while (my_terminate_is_required) {
|
||||||
bool a_stop_is_required = false;
|
bool a_stop_is_required = false;
|
||||||
|
|
||||||
(void)pthread_mutex_lock(&my_mutex);
|
(void)pthread_mutex_lock(&my_mutex);
|
||||||
my_event_is_running = false;
|
my_event_is_running = false;
|
||||||
|
|
||||||
while (my_start_is_required == false) {
|
while (my_start_is_required == false && my_terminate_is_required == false) {
|
||||||
while ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR)
|
while ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR)
|
||||||
continue; // Restart when interrupted by handler
|
continue; // Restart when interrupted by handler
|
||||||
}
|
}
|
||||||
@@ -271,7 +272,7 @@ static void *polling_thread(void *p)
|
|||||||
pthread_mutex_unlock(&my_mutex);
|
pthread_mutex_unlock(&my_mutex);
|
||||||
|
|
||||||
// In this loop, my_event_is_running = true
|
// In this loop, my_event_is_running = true
|
||||||
while (head && (a_stop_is_required == false)) {
|
while (head && (a_stop_is_required == false) && (my_terminate_is_required == false)) {
|
||||||
espeak_EVENT *event = (espeak_EVENT *)(head->data);
|
espeak_EVENT *event = (espeak_EVENT *)(head->data);
|
||||||
assert(event);
|
assert(event);
|
||||||
|
|
||||||
@@ -304,7 +305,7 @@ static void *polling_thread(void *p)
|
|||||||
|
|
||||||
(void)pthread_mutex_unlock(&my_mutex);
|
(void)pthread_mutex_unlock(&my_mutex);
|
||||||
|
|
||||||
if (a_stop_is_required == true) {
|
if (a_stop_is_required == true || my_terminate_is_required == true) {
|
||||||
// no mutex required since the stop command is synchronous
|
// no mutex required since the stop command is synchronous
|
||||||
// and waiting for my_cond_stop_is_acknowledged
|
// and waiting for my_cond_stop_is_acknowledged
|
||||||
init();
|
init();
|
||||||
@@ -384,8 +385,12 @@ static void init()
|
|||||||
void event_terminate()
|
void event_terminate()
|
||||||
{
|
{
|
||||||
if (thread_inited) {
|
if (thread_inited) {
|
||||||
pthread_cancel(my_thread);
|
my_terminate_is_required = true;
|
||||||
|
pthread_cond_signal(&my_cond_start_is_required);
|
||||||
|
pthread_cond_signal(&my_cond_stop_is_required);
|
||||||
pthread_join(my_thread, NULL);
|
pthread_join(my_thread, NULL);
|
||||||
|
my_terminate_is_required = false;
|
||||||
|
|
||||||
pthread_mutex_destroy(&my_mutex);
|
pthread_mutex_destroy(&my_mutex);
|
||||||
pthread_cond_destroy(&my_cond_start_is_required);
|
pthread_cond_destroy(&my_cond_start_is_required);
|
||||||
pthread_cond_destroy(&my_cond_stop_is_required);
|
pthread_cond_destroy(&my_cond_stop_is_required);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ static pthread_mutex_t my_mutex;
|
|||||||
static bool my_command_is_running = false;
|
static bool my_command_is_running = false;
|
||||||
static pthread_cond_t my_cond_command_is_running;
|
static pthread_cond_t my_cond_command_is_running;
|
||||||
static bool my_stop_is_required = false;
|
static bool my_stop_is_required = false;
|
||||||
|
static bool my_terminate_is_required = 0;
|
||||||
|
|
||||||
// my_thread: reads commands from the fifo, and runs them.
|
// my_thread: reads commands from the fifo, and runs them.
|
||||||
static pthread_t my_thread;
|
static pthread_t my_thread;
|
||||||
@@ -290,7 +291,7 @@ static void *say_thread(void *p)
|
|||||||
|
|
||||||
bool look_for_inactivity = false;
|
bool look_for_inactivity = false;
|
||||||
|
|
||||||
while (1) {
|
while (!my_terminate_is_required) {
|
||||||
bool a_start_is_required = false;
|
bool a_start_is_required = false;
|
||||||
if (look_for_inactivity) {
|
if (look_for_inactivity) {
|
||||||
a_start_is_required = sleep_until_start_request_or_inactivity();
|
a_start_is_required = sleep_until_start_request_or_inactivity();
|
||||||
@@ -303,7 +304,7 @@ static void *say_thread(void *p)
|
|||||||
assert(!a_status);
|
assert(!a_status);
|
||||||
|
|
||||||
if (!a_start_is_required) {
|
if (!a_start_is_required) {
|
||||||
while (my_start_is_required == false) {
|
while (my_start_is_required == false && my_terminate_is_required == false) {
|
||||||
while ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR)
|
while ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR)
|
||||||
continue; // Restart when interrupted by handler
|
continue; // Restart when interrupted by handler
|
||||||
}
|
}
|
||||||
@@ -315,7 +316,7 @@ static void *say_thread(void *p)
|
|||||||
assert(-1 != pthread_cond_broadcast(&my_cond_command_is_running));
|
assert(-1 != pthread_cond_broadcast(&my_cond_command_is_running));
|
||||||
assert(-1 != pthread_mutex_unlock(&my_mutex));
|
assert(-1 != pthread_mutex_unlock(&my_mutex));
|
||||||
|
|
||||||
while (my_command_is_running) {
|
while (my_command_is_running && !my_terminate_is_required) {
|
||||||
int a_status = pthread_mutex_lock(&my_mutex);
|
int a_status = pthread_mutex_lock(&my_mutex);
|
||||||
assert(!a_status);
|
assert(!a_status);
|
||||||
t_espeak_command *a_command = (t_espeak_command *)pop();
|
t_espeak_command *a_command = (t_espeak_command *)pop();
|
||||||
@@ -336,7 +337,7 @@ static void *say_thread(void *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (my_stop_is_required) {
|
if (my_stop_is_required || my_terminate_is_required) {
|
||||||
// no mutex required since the stop command is synchronous
|
// no mutex required since the stop command is synchronous
|
||||||
// and waiting for my_cond_stop_is_acknowledged
|
// and waiting for my_cond_stop_is_acknowledged
|
||||||
init(1);
|
init(1);
|
||||||
@@ -437,8 +438,11 @@ static void init(int process_parameters)
|
|||||||
|
|
||||||
void fifo_terminate()
|
void fifo_terminate()
|
||||||
{
|
{
|
||||||
pthread_cancel(my_thread);
|
my_terminate_is_required = true;
|
||||||
|
pthread_cond_signal(&my_cond_start_is_required);
|
||||||
pthread_join(my_thread, NULL);
|
pthread_join(my_thread, NULL);
|
||||||
|
my_terminate_is_required = false;
|
||||||
|
|
||||||
pthread_mutex_destroy(&my_mutex);
|
pthread_mutex_destroy(&my_mutex);
|
||||||
pthread_cond_destroy(&my_cond_start_is_required);
|
pthread_cond_destroy(&my_cond_start_is_required);
|
||||||
pthread_cond_destroy(&my_cond_stop_is_acknowledged);
|
pthread_cond_destroy(&my_cond_stop_is_acknowledged);
|
||||||
|
|||||||
Reference in New Issue
Block a user