mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
jack: use a separate thread for notify
Some jack clients will take a lock before doing IPC and then will take the same lock in a notify callback. This prevents the IPC from progressing and causes a deadlock. Make a separate thread to dispatch the notify so that we don't block the IPC in any case. Fixes #3585
This commit is contained in:
parent
40cc2f7068
commit
69d0f586b2
1 changed files with 27 additions and 14 deletions
|
|
@ -273,6 +273,8 @@ struct context {
|
|||
struct pw_loop *l;
|
||||
struct pw_thread_loop *loop; /* thread_lock protects all below */
|
||||
struct pw_context *context;
|
||||
struct pw_loop *nl;
|
||||
struct pw_thread_loop *notify;
|
||||
|
||||
struct spa_thread_utils *old_thread_utils;
|
||||
struct spa_thread_utils thread_utils;
|
||||
|
|
@ -952,7 +954,7 @@ jack_get_version_string(void)
|
|||
#define check_callbacks(c) \
|
||||
({ \
|
||||
if ((c)->frozen_callbacks == 0 && (c)->pending_callbacks) \
|
||||
pw_loop_signal_event((c)->context.l, (c)->notify_source); \
|
||||
pw_loop_signal_event((c)->context.nl, (c)->notify_source); \
|
||||
})
|
||||
#define thaw_callbacks(c) \
|
||||
({ \
|
||||
|
|
@ -960,16 +962,18 @@ jack_get_version_string(void)
|
|||
check_callbacks(c); \
|
||||
})
|
||||
|
||||
static void emit_callbacks(struct client *c)
|
||||
static void on_notify_event(void *data, uint64_t count)
|
||||
{
|
||||
struct client *c = data;
|
||||
struct object *o;
|
||||
int32_t avail;
|
||||
uint32_t index;
|
||||
struct notify *notify;
|
||||
bool do_graph = false, do_recompute_capture = false, do_recompute_playback = false;
|
||||
|
||||
pw_thread_loop_lock(c->context.loop);
|
||||
if (c->frozen_callbacks != 0 || !c->pending_callbacks)
|
||||
return;
|
||||
goto done;
|
||||
|
||||
pw_log_debug("%p: enter active:%u", c, c->active);
|
||||
|
||||
|
|
@ -1085,7 +1089,9 @@ static void emit_callbacks(struct client *c)
|
|||
do_callback(c, graph_callback, c->active, c->graph_arg);
|
||||
|
||||
thaw_callbacks(c);
|
||||
done:
|
||||
pw_log_debug("%p: leave", c);
|
||||
pw_thread_loop_unlock(c->context.loop);
|
||||
}
|
||||
|
||||
static int queue_notify(struct client *c, int type, struct object *o, int arg1, const char *msg)
|
||||
|
|
@ -1175,12 +1181,6 @@ done:
|
|||
return res;
|
||||
}
|
||||
|
||||
static void on_notify_event(void *data, uint64_t count)
|
||||
{
|
||||
struct client *c = data;
|
||||
emit_callbacks(c);
|
||||
}
|
||||
|
||||
static void on_sync_reply(void *data, uint32_t id, int seq)
|
||||
{
|
||||
struct client *client = data;
|
||||
|
|
@ -3603,7 +3603,6 @@ static void registry_event_global(void *data, uint32_t id,
|
|||
queue_notify(c, NOTIFY_TYPE_CONNECT, o, 1, NULL);
|
||||
break;
|
||||
}
|
||||
emit_callbacks(c);
|
||||
|
||||
exit:
|
||||
return;
|
||||
|
|
@ -3661,7 +3660,6 @@ static void registry_event_global_remove(void *data, uint32_t id)
|
|||
}
|
||||
break;
|
||||
}
|
||||
emit_callbacks(c);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -3769,6 +3767,8 @@ jack_client_t * jack_client_open (const char *client_name,
|
|||
goto no_props;
|
||||
|
||||
client->context.loop = pw_thread_loop_new(client->name, NULL);
|
||||
if (client->context.loop == NULL)
|
||||
goto no_props;
|
||||
client->context.l = pw_thread_loop_get_loop(client->context.loop);
|
||||
client->context.context = pw_context_new(
|
||||
client->context.l,
|
||||
|
|
@ -3777,9 +3777,14 @@ jack_client_t * jack_client_open (const char *client_name,
|
|||
if (client->context.context == NULL)
|
||||
goto no_props;
|
||||
|
||||
client->context.notify = pw_thread_loop_new(client->name, NULL);
|
||||
if (client->context.notify == NULL)
|
||||
goto no_props;
|
||||
client->context.nl = pw_thread_loop_get_loop(client->context.notify);
|
||||
|
||||
client->max_frames = client->context.context->settings.clock_quantum_limit;
|
||||
|
||||
client->notify_source = pw_loop_add_event(client->context.l,
|
||||
client->notify_source = pw_loop_add_event(client->context.nl,
|
||||
on_notify_event, client);
|
||||
client->notify_buffer = calloc(1, NOTIFY_BUFFER_SIZE + sizeof(struct notify));
|
||||
spa_ringbuffer_init(&client->notify_ring);
|
||||
|
|
@ -3969,6 +3974,8 @@ jack_client_t * jack_client_open (const char *client_name,
|
|||
}
|
||||
pw_thread_loop_unlock(client->context.loop);
|
||||
|
||||
pw_thread_loop_start(client->context.notify);
|
||||
|
||||
pw_log_info("%p: opened", client);
|
||||
return (jack_client_t *)client;
|
||||
|
||||
|
|
@ -4026,10 +4033,14 @@ int jack_client_close (jack_client_t *client)
|
|||
clean_transport(c);
|
||||
|
||||
if (c->context.loop) {
|
||||
queue_notify(c, NOTIFY_TYPE_REGISTRATION, c->object, 0, NULL);
|
||||
pw_loop_invoke(c->context.l, NULL, 0, NULL, 0, false, c);
|
||||
pw_thread_loop_stop(c->context.loop);
|
||||
}
|
||||
if (c->context.notify) {
|
||||
queue_notify(c, NOTIFY_TYPE_REGISTRATION, c->object, 0, NULL);
|
||||
pw_loop_invoke(c->context.nl, NULL, 0, NULL, 0, false, c);
|
||||
pw_thread_loop_stop(c->context.notify);
|
||||
}
|
||||
|
||||
if (c->registry) {
|
||||
spa_hook_remove(&c->registry_listener);
|
||||
|
|
@ -4053,11 +4064,13 @@ int jack_client_close (jack_client_t *client)
|
|||
pw_context_destroy(c->context.context);
|
||||
|
||||
if (c->notify_source)
|
||||
pw_loop_destroy_source(c->context.l, c->notify_source);
|
||||
pw_loop_destroy_source(c->context.nl, c->notify_source);
|
||||
free(c->notify_buffer);
|
||||
|
||||
if (c->context.loop)
|
||||
pw_thread_loop_destroy(c->context.loop);
|
||||
if (c->context.notify)
|
||||
pw_thread_loop_destroy(c->context.notify);
|
||||
|
||||
pw_log_debug("%p: free", client);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue