From c4fece74a583fe583c52576c1a83a7d1fe2cb6e4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 21 Oct 2024 16:45:17 +0200 Subject: [PATCH] loop: fix race in shutdown Make it possible to call loop_queue_destroy() from both the TSS destroy and impl_clear() without races. We make sure that only one can remove the queue from the queue list and cleanup. We also store the IN_TSS flag in the flags so that we can see them before the queue is added to the queue list. Only free the IN_TSS queue when the TSS destroy is called. See #4356 --- spa/plugins/support/loop.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index b2677635a..623d39a8f 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -86,13 +86,13 @@ struct queue { #define QUEUE_FLAG_NONE (0) #define QUEUE_FLAG_ACK_FD (1<<0) +#define QUEUE_FLAG_IN_TSS (1<<1) uint32_t flags; struct queue *overflow; int ack_fd; struct spa_ratelimit rate_limit; bool destroyed; - bool in_tss; struct spa_ringbuffer buffer; uint8_t *buffer_data; @@ -413,9 +413,7 @@ static void loop_queue_destroy(void *data) struct queue *queue = data; struct impl *impl = queue->impl; - if (!queue->destroyed) { - queue->destroyed = true; - + if (SPA_ATOMIC_CAS(queue->destroyed, false, true)) { pthread_mutex_lock(&impl->queue_lock); spa_list_remove(&queue->link); pthread_mutex_unlock(&impl->queue_lock); @@ -426,7 +424,7 @@ static void loop_queue_destroy(void *data) if (queue->flags & QUEUE_FLAG_ACK_FD) spa_system_close(impl->system, queue->ack_fd); } - if (!queue->in_tss) + if (!SPA_FLAG_IS_SET(queue->flags, QUEUE_FLAG_IN_TSS)) free(queue); } @@ -434,8 +432,8 @@ static void loop_queue_destroy_tss(void *data) { struct queue *queue = data; if (queue) { - queue->in_tss = false; loop_queue_destroy(queue); + free(queue); } } @@ -447,10 +445,9 @@ static int loop_invoke(void *object, spa_invoke_func_t func, uint32_t seq, local_queue = tss_get(impl->queue_tss_id); if (local_queue == NULL) { - local_queue = loop_create_queue(impl, QUEUE_FLAG_ACK_FD); + local_queue = loop_create_queue(impl, QUEUE_FLAG_ACK_FD | QUEUE_FLAG_IN_TSS); if (local_queue == NULL) return -errno; - local_queue->in_tss = true; tss_set(impl->queue_tss_id, local_queue); } return loop_queue_invoke(local_queue, func, seq, data, size, block, user_data);