diff --git a/daemon/aux.c b/daemon/aux.c index 552eacf7f..fd97d04e8 100644 --- a/daemon/aux.c +++ b/daemon/aux.c @@ -24,8 +24,10 @@ struct detach_thread { }; -mutex_t threads_to_join_lock = MUTEX_STATIC_INIT; -static GSList *threads_to_join; +static mutex_t threads_lists_lock = MUTEX_STATIC_INIT; +static GList *threads_to_join; +static GList *threads_running; +static cond_t threads_cond = COND_STATIC_INIT; @@ -119,31 +121,58 @@ void g_queue_clear(GQueue *q) { -void thread_join_me() { +static void thread_join_me() { pthread_t *me; me = g_slice_alloc(sizeof(*me)); *me = pthread_self(); - mutex_lock(&threads_to_join_lock); - threads_to_join = g_slist_prepend(threads_to_join, me); - mutex_unlock(&threads_to_join_lock); + mutex_lock(&threads_lists_lock); + threads_to_join = g_list_prepend(threads_to_join, me); + cond_broadcast(&threads_cond); + mutex_unlock(&threads_lists_lock); } -void threads_join_all() { +static gint thread_equal(gconstpointer a, gconstpointer b) { + const pthread_t *x = a, *y = b; + return !pthread_equal(*x, *y); +} + +void threads_join_all(int wait) { pthread_t *t; + GList *l; + + mutex_lock(&threads_lists_lock); + while (1) { + while (threads_to_join) { + t = threads_to_join->data; + pthread_join(*t, NULL); + threads_to_join = g_list_delete_link(threads_to_join, threads_to_join); + l = g_list_find_custom(threads_running, t, thread_equal); + if (l) + threads_running = g_list_delete_link(threads_running, l); + else + abort(); + g_slice_free1(sizeof(*t), t); + } - mutex_lock(&threads_to_join_lock); - while (threads_to_join) { - t = threads_to_join->data; - pthread_join(*t, NULL); - threads_to_join = g_slist_delete_link(threads_to_join, threads_to_join); - g_slice_free1(sizeof(*t), t); + if (!wait) + break; + if (!threads_running) + break; + cond_wait(&threads_cond, &threads_lists_lock); } - mutex_unlock(&threads_to_join_lock); + mutex_unlock(&threads_lists_lock); } -static gpointer thread_detach_func(gpointer d) { +static void *thread_detach_func(void *d) { struct detach_thread *dt = d; + pthread_t *t; + + t = g_slice_alloc(sizeof(*t)); + *t = pthread_self(); + mutex_lock(&threads_lists_lock); + threads_running = g_list_prepend(threads_running, t); + mutex_unlock(&threads_lists_lock); dt->func(dt->data); g_slice_free1(sizeof(*dt), dt); @@ -151,7 +180,7 @@ static gpointer thread_detach_func(gpointer d) { return NULL; } -int thread_create(void *(*func)(void *), void *arg, int joinable, pthread_t *handle) { +static int thread_create(void *(*func)(void *), void *arg, int joinable, pthread_t *handle) { pthread_attr_t att; pthread_t thr; int ret; @@ -162,9 +191,12 @@ int thread_create(void *(*func)(void *), void *arg, int joinable, pthread_t *han abort(); ret = pthread_create(&thr, &att, func, arg); pthread_attr_destroy(&att); - if (!ret && handle) + if (ret) + return ret; + if (handle) *handle = thr; - return ret; + + return 0; } void thread_create_detach(void (*f)(void *), void *d) { diff --git a/daemon/aux.h b/daemon/aux.h index faa5031ba..0128d52af 100644 --- a/daemon/aux.h +++ b/daemon/aux.h @@ -169,11 +169,10 @@ typedef pthread_cond_t cond_t; #define cond_wait(c,m) pthread_cond_wait(c,m) #define cond_signal(c) pthread_cond_signal(c) #define cond_broadcast(c) pthread_cond_broadcast(c) +#define COND_STATIC_INIT PTHREAD_COND_INITIALIZER -void thread_join_me(); -void threads_join_all(); -int thread_create(void *(*)(void *), void *, int, pthread_t *); +void threads_join_all(int); void thread_create_detach(void (*)(void *), void *); diff --git a/daemon/main.c b/daemon/main.c index 8ea7defb8..cac8a4bf2 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -431,10 +431,10 @@ int main(int argc, char **argv) { while (!global_shutdown) { usleep(100000); - threads_join_all(); + threads_join_all(0); } - threads_join_all(); + threads_join_all(1); mylog(LOG_INFO, "Version %s shutting down", MEDIAPROXY_VERSION);