mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-07-03 07:58:41 +00:00
jack: don't call free_link from the data thread
We are not allowed to call free_link from the data thread because it does free() and some pw_mem calls which should only be called from the main thread. To solve this, pause the core, queue a free_link operation on the data thread, which will be scheduled after the previous remove_link operation completes, free the link and then resume the core. Blocking and resuming the core is necessary because we can't block for completion of the invoke calls (the jack method is not allowed to block) and we must ensure that nothing can happen with the memory (like reuse the mem_id) before we have cleaned it up. Fixes a crash in jack with create/destroy link stress.
This commit is contained in:
parent
cdfe95c091
commit
b0ce5d0dd8
|
@ -2897,6 +2897,16 @@ do_queue_memmap_free(struct spa_loop *loop,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void queue_memmap_free(struct client *c, struct pw_memmap *mem)
|
||||
{
|
||||
if (mem != NULL) {
|
||||
mem->tag[0] = SPA_ID_INVALID;
|
||||
pw_core_set_paused(c->core, true);
|
||||
pw_data_loop_invoke(c->loop,
|
||||
do_queue_memmap_free, SPA_ID_INVALID, &mem, sizeof(&mem), false, c);
|
||||
}
|
||||
}
|
||||
|
||||
static int client_node_port_set_io(void *data,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id,
|
||||
|
@ -2947,17 +2957,13 @@ static int client_node_port_set_io(void *data,
|
|||
case SPA_IO_Buffers:
|
||||
case SPA_IO_AsyncBuffers:
|
||||
mix_set_io(mix, ptr, size);
|
||||
if (old != NULL) {
|
||||
old->tag[0] = SPA_ID_INVALID;
|
||||
pw_core_set_paused(c->core, true);
|
||||
pw_data_loop_invoke(c->loop,
|
||||
do_queue_memmap_free, SPA_ID_INVALID, &old, sizeof(&old), false, c);
|
||||
old = NULL;
|
||||
}
|
||||
queue_memmap_free(c, old);
|
||||
old = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit_free:
|
||||
pw_memmap_free(old);
|
||||
exit:
|
||||
|
@ -2994,10 +3000,36 @@ do_remove_link(struct spa_loop *loop,
|
|||
trigger = get_time_ns(c->l->system);
|
||||
deactivate_link(c, link, trigger);
|
||||
}
|
||||
free_link(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_free_link(struct spa_loop *loop,
|
||||
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
|
||||
{
|
||||
struct client *c = user_data;
|
||||
struct link *l = *((struct link **)data);
|
||||
free_link(l);
|
||||
pw_core_set_paused(c->core, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_queue_free_link(struct spa_loop *loop,
|
||||
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
|
||||
{
|
||||
struct client *c = user_data;
|
||||
pw_loop_invoke(c->context.l, do_free_link, 0, data, size, false, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void queue_free_link(struct client *c, struct link *l)
|
||||
{
|
||||
pw_core_set_paused(c->core, true);
|
||||
pw_data_loop_invoke(c->loop,
|
||||
do_queue_free_link, SPA_ID_INVALID, &l, sizeof(&l), false, c);
|
||||
}
|
||||
|
||||
static int client_node_set_activation(void *data,
|
||||
uint32_t node_id,
|
||||
int signalfd,
|
||||
|
@ -3060,6 +3092,7 @@ static int client_node_set_activation(void *data,
|
|||
|
||||
pw_data_loop_invoke(c->loop,
|
||||
do_remove_link, SPA_ID_INVALID, NULL, 0, false, link);
|
||||
queue_free_link(c, link);
|
||||
}
|
||||
|
||||
if (c->driver_id == node_id)
|
||||
|
|
Loading…
Reference in New Issue
Block a user