From e76351da79b1f15769f6e8033582eebfde32f9ed Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 2 Mar 2020 15:44:47 +0100 Subject: [PATCH] data-loop: add option to pthread_cancel the thread Don't use pthread_cancel by default to stop the data thread but instead use an eventfd. pthread_cancel uses a signal and is not nice to use in a library as it can cause strange crashes. See #211 --- src/pipewire/data-loop.c | 32 ++++++++++++++++++++++++++++++-- src/pipewire/private.h | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/pipewire/data-loop.c b/src/pipewire/data-loop.c index 26c83ce9d..a3c01e0d9 100644 --- a/src/pipewire/data-loop.c +++ b/src/pipewire/data-loop.c @@ -86,9 +86,17 @@ static void *do_loop(void *user_data) return NULL; } +static void do_stop(void *data, uint64_t count) +{ + struct pw_data_loop *this = data; + pw_log_debug(NAME" %p: stopping", this); + this->running = false; +} + static struct pw_data_loop *loop_new(struct pw_loop *loop, const struct spa_dict *props) { struct pw_data_loop *this; + const char *str; int res; this = calloc(1, sizeof(struct pw_data_loop)); @@ -110,10 +118,23 @@ static struct pw_data_loop *loop_new(struct pw_loop *loop, const struct spa_dict } this->loop = loop; + if (props == NULL || + (str = spa_dict_lookup(props, "loop.cancel")) == NULL || + pw_properties_parse_bool(str) == false) { + this->event = pw_loop_add_event(this->loop, do_stop, this); + if (this->event == NULL) { + res = -errno; + pw_log_error(NAME" %p: can't add event: %m", this); + goto error_loop_destroy; + } + } spa_hook_list_init(&this->listener_list); return this; +error_loop_destroy: + if (this->created && this->loop) + pw_loop_destroy(this->loop); error_free: free(this); error_cleanup: @@ -146,6 +167,8 @@ void pw_data_loop_destroy(struct pw_data_loop *loop) pw_data_loop_stop(loop); + if (loop->event) + pw_loop_destroy_source(loop->loop, loop->event); if (loop->created) pw_loop_destroy(loop->loop); free(loop); @@ -203,8 +226,13 @@ int pw_data_loop_stop(struct pw_data_loop *loop) { pw_log_debug(NAME": %p stopping", loop); if (loop->running) { - pw_log_debug(NAME": %p cancel", loop); - pthread_cancel(loop->thread); + if (loop->event) { + pw_log_debug(NAME": %p signal", loop); + pw_loop_signal_event(loop->loop, loop->event); + } else { + pw_log_debug(NAME": %p cancel", loop); + pthread_cancel(loop->thread); + } pw_log_debug(NAME": %p join", loop); pthread_join(loop->thread, NULL); pw_log_debug(NAME": %p joined", loop); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 083c8a537..2bff0494c 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -316,6 +316,7 @@ struct pw_data_loop { struct pw_loop *loop; struct spa_hook_list listener_list; + struct spa_source *event; pthread_t thread; unsigned int created:1;