pipewire: use lock for registry and init

Use a global lock to serialize concurrent pw_init calls.
Use a global lock to protect the global registry. With the alsa api,
multiple threads could open the device and create streams and
load/unload plugins.

See !942
This commit is contained in:
Wim Taymans 2021-09-21 10:28:17 +02:00
parent e8e7e72b76
commit 68f4dee2d9

View file

@ -81,17 +81,19 @@ struct support {
char **categories; char **categories;
const char *plugin_dir; const char *plugin_dir;
const char *support_lib; const char *support_lib;
struct registry *registry; struct registry registry;
char *i18n_domain; char *i18n_domain;
struct spa_interface i18n_iface; struct spa_interface i18n_iface;
struct spa_support support[MAX_SUPPORT]; struct spa_support support[MAX_SUPPORT];
uint32_t n_support; uint32_t n_support;
unsigned int initialized:1;
unsigned int in_valgrind:1; unsigned int in_valgrind:1;
unsigned int no_color:1; unsigned int no_color:1;
unsigned int no_config:1; unsigned int no_config:1;
}; };
static struct registry global_registry; static pthread_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t support_lock = PTHREAD_MUTEX_INITIALIZER;
static struct support global_support; static struct support global_support;
static struct plugin * static struct plugin *
@ -242,8 +244,7 @@ uint32_t pw_get_support(struct spa_support *support, uint32_t max_support)
return n; return n;
} }
SPA_EXPORT static struct spa_handle *load_spa_handle(const char *lib,
struct spa_handle *pw_load_spa_handle(const char *lib,
const char *factory_name, const char *factory_name,
const struct spa_dict *info, const struct spa_dict *info,
uint32_t n_support, uint32_t n_support,
@ -271,13 +272,15 @@ struct spa_handle *pw_load_spa_handle(const char *lib,
res = -ENOENT; res = -ENOENT;
while ((p = pw_split_walk(sup->plugin_dir, ":", &len, &state))) { while ((p = pw_split_walk(sup->plugin_dir, ":", &len, &state))) {
if ((plugin = open_plugin(sup->registry, p, len, lib)) != NULL) if ((plugin = open_plugin(&sup->registry, p, len, lib)) != NULL)
break; break;
res = -errno; res = -errno;
} }
if (plugin == NULL) if (plugin == NULL)
goto error_out; goto error_out;
pthread_mutex_unlock(&support_lock);
factory = find_factory(plugin, factory_name); factory = find_factory(plugin, factory_name);
if (factory == NULL) { if (factory == NULL) {
res = -errno; res = -errno;
@ -298,6 +301,7 @@ struct spa_handle *pw_load_spa_handle(const char *lib,
goto error_free_handle; goto error_free_handle;
} }
pthread_mutex_lock(&support_lock);
handle->ref = 1; handle->ref = 1;
handle->plugin = plugin; handle->plugin = plugin;
handle->factory_name = strdup(factory_name); handle->factory_name = strdup(factory_name);
@ -308,15 +312,30 @@ struct spa_handle *pw_load_spa_handle(const char *lib,
error_free_handle: error_free_handle:
free(handle); free(handle);
error_unref_plugin: error_unref_plugin:
pthread_mutex_lock(&support_lock);
unref_plugin(plugin); unref_plugin(plugin);
error_out: error_out:
errno = -res; errno = -res;
return NULL; return NULL;
} }
SPA_EXPORT
struct spa_handle *pw_load_spa_handle(const char *lib,
const char *factory_name,
const struct spa_dict *info,
uint32_t n_support,
const struct spa_support support[])
{
struct spa_handle *handle;
pthread_mutex_lock(&support_lock);
handle = load_spa_handle(lib, factory_name, info, n_support, support);
pthread_mutex_unlock(&support_lock);
return handle;
}
static struct handle *find_handle(struct spa_handle *handle) static struct handle *find_handle(struct spa_handle *handle)
{ {
struct registry *registry = global_support.registry; struct registry *registry = &global_support.registry;
struct plugin *p; struct plugin *p;
struct handle *h; struct handle *h;
@ -333,13 +352,16 @@ SPA_EXPORT
int pw_unload_spa_handle(struct spa_handle *handle) int pw_unload_spa_handle(struct spa_handle *handle)
{ {
struct handle *h; struct handle *h;
int res = 0;
pthread_mutex_lock(&support_lock);
if ((h = find_handle(handle)) == NULL) if ((h = find_handle(handle)) == NULL)
return -ENOENT; res = -ENOENT;
else
unref_handle(h);
pthread_mutex_unlock(&support_lock);
unref_handle(h); return res;
return 0;
} }
static void *add_interface(struct support *support, static void *add_interface(struct support *support,
@ -351,17 +373,24 @@ static void *add_interface(struct support *support,
void *iface = NULL; void *iface = NULL;
int res = -ENOENT; int res = -ENOENT;
handle = pw_load_spa_handle(support->support_lib, handle = load_spa_handle(support->support_lib,
factory_name, info, factory_name, info,
support->n_support, support->support); support->n_support, support->support);
if (handle == NULL)
return NULL;
if (handle == NULL || pthread_mutex_unlock(&support_lock);
(res = spa_handle_get_interface(handle, type, &iface)) < 0) { res = spa_handle_get_interface(handle, type, &iface);
pw_log_error("can't get %s interface %d", type, res); pthread_mutex_lock(&support_lock);
} else {
support->support[support->n_support++] = if (res < 0 || iface == NULL) {
SPA_SUPPORT_INIT(type, iface); pw_log_error("can't get %s interface %d: %s", type, res,
spa_strerror(res));
return NULL;
} }
support->support[support->n_support++] =
SPA_SUPPORT_INIT(type, iface);
return iface; return iface;
} }
@ -376,6 +405,7 @@ int pw_set_domain(const char *domain)
return -errno; return -errno;
return 0; return 0;
} }
SPA_EXPORT SPA_EXPORT
const char *pw_get_domain(void) const char *pw_get_domain(void)
{ {
@ -458,24 +488,30 @@ static struct spa_log *load_journal_logger(struct support *support)
items[0] = SPA_DICT_ITEM_INIT(SPA_KEY_LOG_LEVEL, level); items[0] = SPA_DICT_ITEM_INIT(SPA_KEY_LOG_LEVEL, level);
info = SPA_DICT_INIT(items, 1); info = SPA_DICT_INIT(items, 1);
handle = pw_load_spa_handle("support/libspa-journal", handle = load_spa_handle("support/libspa-journal",
SPA_NAME_SUPPORT_LOG, &info, SPA_NAME_SUPPORT_LOG, &info,
support->n_support, support->support); support->n_support, support->support);
if (handle == NULL)
return NULL;
if (handle == NULL || pthread_mutex_unlock(&support_lock);
(res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Log, &iface)) < 0) { res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Log, &iface);
pw_log_error("can't get log interface %d", res); pthread_mutex_lock(&support_lock);
} else {
/* look for an existing logger, and if (res < 0 || iface == NULL) {
* replace it with the journal logger */ pw_log_error("can't get log interface %d: %s", res,
for (i = 0; i < support->n_support; i++) { spa_strerror(res));
if (spa_streq(support->support[i].type, SPA_TYPE_INTERFACE_Log)) { return NULL;
support->support[i].data = iface;
break;
}
}
} }
/* look for an existing logger, and
* replace it with the journal logger */
for (i = 0; i < support->n_support; i++) {
if (spa_streq(support->support[i].type, SPA_TYPE_INTERFACE_Log)) {
support->support[i].data = iface;
break;
}
}
return (struct spa_log *) iface; return (struct spa_log *) iface;
} }
#endif #endif
@ -502,9 +538,11 @@ void pw_init(int *argc, char **argv[])
struct spa_log *log; struct spa_log *log;
char level[32]; char level[32];
if (support->registry != NULL) pthread_mutex_lock(&init_lock);
return; if (support->initialized)
goto done;
pthread_mutex_lock(&support_lock);
support->in_valgrind = RUNNING_ON_VALGRIND; support->in_valgrind = RUNNING_ON_VALGRIND;
if (getenv("NO_COLOR") != NULL) if (getenv("NO_COLOR") != NULL)
@ -526,8 +564,7 @@ void pw_init(int *argc, char **argv[])
str = SUPPORTLIB; str = SUPPORTLIB;
support->support_lib = str; support->support_lib = str;
spa_list_init(&global_registry.plugins); spa_list_init(&support->registry.plugins);
support->registry = &global_registry;
if (pw_log_is_default()) { if (pw_log_is_default()) {
n_items = 0; n_items = 0;
@ -569,15 +606,21 @@ void pw_init(int *argc, char **argv[])
add_i18n(support); add_i18n(support);
pw_log_info("version %s", pw_get_library_version()); pw_log_info("version %s", pw_get_library_version());
support->initialized = true;
pthread_mutex_unlock(&support_lock);
done:
pthread_mutex_unlock(&init_lock);
} }
SPA_EXPORT SPA_EXPORT
void pw_deinit(void) void pw_deinit(void)
{ {
struct support *support = &global_support; struct support *support = &global_support;
struct registry *registry = &global_registry; struct registry *registry = &support->registry;
struct plugin *p; struct plugin *p;
pthread_mutex_lock(&init_lock);
pthread_mutex_lock(&support_lock);
pw_log_set(NULL); pw_log_set(NULL);
spa_list_consume(p, &registry->plugins, link) { spa_list_consume(p, &registry->plugins, link) {
struct handle *h; struct handle *h;
@ -589,7 +632,8 @@ void pw_deinit(void)
pw_free_strv(support->categories); pw_free_strv(support->categories);
free(support->i18n_domain); free(support->i18n_domain);
spa_zero(global_support); spa_zero(global_support);
spa_zero(global_registry); pthread_mutex_unlock(&support_lock);
pthread_mutex_unlock(&init_lock);
} }