mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	jack: keep object cache
Keep per type free_lists so that we can't reuse an old port object for a link/node. This makes it more likely that ports are still available after being freed. Keep all allocated objects indexed in a global cache map. Use the global cache index as the jack_port_id_t in connection and port registration callbacks. Since the port_id is unique per allocated object and since the objects types are never changed, we can always find a port with the given port_id in the cache. This vastly improves tools like catia that insist on querying objects after they have been removed/destroyed.
This commit is contained in:
		
							parent
							
								
									c387e83c65
								
							
						
					
					
						commit
						2e87127700
					
				
					 1 changed files with 51 additions and 28 deletions
				
			
		| 
						 | 
					@ -99,8 +99,8 @@ struct globals {
 | 
				
			||||||
	jack_thread_creator_t creator;
 | 
						jack_thread_creator_t creator;
 | 
				
			||||||
	pthread_mutex_t lock;
 | 
						pthread_mutex_t lock;
 | 
				
			||||||
	struct pw_array descriptions;
 | 
						struct pw_array descriptions;
 | 
				
			||||||
	struct spa_list free_objects;
 | 
						struct spa_list free_objects[3];
 | 
				
			||||||
 | 
						struct pw_map cache;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct globals globals;
 | 
					static struct globals globals;
 | 
				
			||||||
| 
						 | 
					@ -117,12 +117,12 @@ struct object {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct client *client;
 | 
						struct client *client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define INTERFACE_Invalid	0
 | 
					#define INTERFACE_Port		0
 | 
				
			||||||
#define INTERFACE_Port		1
 | 
					#define INTERFACE_Node		1
 | 
				
			||||||
#define INTERFACE_Node		2
 | 
					#define INTERFACE_Link		2
 | 
				
			||||||
#define INTERFACE_Link		3
 | 
					 | 
				
			||||||
	uint32_t type;
 | 
						uint32_t type;
 | 
				
			||||||
	uint32_t id;
 | 
						uint32_t id;
 | 
				
			||||||
 | 
						uint32_t idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
| 
						 | 
					@ -137,6 +137,8 @@ struct object {
 | 
				
			||||||
			bool src_ours;
 | 
								bool src_ours;
 | 
				
			||||||
			bool dst_ours;
 | 
								bool dst_ours;
 | 
				
			||||||
			bool is_complete;
 | 
								bool is_complete;
 | 
				
			||||||
 | 
								uint32_t src_idx;
 | 
				
			||||||
 | 
								uint32_t dst_idx;
 | 
				
			||||||
		} port_link;
 | 
							} port_link;
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
			unsigned long flags;
 | 
								unsigned long flags;
 | 
				
			||||||
| 
						 | 
					@ -415,22 +417,35 @@ static void init_port_pool(struct client *c, enum spa_direction direction)
 | 
				
			||||||
	c->n_port_pool[direction] = 0;
 | 
						c->n_port_pool[direction] = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct object * find_cache(uint32_t type, uint32_t idx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct object *o;
 | 
				
			||||||
 | 
						pthread_mutex_lock(&globals.lock);
 | 
				
			||||||
 | 
						o = pw_map_lookup(&globals.cache, idx);
 | 
				
			||||||
 | 
						if (o != NULL && o->type != type)
 | 
				
			||||||
 | 
							o = NULL;
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
 | 
						return o;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct object * alloc_object(struct client *c, int type)
 | 
					static struct object * alloc_object(struct client *c, int type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct object *o;
 | 
						struct object *o;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_lock(&globals.lock);
 | 
						pthread_mutex_lock(&globals.lock);
 | 
				
			||||||
	if (spa_list_is_empty(&globals.free_objects)) {
 | 
						if (spa_list_is_empty(&globals.free_objects[type])) {
 | 
				
			||||||
		o = calloc(OBJECT_CHUNK, sizeof(struct object));
 | 
							o = calloc(OBJECT_CHUNK, sizeof(struct object));
 | 
				
			||||||
		if (o == NULL) {
 | 
							if (o == NULL) {
 | 
				
			||||||
			pthread_mutex_unlock(&globals.lock);
 | 
								pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for (i = 0; i < OBJECT_CHUNK; i++)
 | 
							for (i = 0; i < OBJECT_CHUNK; i++) {
 | 
				
			||||||
			spa_list_append(&globals.free_objects, &o[i].link);
 | 
								o[i].idx = pw_map_insert_new(&globals.cache, &o[i]);
 | 
				
			||||||
 | 
								spa_list_append(&globals.free_objects[type], &o[i].link);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	o = spa_list_first(&globals.free_objects, struct object, link);
 | 
						}
 | 
				
			||||||
 | 
						o = spa_list_first(&globals.free_objects[type], struct object, link);
 | 
				
			||||||
	spa_list_remove(&o->link);
 | 
						spa_list_remove(&o->link);
 | 
				
			||||||
	pthread_mutex_unlock(&globals.lock);
 | 
						pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -450,7 +465,7 @@ static void free_object(struct client *c, struct object *o)
 | 
				
			||||||
	pw_log_debug("%p: object:%p type:%d", c, o, o->type);
 | 
						pw_log_debug("%p: object:%p type:%d", c, o, o->type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_lock(&globals.lock);
 | 
						pthread_mutex_lock(&globals.lock);
 | 
				
			||||||
	spa_list_append(&globals.free_objects, &o->link);
 | 
						spa_list_append(&globals.free_objects[o->type], &o->link);
 | 
				
			||||||
	o->client = NULL;
 | 
						o->client = NULL;
 | 
				
			||||||
	pthread_mutex_unlock(&globals.lock);
 | 
						pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2364,8 +2379,11 @@ static int client_node_port_set_mix_info(void *object,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((l = find_link(c, src, dst)) != NULL && !l->port_link.is_complete) {
 | 
						if ((l = find_link(c, src, dst)) != NULL && !l->port_link.is_complete) {
 | 
				
			||||||
		l->port_link.is_complete = true;
 | 
							l->port_link.is_complete = true;
 | 
				
			||||||
		pw_log_info("%p: our link %d -> %d completed", c, src, dst);
 | 
							pw_log_info("%p: our link %d/%u -> %d/%u completed", c,
 | 
				
			||||||
		do_callback(c, connect_callback, src, dst, 1, c->connect_arg);
 | 
									l->port_link.src, l->port_link.src_idx,
 | 
				
			||||||
 | 
									l->port_link.dst, l->port_link.dst_idx);
 | 
				
			||||||
 | 
							do_callback(c, connect_callback,
 | 
				
			||||||
 | 
									l->port_link.src_idx, l->port_link.dst_idx, 1, c->connect_arg);
 | 
				
			||||||
		do_callback(c, graph_callback, c->graph_arg);
 | 
							do_callback(c, graph_callback, c->graph_arg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2784,6 +2802,7 @@ static void registry_event_global(void *data, uint32_t id,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((p = find_type(c, o->port_link.src, INTERFACE_Port, true)) == NULL)
 | 
							if ((p = find_type(c, o->port_link.src, INTERFACE_Port, true)) == NULL)
 | 
				
			||||||
			goto exit_free;
 | 
								goto exit_free;
 | 
				
			||||||
 | 
							o->port_link.src_idx = p->idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		o->port_link.src_ours = p->port.port != NULL &&
 | 
							o->port_link.src_ours = p->port.port != NULL &&
 | 
				
			||||||
			p->port.port->client == c;
 | 
								p->port.port->client == c;
 | 
				
			||||||
| 
						 | 
					@ -2795,6 +2814,7 @@ static void registry_event_global(void *data, uint32_t id,
 | 
				
			||||||
		if ((p = find_type(c, o->port_link.dst, INTERFACE_Port, true)) == NULL)
 | 
							if ((p = find_type(c, o->port_link.dst, INTERFACE_Port, true)) == NULL)
 | 
				
			||||||
			goto exit_free;
 | 
								goto exit_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							o->port_link.dst_idx = p->idx;
 | 
				
			||||||
		o->port_link.dst_ours = p->port.port != NULL &&
 | 
							o->port_link.dst_ours = p->port.port != NULL &&
 | 
				
			||||||
			p->port.port->client == c;
 | 
								p->port.port->client == c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2848,18 +2868,20 @@ static void registry_event_global(void *data, uint32_t id,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case INTERFACE_Port:
 | 
						case INTERFACE_Port:
 | 
				
			||||||
		pw_log_info("%p: port added %d \"%s\"", c, o->id, o->port.name);
 | 
							pw_log_info("%p: port added %d/%d \"%s\"", c, o->id, o->idx, o->port.name);
 | 
				
			||||||
		do_callback(c, portregistration_callback,
 | 
							do_callback(c, portregistration_callback,
 | 
				
			||||||
				o->id, 1, c->portregistration_arg);
 | 
									o->idx, 1, c->portregistration_arg);
 | 
				
			||||||
		graph_changed = true;
 | 
							graph_changed = true;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case INTERFACE_Link:
 | 
						case INTERFACE_Link:
 | 
				
			||||||
		pw_log_info("%p: link %u %d -> %d added complete:%d", c, o->id,
 | 
							pw_log_info("%p: link %u/%u %d/%d -> %d/%d added complete:%d", c, o->id, o->idx,
 | 
				
			||||||
				o->port_link.src, o->port_link.dst, o->port_link.is_complete);
 | 
									o->port_link.src, o->port_link.src_idx,
 | 
				
			||||||
 | 
									o->port_link.dst, o->port_link.dst_idx,
 | 
				
			||||||
 | 
									o->port_link.is_complete);
 | 
				
			||||||
		if (o->port_link.is_complete) {
 | 
							if (o->port_link.is_complete) {
 | 
				
			||||||
			do_callback(c, connect_callback,
 | 
								do_callback(c, connect_callback,
 | 
				
			||||||
					o->port_link.src, o->port_link.dst, 1, c->connect_arg);
 | 
										o->port_link.src_idx, o->port_link.dst_idx, 1, c->connect_arg);
 | 
				
			||||||
			graph_changed = true;
 | 
								graph_changed = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -2907,20 +2929,21 @@ static void registry_event_global_remove(void *object, uint32_t id)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case INTERFACE_Port:
 | 
						case INTERFACE_Port:
 | 
				
			||||||
		pw_log_info("%p: port %u removed \"%s\"", c, o->id, o->port.name);
 | 
							pw_log_info("%p: port %u/%u removed \"%s\"", c, o->id, o->idx, o->port.name);
 | 
				
			||||||
		do_callback(c, portregistration_callback,
 | 
							do_callback(c, portregistration_callback,
 | 
				
			||||||
				o->id, 0, c->portregistration_arg);
 | 
									o->idx, 0, c->portregistration_arg);
 | 
				
			||||||
		graph_changed = true;
 | 
							graph_changed = true;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case INTERFACE_Link:
 | 
						case INTERFACE_Link:
 | 
				
			||||||
		if (o->port_link.is_complete &&
 | 
							if (o->port_link.is_complete &&
 | 
				
			||||||
		    find_type(c, o->port_link.src, INTERFACE_Port, true) != NULL &&
 | 
							    find_type(c, o->port_link.src, INTERFACE_Port, true) != NULL &&
 | 
				
			||||||
		    find_type(c, o->port_link.dst, INTERFACE_Port, true) != NULL) {
 | 
							    find_type(c, o->port_link.dst, INTERFACE_Port, true) != NULL) {
 | 
				
			||||||
			pw_log_info("%p: link %u %d -> %d removed", c, o->id,
 | 
								pw_log_info("%p: link %u/%u %d/%u -> %d/%u removed", c, o->id, o->idx,
 | 
				
			||||||
					o->port_link.src, o->port_link.dst);
 | 
										o->port_link.src, o->port_link.src_idx,
 | 
				
			||||||
 | 
										o->port_link.dst, o->port_link.dst_idx);
 | 
				
			||||||
			o->port_link.is_complete = false;
 | 
								o->port_link.is_complete = false;
 | 
				
			||||||
			do_callback(c, connect_callback,
 | 
								do_callback(c, connect_callback,
 | 
				
			||||||
					o->port_link.src, o->port_link.dst, 0, c->connect_arg);
 | 
										o->port_link.src_idx, o->port_link.dst_idx, 0, c->connect_arg);
 | 
				
			||||||
			graph_changed = true;
 | 
								graph_changed = true;
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			pw_log_warn("unlink between unknown ports %d and %d",
 | 
								pw_log_warn("unlink between unknown ports %d and %d",
 | 
				
			||||||
| 
						 | 
					@ -5201,13 +5224,10 @@ jack_port_t * jack_port_by_id (jack_client_t *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_return_val_if_fail(c != NULL, NULL);
 | 
						spa_return_val_if_fail(c != NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_lock(&c->context.lock);
 | 
						res = find_cache(INTERFACE_Port, port_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = find_type(c, port_id, INTERFACE_Port, false);
 | 
					 | 
				
			||||||
	pw_log_debug("%p: port %d -> %p", c, port_id, res);
 | 
						pw_log_debug("%p: port %d -> %p", c, port_id, res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_unlock(&c->context.lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (res == NULL)
 | 
						if (res == NULL)
 | 
				
			||||||
		pw_log_info("%p: port %d not found", c, port_id);
 | 
							pw_log_info("%p: port %d not found", c, port_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6010,5 +6030,8 @@ static void reg(void)
 | 
				
			||||||
	PW_LOG_TOPIC_INIT(jack_log_topic);
 | 
						PW_LOG_TOPIC_INIT(jack_log_topic);
 | 
				
			||||||
	pthread_mutex_init(&globals.lock, NULL);
 | 
						pthread_mutex_init(&globals.lock, NULL);
 | 
				
			||||||
	pw_array_init(&globals.descriptions, 16);
 | 
						pw_array_init(&globals.descriptions, 16);
 | 
				
			||||||
	spa_list_init(&globals.free_objects);
 | 
						spa_list_init(&globals.free_objects[INTERFACE_Port]);
 | 
				
			||||||
 | 
						spa_list_init(&globals.free_objects[INTERFACE_Node]);
 | 
				
			||||||
 | 
						spa_list_init(&globals.free_objects[INTERFACE_Link]);
 | 
				
			||||||
 | 
						pw_map_init(&globals.cache, 64, 64);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue