From 3bdd2e01c56ec13179340ecdce0b766f72e4339e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 10 Dec 2022 00:40:21 +0100 Subject: [PATCH] pipewire: store SPA handles in a global list by age Operating on the assumption that every SPA handle can reference any other older SPA handle, the only safe destruction order is from youngest to oldest. To achieve this, store all handles across all plugins sorted by age (youngest first), and use that as the order of destruction in `pw_deinit()`. This line of thinking does not account for what happens when a handle that is referenced by others is unloaded, but it does not make that case worse either. See #2881 --- src/pipewire/pipewire.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index 255760c90..f0629927b 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -64,7 +64,6 @@ struct plugin { char *filename; void *hnd; spa_handle_factory_enum_func_t enum_func; - struct spa_list handles; int ref; }; @@ -78,6 +77,7 @@ struct handle { struct registry { struct spa_list plugins; + struct spa_list handles; /* all handles across all plugins by age (youngest first) */ }; struct support { @@ -149,7 +149,6 @@ open_plugin(struct registry *registry, plugin->filename = strdup(filename); plugin->hnd = hnd; plugin->enum_func = enum_func; - spa_list_init(&plugin->handles); spa_list_append(®istry->plugins, &plugin->link); @@ -290,7 +289,7 @@ static struct spa_handle *load_spa_handle(const char *lib, handle->ref = 1; handle->plugin = plugin; handle->factory_name = strdup(factory_name); - spa_list_append(&plugin->handles, &handle->link); + spa_list_prepend(&sup->registry.handles, &handle->link); return &handle->handle; @@ -321,15 +320,13 @@ struct spa_handle *pw_load_spa_handle(const char *lib, static struct handle *find_handle(struct spa_handle *handle) { struct registry *registry = &global_support.registry; - struct plugin *p; struct handle *h; - spa_list_for_each(p, ®istry->plugins, link) { - spa_list_for_each(h, &p->handles, link) { - if (&h->handle == handle) - return h; - } + spa_list_for_each(h, ®istry->handles, link) { + if (&h->handle == handle) + return h; } + return NULL; } @@ -611,6 +608,7 @@ void pw_init(int *argc, char **argv[]) support->support_lib = str; spa_list_init(&support->registry.plugins); + spa_list_init(&support->registry.handles); if (pw_log_is_default()) { char *patterns = NULL; @@ -684,7 +682,7 @@ void pw_deinit(void) { struct support *support = &global_support; struct registry *registry = &support->registry; - struct plugin *p; + struct handle *h; pthread_mutex_lock(&init_lock); if (support->init_count == 0) @@ -694,13 +692,10 @@ void pw_deinit(void) pthread_mutex_lock(&support_lock); pw_log_set(NULL); - spa_list_consume(p, ®istry->plugins, link) { - struct handle *h; - p->ref++; - spa_list_consume(h, &p->handles, link) - unref_handle(h); - unref_plugin(p); - } + + spa_list_consume(h, ®istry->handles, link) + unref_handle(h); + pw_free_strv(support->categories); free(support->i18n_domain); spa_zero(global_support);