client-node: keep target links in list

Don't allocate the links in an array because they might be moved
when the array is resized. Instead just use calloc and add them
to a list.

Make sure we update the list used in the real-time thread from a
safe context.
This commit is contained in:
Wim Taymans 2020-02-07 16:45:58 +01:00
parent 936c290cc1
commit ee67ab9c04
2 changed files with 55 additions and 34 deletions

View file

@ -169,13 +169,6 @@ struct buffer {
uint32_t n_mem; uint32_t n_mem;
}; };
struct link {
uint32_t node_id;
struct pw_memmap *mem;
struct pw_node_activation *activation;
int signalfd;
};
struct mix { struct mix {
struct spa_list link; struct spa_list link;
struct spa_list port_link; struct spa_list port_link;
@ -209,6 +202,16 @@ struct port {
float empty[MAX_BUFFER_FRAMES + MAX_ALIGN]; float empty[MAX_BUFFER_FRAMES + MAX_ALIGN];
}; };
struct link {
struct spa_list link;
struct spa_list target_link;
struct client *client;
uint32_t node_id;
struct pw_memmap *mem;
struct pw_node_activation *activation;
int signalfd;
};
struct context { struct context {
struct pw_thread_loop *loop; struct pw_thread_loop *loop;
struct pw_context *context; struct pw_context *context;
@ -304,7 +307,7 @@ struct client {
struct spa_list ports[2]; struct spa_list ports[2];
struct spa_list free_ports[2]; struct spa_list free_ports[2];
struct pw_array links; struct spa_list links;
uint32_t driver_id; uint32_t driver_id;
struct pw_node_activation *driver_activation; struct pw_node_activation *driver_activation;
@ -312,6 +315,8 @@ struct client {
struct pw_node_activation *activation; struct pw_node_activation *activation;
uint32_t xrun_count; uint32_t xrun_count;
struct spa_list target_links;
unsigned int started:1; unsigned int started:1;
unsigned int active:1; unsigned int active:1;
unsigned int destroyed:1; unsigned int destroyed:1;
@ -624,11 +629,11 @@ static const struct pw_proxy_events proxy_events = {
.bound = on_node_bound, .bound = on_node_bound,
}; };
static struct link *find_activation(struct pw_array *links, uint32_t node_id) static struct link *find_activation(struct spa_list *links, uint32_t node_id)
{ {
struct link *l; struct link *l;
pw_array_for_each(l, links) { spa_list_for_each(l, links, link) {
if (l->node_id == node_id) if (l->node_id == node_id)
return l; return l;
} }
@ -1019,7 +1024,7 @@ static inline void signal_sync(struct client *c)
activation->finish_time = nsec; activation->finish_time = nsec;
cmd = 1; cmd = 1;
pw_array_for_each(l, &c->links) { spa_list_for_each(l, &c->target_links, target_link) {
struct pw_node_activation_state *state; struct pw_node_activation_state *state;
if (l->activation == NULL) if (l->activation == NULL)
@ -1098,10 +1103,11 @@ on_rtsocket_condition(void *data, int fd, uint32_t mask)
static void clear_link(struct client *c, struct link *link) static void clear_link(struct client *c, struct link *link)
{ {
link->node_id = SPA_ID_INVALID; spa_list_remove(&link->target_link);
link->activation = NULL;
pw_memmap_free(link->mem); pw_memmap_free(link->mem);
close(link->signalfd); close(link->signalfd);
spa_list_remove(&link->link);
free(link);
} }
static void clean_transport(struct client *c) static void clean_transport(struct client *c)
@ -1115,10 +1121,8 @@ static void clean_transport(struct client *c)
unhandle_socket(c); unhandle_socket(c);
pw_array_for_each(l, &c->links) spa_list_consume(l, &c->links, link)
if (l->node_id != SPA_ID_INVALID) clear_link(c, l);
clear_link(c, l);
pw_array_clear(&c->links);
c->has_transport = false; c->has_transport = false;
} }
@ -1700,6 +1704,17 @@ static int client_node_port_set_io(void *object,
return res; return res;
} }
static int
do_activate_link(struct spa_loop *loop,
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
{
struct link *link = user_data;
struct client *c = link->client;
pw_log_trace("link %p activate", link);
spa_list_append(&c->target_links, &link->target_link);
return 0;
}
static int client_node_set_activation(void *object, static int client_node_set_activation(void *object,
uint32_t node_id, uint32_t node_id,
int signalfd, int signalfd,
@ -1739,15 +1754,20 @@ static int client_node_set_activation(void *object,
mem_id, offset, size, ptr); mem_id, offset, size, ptr);
if (ptr) { if (ptr) {
link = pw_array_add(&c->links, sizeof(struct link)); link = calloc(1, sizeof(struct link));
if (link == NULL) { if (link == NULL) {
res = -errno; res = -errno;
goto exit; goto exit;
} }
link->client = c;
link->node_id = node_id; link->node_id = node_id;
link->mem = mm; link->mem = mm;
link->activation = ptr; link->activation = ptr;
link->signalfd = signalfd; link->signalfd = signalfd;
spa_list_append(&c->links, &link->link);
pw_loop_invoke(c->loop->loop,
do_activate_link, SPA_ID_INVALID, NULL, 0, false, link);
} }
else { else {
link = find_activation(&c->links, node_id); link = find_activation(&c->links, node_id);
@ -2141,7 +2161,8 @@ jack_client_t * jack_client_open (const char *client_name,
if (client->loop == NULL) if (client->loop == NULL)
goto init_failed; goto init_failed;
pw_array_init(&client->links, 64); spa_list_init(&client->links);
spa_list_init(&client->target_links);
client->buffer_frames = (uint32_t)-1; client->buffer_frames = (uint32_t)-1;
client->sample_rate = (uint32_t)-1; client->sample_rate = (uint32_t)-1;

View file

@ -89,10 +89,11 @@ struct node_data {
struct spa_io_position *position; struct spa_io_position *position;
struct pw_array links; struct spa_list links;
}; };
struct link { struct link {
struct spa_list link;
struct node_data *data; struct node_data *data;
struct pw_memmap *map; struct pw_memmap *map;
struct pw_node_target target; struct pw_node_target target;
@ -102,11 +103,11 @@ struct link {
/** \endcond */ /** \endcond */
static struct link *find_activation(struct pw_array *links, uint32_t node_id) static struct link *find_activation(struct spa_list *links, uint32_t node_id)
{ {
struct link *l; struct link *l;
pw_array_for_each(l, links) { spa_list_for_each(l, links, link) {
if (l->node_id == node_id) if (l->node_id == node_id)
return l; return l;
} }
@ -118,18 +119,19 @@ do_deactivate_link(struct spa_loop *loop,
bool async, uint32_t seq, const void *data, size_t size, void *user_data) bool async, uint32_t seq, const void *data, size_t size, void *user_data)
{ {
struct link *link = user_data; struct link *link = user_data;
pw_log_trace("link %p deactivate", link);
spa_list_remove(&link->target.link); spa_list_remove(&link->target.link);
return 0; return 0;
} }
static void clear_link(struct node_data *data, struct link *link) static void clear_link(struct node_data *data, struct link *link)
{ {
pw_loop_invoke(data->context->data_loop, pw_loop_invoke(data->context->data_loop,
do_deactivate_link, SPA_ID_INVALID, NULL, 0, true, link); do_deactivate_link, SPA_ID_INVALID, NULL, 0, true, link);
link->node_id = SPA_ID_INVALID;
link->target.activation = NULL;
pw_memmap_free(link->map); pw_memmap_free(link->map);
close(link->signalfd); close(link->signalfd);
spa_list_remove(&link->link);
free(link);
} }
static void clean_transport(struct node_data *data) static void clean_transport(struct node_data *data)
@ -141,11 +143,8 @@ static void clean_transport(struct node_data *data)
if (!data->have_transport) if (!data->have_transport)
return; return;
pw_array_for_each(l, &data->links) { spa_list_consume(l, &data->links, link)
if (l->node_id != SPA_ID_INVALID) clear_link(data, l);
clear_link(data, l);
}
pw_array_clear(&data->links);
while ((mm = pw_mempool_find_tag(data->pool, tag, sizeof(uint32_t))) != NULL) while ((mm = pw_mempool_find_tag(data->pool, tag, sizeof(uint32_t))) != NULL)
pw_memmap_free(mm); pw_memmap_free(mm);
@ -816,8 +815,9 @@ do_activate_link(struct spa_loop *loop,
{ {
struct link *link = user_data; struct link *link = user_data;
struct node_data *d = link->data; struct node_data *d = link->data;
pw_log_trace("link %p activate", link);
spa_list_append(&d->node->rt.target_list, &link->target.link); spa_list_append(&d->node->rt.target_list, &link->target.link);
return 0; return 0;
} }
static int static int
@ -860,7 +860,7 @@ client_node_set_activation(void *object,
if (ptr) { if (ptr) {
link = pw_array_add(&data->links, sizeof(struct link)); link = calloc(1, sizeof(struct link));
if (link == NULL) { if (link == NULL) {
res = -errno; res = -errno;
goto error_exit; goto error_exit;
@ -873,6 +873,7 @@ client_node_set_activation(void *object,
link->target.signal = link_signal_func; link->target.signal = link_signal_func;
link->target.data = link; link->target.data = link;
link->target.node = NULL; link->target.node = NULL;
spa_list_append(&data->links, &link->link);
pw_loop_invoke(data->context->data_loop, pw_loop_invoke(data->context->data_loop,
do_activate_link, SPA_ID_INVALID, NULL, 0, false, link); do_activate_link, SPA_ID_INVALID, NULL, 0, false, link);
@ -1170,8 +1171,7 @@ static struct pw_proxy *node_export(struct pw_core *core, void *object, bool do_
for (i = 0; i < MAX_MIX; i++) for (i = 0; i < MAX_MIX; i++)
spa_list_append(&data->free_mix, &data->mix_pool[i].link); spa_list_append(&data->free_mix, &data->mix_pool[i].link);
pw_array_init(&data->links, 64); spa_list_init(&data->links);
pw_array_ensure_size(&data->links, sizeof(struct link) * 64);
pw_proxy_add_listener(client_node, pw_proxy_add_listener(client_node,
&data->proxy_client_node_listener, &data->proxy_client_node_listener,