mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	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:
		
							parent
							
								
									936c290cc1
								
							
						
					
					
						commit
						ee67ab9c04
					
				
					 2 changed files with 55 additions and 34 deletions
				
			
		| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,6 +119,7 @@ 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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -126,10 +128,10 @@ 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,6 +815,7 @@ 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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue