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.master
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; | ||||
{ | { | ||||
(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 | ||||
} | } | ||||
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); | ||||
(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(); | ||||
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); |
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; | ||||
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(); | ||||
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 | ||||
} | } | ||||
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(); | ||||
} | } | ||||
} | } | ||||
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); | ||||
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); |