mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	jack: free ports and cached objects
Free the client ports when closing. Move the per client cached objects to the global cache. Free the per-client cached mix and ports. Add a destructor that frees the cached global objects.
This commit is contained in:
		
							parent
							
								
									18e1da54bd
								
							
						
					
					
						commit
						f759bb68f5
					
				
					 1 changed files with 64 additions and 8 deletions
				
			
		|  | @ -193,6 +193,7 @@ struct object { | ||||||
| 	unsigned int visible; | 	unsigned int visible; | ||||||
| 	unsigned int removing:1; | 	unsigned int removing:1; | ||||||
| 	unsigned int removed:1; | 	unsigned int removed:1; | ||||||
|  | 	unsigned int to_free:1; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct midi_buffer { | struct midi_buffer { | ||||||
|  | @ -240,9 +241,11 @@ struct mix { | ||||||
| 
 | 
 | ||||||
| 	struct spa_io_buffers *io[2]; | 	struct spa_io_buffers *io[2]; | ||||||
| 
 | 
 | ||||||
|  | 	struct spa_list queue; | ||||||
| 	struct buffer buffers[MAX_BUFFERS]; | 	struct buffer buffers[MAX_BUFFERS]; | ||||||
| 	uint32_t n_buffers; | 	uint32_t n_buffers; | ||||||
| 	struct spa_list queue; | 
 | ||||||
|  | 	unsigned int to_free:1; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct port { | struct port { | ||||||
|  | @ -273,6 +276,7 @@ struct port { | ||||||
| 
 | 
 | ||||||
| 	unsigned int empty_out:1; | 	unsigned int empty_out:1; | ||||||
| 	unsigned int zeroed:1; | 	unsigned int zeroed:1; | ||||||
|  | 	unsigned int to_free:1; | ||||||
| 
 | 
 | ||||||
| 	void *(*get_buffer) (struct port *p, jack_nframes_t frames); | 	void *(*get_buffer) (struct port *p, jack_nframes_t frames); | ||||||
| 
 | 
 | ||||||
|  | @ -517,6 +521,7 @@ static struct object * alloc_object(struct client *c, int type) | ||||||
| 			pthread_mutex_unlock(&globals.lock); | 			pthread_mutex_unlock(&globals.lock); | ||||||
| 			return NULL; | 			return NULL; | ||||||
| 		} | 		} | ||||||
|  | 		o[0].to_free = true; | ||||||
| 		for (i = 0; i < OBJECT_CHUNK; i++) | 		for (i = 0; i < OBJECT_CHUNK; i++) | ||||||
| 			spa_list_append(&globals.free_objects, &o[i].link); | 			spa_list_append(&globals.free_objects, &o[i].link); | ||||||
| 	} | 	} | ||||||
|  | @ -537,9 +542,10 @@ static void recycle_objects(struct client *c, uint32_t remain) | ||||||
| 	struct object *o, *t; | 	struct object *o, *t; | ||||||
| 	pthread_mutex_lock(&globals.lock); | 	pthread_mutex_lock(&globals.lock); | ||||||
| 	spa_list_for_each_safe(o, t, &c->context.objects, link) { | 	spa_list_for_each_safe(o, t, &c->context.objects, link) { | ||||||
|  | 		pw_log_debug("%p: recycle object:%p remived:%d type:%d id:%u/%u %u/%u", | ||||||
|  | 				c, o, o->removed, o->type, o->id, o->serial, | ||||||
|  | 				c->context.free_count, remain); | ||||||
| 		if (o->removed) { | 		if (o->removed) { | ||||||
| 			pw_log_debug("%p: recycle object:%p type:%d id:%u/%u", |  | ||||||
| 					c, o, o->type, o->id, o->serial); |  | ||||||
| 			spa_list_remove(&o->link); | 			spa_list_remove(&o->link); | ||||||
| 			memset(o, 0, sizeof(struct object)); | 			memset(o, 0, sizeof(struct object)); | ||||||
| 			spa_list_append(&globals.free_objects, &o->link); | 			spa_list_append(&globals.free_objects, &o->link); | ||||||
|  | @ -555,13 +561,14 @@ static void recycle_objects(struct client *c, uint32_t remain) | ||||||
|  * move it to the end of the queue. */ |  * move it to the end of the queue. */ | ||||||
| static void free_object(struct client *c, struct object *o) | 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 %u/%u", c, o, o->type, | ||||||
|  | 			c->context.free_count, RECYCLE_THRESHOLD); | ||||||
| 	pthread_mutex_lock(&c->context.lock); | 	pthread_mutex_lock(&c->context.lock); | ||||||
| 	spa_list_remove(&o->link); | 	spa_list_remove(&o->link); | ||||||
| 	o->removed = true; | 	o->removed = true; | ||||||
| 	o->id = SPA_ID_INVALID; | 	o->id = SPA_ID_INVALID; | ||||||
| 	spa_list_append(&c->context.objects, &o->link); | 	spa_list_append(&c->context.objects, &o->link); | ||||||
| 	if (++c->context.free_count > RECYCLE_THRESHOLD) | 	if (++c->context.free_count >= RECYCLE_THRESHOLD) | ||||||
| 		recycle_objects(c, RECYCLE_THRESHOLD / 2); | 		recycle_objects(c, RECYCLE_THRESHOLD / 2); | ||||||
| 	pthread_mutex_unlock(&c->context.lock); | 	pthread_mutex_unlock(&c->context.lock); | ||||||
| 
 | 
 | ||||||
|  | @ -678,6 +685,7 @@ static struct mix *create_mix(struct client *c, struct port *port, | ||||||
| 		mix = calloc(OBJECT_CHUNK, sizeof(struct mix)); | 		mix = calloc(OBJECT_CHUNK, sizeof(struct mix)); | ||||||
| 		if (mix == NULL) | 		if (mix == NULL) | ||||||
| 			return NULL; | 			return NULL; | ||||||
|  | 		mix[0].to_free = true; | ||||||
| 		for (i = 0; i < OBJECT_CHUNK; i++) | 		for (i = 0; i < OBJECT_CHUNK; i++) | ||||||
| 			spa_list_append(&c->free_mix, &mix[i].link); | 			spa_list_append(&c->free_mix, &mix[i].link); | ||||||
| 	} | 	} | ||||||
|  | @ -742,6 +750,7 @@ static struct port * alloc_port(struct client *c, enum spa_direction direction) | ||||||
| 		p = calloc(OBJECT_CHUNK, port_size); | 		p = calloc(OBJECT_CHUNK, port_size); | ||||||
| 		if (p == NULL) | 		if (p == NULL) | ||||||
| 			return NULL; | 			return NULL; | ||||||
|  | 		p[0].to_free = true; | ||||||
| 		for (i = 0; i < OBJECT_CHUNK; i++) { | 		for (i = 0; i < OBJECT_CHUNK; i++) { | ||||||
| 			struct port *t = SPA_PTROFF(p, port_size * i, struct port); | 			struct port *t = SPA_PTROFF(p, port_size * i, struct port); | ||||||
| 			spa_list_append(&c->free_ports, &t->link); | 			spa_list_append(&c->free_ports, &t->link); | ||||||
|  | @ -4487,6 +4496,9 @@ int jack_client_close (jack_client_t *client) | ||||||
| { | { | ||||||
| 	struct client *c = (struct client *) client; | 	struct client *c = (struct client *) client; | ||||||
| 	struct object *o; | 	struct object *o; | ||||||
|  | 	union pw_map_item *item; | ||||||
|  | 	struct mix *m, *tm; | ||||||
|  | 	struct port *p, *tp; | ||||||
| 	int res; | 	int res; | ||||||
| 
 | 
 | ||||||
| 	return_val_if_fail(c != NULL, -EINVAL); | 	return_val_if_fail(c != NULL, -EINVAL); | ||||||
|  | @ -4544,10 +4556,40 @@ int jack_client_close (jack_client_t *client) | ||||||
| 
 | 
 | ||||||
| 	pw_log_debug("%p: free", client); | 	pw_log_debug("%p: free", client); | ||||||
| 
 | 
 | ||||||
| 	spa_list_consume(o, &c->context.objects, link) | 	pw_array_for_each(item, &c->ports[SPA_DIRECTION_OUTPUT].items) { | ||||||
| 		free_object(c, o); |                 if (pw_map_item_is_free(item)) | ||||||
| 	recycle_objects(c, 0); | 			continue; | ||||||
|  | 		free_port(c, item->data, false); | ||||||
|  | 	} | ||||||
|  | 	pw_array_for_each(item, &c->ports[SPA_DIRECTION_INPUT].items) { | ||||||
|  |                 if (pw_map_item_is_free(item)) | ||||||
|  | 			continue; | ||||||
|  | 		free_port(c, item->data, false); | ||||||
|  | 	} | ||||||
|  | 	spa_list_consume(o, &c->context.objects, link) { | ||||||
|  | 		bool to_free = o->to_free; | ||||||
|  | 		spa_list_remove(&o->link); | ||||||
|  | 		memset(o, 0, sizeof(struct object)); | ||||||
|  | 		o->to_free = to_free; | ||||||
|  | 		spa_list_append(&globals.free_objects, &o->link); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	spa_list_for_each_safe(m, tm, &c->free_mix, link) { | ||||||
|  | 		if (!m->to_free) | ||||||
|  | 			spa_list_remove(&m->link); | ||||||
|  | 	} | ||||||
|  | 	spa_list_consume(m, &c->free_mix, link) { | ||||||
|  | 		spa_list_remove(&m->link); | ||||||
|  | 		free(m); | ||||||
|  | 	} | ||||||
|  | 	spa_list_for_each_safe(p, tp, &c->free_ports, link) { | ||||||
|  | 		if (!p->to_free) | ||||||
|  | 			spa_list_remove(&p->link); | ||||||
|  | 	} | ||||||
|  | 	spa_list_consume(p, &c->free_ports, link) { | ||||||
|  | 		spa_list_remove(&p->link); | ||||||
|  | 		free(p); | ||||||
|  | 	} | ||||||
| 	pw_map_clear(&c->ports[SPA_DIRECTION_INPUT]); | 	pw_map_clear(&c->ports[SPA_DIRECTION_INPUT]); | ||||||
| 	pw_map_clear(&c->ports[SPA_DIRECTION_OUTPUT]); | 	pw_map_clear(&c->ports[SPA_DIRECTION_OUTPUT]); | ||||||
| 
 | 
 | ||||||
|  | @ -7699,3 +7741,17 @@ static void reg(void) | ||||||
| 	pw_array_init(&globals.descriptions, 16); | 	pw_array_init(&globals.descriptions, 16); | ||||||
| 	spa_list_init(&globals.free_objects); | 	spa_list_init(&globals.free_objects); | ||||||
| } | } | ||||||
|  | static void unreg(void) __attribute__ ((destructor)); | ||||||
|  | static void unreg(void) | ||||||
|  | { | ||||||
|  | 	struct object *o, *to; | ||||||
|  | 	spa_list_for_each_safe(o, to, &globals.free_objects, link) { | ||||||
|  | 		if (!o->to_free) | ||||||
|  | 			spa_list_remove(&o->link); | ||||||
|  | 	} | ||||||
|  | 	spa_list_consume(o, &globals.free_objects, link) { | ||||||
|  | 		spa_list_remove(&o->link); | ||||||
|  | 		free(o); | ||||||
|  | 	} | ||||||
|  | 	pw_deinit(); | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Wim Taymans
						Wim Taymans