Browse Source

Use condition variables in event.c instead of semaphores.

master
Rui Batista 8 years ago
parent
commit
cc51af059f
1 changed files with 40 additions and 47 deletions
  1. 40
    47
      src/libespeak-ng/event.c

+ 40
- 47
src/libespeak-ng/event.c View File

#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <pthread.h> #include <pthread.h>
#include <semaphore.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>


// my_mutex: protects my_thread_is_talking, // my_mutex: protects my_thread_is_talking,
static pthread_mutex_t my_mutex; static pthread_mutex_t my_mutex;
static sem_t my_sem_start_is_required;
static sem_t my_sem_stop_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_required;
static int my_stop_is_required = 0;
static pthread_cond_t my_cond_stop_is_acknowledged;
static int my_stop_is_acknowledged = 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;
pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL); pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL);
init(); init();


assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));
assert(-1 != pthread_cond_init(&my_cond_start_is_required, NULL));
assert(-1 != pthread_cond_init(&my_cond_stop_is_required, NULL));
assert(-1 != pthread_cond_init(&my_cond_stop_is_acknowledged, NULL));


pthread_attr_t a_attrib; pthread_attr_t a_attrib;




espeak_ng_STATUS status; espeak_ng_STATUS status;
if ((status = pthread_mutex_lock(&my_mutex)) != ENS_OK) { if ((status = pthread_mutex_lock(&my_mutex)) != ENS_OK) {
sem_post(&my_sem_start_is_required);
my_start_is_required = 1;
return status; return status;
} }


if ((status = push(a_event)) != ENS_OK) { if ((status = push(a_event)) != ENS_OK) {
event_delete(a_event); event_delete(a_event);
pthread_mutex_unlock(&my_mutex); pthread_mutex_unlock(&my_mutex);
} else
} else {
my_start_is_required = 1;
pthread_cond_signal(&my_cond_start_is_required);
status = pthread_mutex_unlock(&my_mutex); status = pthread_mutex_unlock(&my_mutex);
}


sem_post(&my_sem_start_is_required);


return status; return status;
} }


int a_event_is_running = 0; int a_event_is_running = 0;
if (my_event_is_running) { if (my_event_is_running) {
sem_post(&my_sem_stop_is_required);
my_stop_is_required = 1;
pthread_cond_signal(&my_cond_stop_is_required);
a_event_is_running = 1; a_event_is_running = 1;
} else } else
init(); // clear pending events init(); // clear pending events
return status; return status;


if (a_event_is_running) { if (a_event_is_running) {
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
while(my_stop_is_acknowledged == 0)
while((pthread_cond_wait(&my_cond_stop_is_acknowledged, &my_mutex) == -1) && errno == EINTR)
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
} }




int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
my_event_is_running = 0; my_event_is_running = 0;
pthread_mutex_unlock(&my_mutex);


while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
while(my_start_is_required == 0)
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


a_status = pthread_mutex_lock(&my_mutex);
my_event_is_running = 1; my_event_is_running = 1;
pthread_mutex_unlock(&my_mutex);

a_stop_is_required = 0; a_stop_is_required = 0;
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); // NOTE: may set a_stop_is_required to -1
if ((a_status == 0) && (a_stop_is_required > 0)) {
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
a_stop_is_required = 0;
my_start_is_required = 0;

pthread_mutex_unlock(&my_mutex);


// In this loop, my_event_is_running = 1 // In this loop, my_event_is_running = 1
while (head && (a_stop_is_required <= 0)) {
while (0 == sem_trywait(&my_sem_start_is_required))
;
while (head && (a_stop_is_required == 0)) {


espeak_EVENT *event = (espeak_EVENT *)(head->data); espeak_EVENT *event = (espeak_EVENT *)(head->data);
assert(event); assert(event);


a_status = pthread_mutex_lock(&my_mutex); a_status = pthread_mutex_lock(&my_mutex);
event_delete((espeak_EVENT *)pop()); event_delete((espeak_EVENT *)pop());
a_status = pthread_mutex_unlock(&my_mutex);
a_stop_is_required = my_stop_is_required;
if(a_stop_is_required > 0)
my_stop_is_required = 0;


a_stop_is_required = 0;
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);

if ((a_status == 0) && (a_stop_is_required > 0)) {
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
a_stop_is_required = 0;
a_status = pthread_mutex_unlock(&my_mutex);
} }


a_status = pthread_mutex_lock(&my_mutex); a_status = pthread_mutex_lock(&my_mutex);


my_event_is_running = 0; my_event_is_running = 0;


if (a_stop_is_required <= 0) {
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);
if ((a_status == 0) && (a_stop_is_required > 0)) {
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
a_stop_is_required = 0;
if (a_stop_is_required == 0) {
a_stop_is_required = my_stop_is_required;
if (a_stop_is_required > 0)
my_stop_is_required = 0;
} }


a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);


if (a_stop_is_required > 0) { if (a_stop_is_required > 0) {
// no mutex required since the stop command is synchronous // 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(); init();


// acknowledge the stop request // acknowledge the stop request
a_status = sem_post(&my_sem_stop_is_acknowledged);
espeak_ng_STATUS a_status = pthread_mutex_lock(&my_mutex);
my_stop_is_acknowledged = 1;
a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged);
a_status = pthread_mutex_unlock(&my_mutex);
} }
} }


pthread_cancel(my_thread); pthread_cancel(my_thread);
pthread_join(my_thread, NULL); pthread_join(my_thread, NULL);
pthread_mutex_destroy(&my_mutex); pthread_mutex_destroy(&my_mutex);
sem_destroy(&my_sem_start_is_required);
sem_destroy(&my_sem_stop_is_required);
sem_destroy(&my_sem_stop_is_acknowledged);
pthread_cond_destroy(&my_cond_start_is_required);
pthread_cond_destroy(&my_cond_stop_is_required);
pthread_cond_destroy(&my_cond_stop_is_acknowledged);
init(); // purge event init(); // purge event
thread_inited = 0; thread_inited = 0;
} }

Loading…
Cancel
Save