mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -05:00
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
This commit is contained in:
parent
6549e313ef
commit
c4fece74a5
1 changed files with 5 additions and 8 deletions
|
|
@ -86,13 +86,13 @@ struct queue {
|
||||||
|
|
||||||
#define QUEUE_FLAG_NONE (0)
|
#define QUEUE_FLAG_NONE (0)
|
||||||
#define QUEUE_FLAG_ACK_FD (1<<0)
|
#define QUEUE_FLAG_ACK_FD (1<<0)
|
||||||
|
#define QUEUE_FLAG_IN_TSS (1<<1)
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
struct queue *overflow;
|
struct queue *overflow;
|
||||||
|
|
||||||
int ack_fd;
|
int ack_fd;
|
||||||
struct spa_ratelimit rate_limit;
|
struct spa_ratelimit rate_limit;
|
||||||
bool destroyed;
|
bool destroyed;
|
||||||
bool in_tss;
|
|
||||||
|
|
||||||
struct spa_ringbuffer buffer;
|
struct spa_ringbuffer buffer;
|
||||||
uint8_t *buffer_data;
|
uint8_t *buffer_data;
|
||||||
|
|
@ -413,9 +413,7 @@ static void loop_queue_destroy(void *data)
|
||||||
struct queue *queue = data;
|
struct queue *queue = data;
|
||||||
struct impl *impl = queue->impl;
|
struct impl *impl = queue->impl;
|
||||||
|
|
||||||
if (!queue->destroyed) {
|
if (SPA_ATOMIC_CAS(queue->destroyed, false, true)) {
|
||||||
queue->destroyed = true;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&impl->queue_lock);
|
pthread_mutex_lock(&impl->queue_lock);
|
||||||
spa_list_remove(&queue->link);
|
spa_list_remove(&queue->link);
|
||||||
pthread_mutex_unlock(&impl->queue_lock);
|
pthread_mutex_unlock(&impl->queue_lock);
|
||||||
|
|
@ -426,7 +424,7 @@ static void loop_queue_destroy(void *data)
|
||||||
if (queue->flags & QUEUE_FLAG_ACK_FD)
|
if (queue->flags & QUEUE_FLAG_ACK_FD)
|
||||||
spa_system_close(impl->system, queue->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);
|
free(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -434,8 +432,8 @@ static void loop_queue_destroy_tss(void *data)
|
||||||
{
|
{
|
||||||
struct queue *queue = data;
|
struct queue *queue = data;
|
||||||
if (queue) {
|
if (queue) {
|
||||||
queue->in_tss = false;
|
|
||||||
loop_queue_destroy(queue);
|
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);
|
local_queue = tss_get(impl->queue_tss_id);
|
||||||
if (local_queue == NULL) {
|
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)
|
if (local_queue == NULL)
|
||||||
return -errno;
|
return -errno;
|
||||||
local_queue->in_tss = true;
|
|
||||||
tss_set(impl->queue_tss_id, local_queue);
|
tss_set(impl->queue_tss_id, local_queue);
|
||||||
}
|
}
|
||||||
return loop_queue_invoke(local_queue, func, seq, data, size, block, user_data);
|
return loop_queue_invoke(local_queue, func, seq, data, size, block, user_data);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue