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;
const char *plugin_dir;
const char *support_lib;
struct registry *registry;
struct registry registry;
char *i18n_domain;
struct spa_interface i18n_iface;
struct spa_support support[MAX_SUPPORT];
uint32_t n_support;
unsigned int initialized:1;
unsigned int in_valgrind:1;
unsigned int no_color: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 plugin *
@ -242,8 +244,7 @@ uint32_t pw_get_support(struct spa_support *support, uint32_t max_support)
return n;
}
SPA_EXPORT
struct spa_handle *pw_load_spa_handle(const char *lib,
static struct spa_handle *load_spa_handle(const char *lib,
const char *factory_name,
const struct spa_dict *info,
uint32_t n_support,
@ -271,13 +272,15 @@ struct spa_handle *pw_load_spa_handle(const char *lib,
res = -ENOENT;
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;
res = -errno;
}
if (plugin == NULL)
goto error_out;
pthread_mutex_unlock(&support_lock);
factory = find_factory(plugin, factory_name);
if (factory == NULL) {
res = -errno;
@ -298,6 +301,7 @@ struct spa_handle *pw_load_spa_handle(const char *lib,
goto error_free_handle;
}
pthread_mutex_lock(&support_lock);
handle->ref = 1;
handle->plugin = plugin;
handle->factory_name = strdup(factory_name);
@ -308,15 +312,30 @@ struct spa_handle *pw_load_spa_handle(const char *lib,
error_free_handle:
free(handle);
error_unref_plugin:
pthread_mutex_lock(&support_lock);
unref_plugin(plugin);
error_out:
errno = -res;
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)
{
struct registry *registry = global_support.registry;
struct registry *registry = &global_support.registry;
struct plugin *p;
struct handle *h;
@ -333,13 +352,16 @@ SPA_EXPORT
int pw_unload_spa_handle(struct spa_handle *handle)
{
struct handle *h;
int res = 0;
pthread_mutex_lock(&support_lock);
if ((h = find_handle(handle)) == NULL)
return -ENOENT;
res = -ENOENT;
else
unref_handle(h);
pthread_mutex_unlock(&support_lock);
unref_handle(h);
return 0;
return res;
}
static void *add_interface(struct support *support,
@ -351,17 +373,24 @@ static void *add_interface(struct support *support,
void *iface = NULL;
int res = -ENOENT;
handle = pw_load_spa_handle(support->support_lib,
handle = load_spa_handle(support->support_lib,
factory_name, info,
support->n_support, support->support);
if (handle == NULL)
return NULL;
if (handle == NULL ||
(res = spa_handle_get_interface(handle, type, &iface)) < 0) {
pw_log_error("can't get %s interface %d", type, res);
} else {
support->support[support->n_support++] =
SPA_SUPPORT_INIT(type, iface);
pthread_mutex_unlock(&support_lock);
res = spa_handle_get_interface(handle, type, &iface);
pthread_mutex_lock(&support_lock);
if (res < 0 || iface == NULL) {
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;
}
@ -376,6 +405,7 @@ int pw_set_domain(const char *domain)
return -errno;
return 0;
}
SPA_EXPORT
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);
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,
support->n_support, support->support);
if (handle == NULL)
return NULL;
if (handle == NULL ||
(res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Log, &iface)) < 0) {
pw_log_error("can't get log interface %d", res);
} else {
/* 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;
}
}
pthread_mutex_unlock(&support_lock);
res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Log, &iface);
pthread_mutex_lock(&support_lock);
if (res < 0 || iface == NULL) {
pw_log_error("can't get log interface %d: %s", res,
spa_strerror(res));
return NULL;
}
/* 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;
}
#endif
@ -502,9 +538,11 @@ void pw_init(int *argc, char **argv[])
struct spa_log *log;
char level[32];
if (support->registry != NULL)
return;
pthread_mutex_lock(&init_lock);
if (support->initialized)
goto done;
pthread_mutex_lock(&support_lock);
support->in_valgrind = RUNNING_ON_VALGRIND;
if (getenv("NO_COLOR") != NULL)
@ -526,8 +564,7 @@ void pw_init(int *argc, char **argv[])
str = SUPPORTLIB;
support->support_lib = str;
spa_list_init(&global_registry.plugins);
support->registry = &global_registry;
spa_list_init(&support->registry.plugins);
if (pw_log_is_default()) {
n_items = 0;
@ -569,15 +606,21 @@ void pw_init(int *argc, char **argv[])
add_i18n(support);
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
void pw_deinit(void)
{
struct support *support = &global_support;
struct registry *registry = &global_registry;
struct registry *registry = &support->registry;
struct plugin *p;
pthread_mutex_lock(&init_lock);
pthread_mutex_lock(&support_lock);
pw_log_set(NULL);
spa_list_consume(p, &registry->plugins, link) {
struct handle *h;
@ -589,7 +632,8 @@ void pw_deinit(void)
pw_free_strv(support->categories);
free(support->i18n_domain);
spa_zero(global_support);
spa_zero(global_registry);
pthread_mutex_unlock(&support_lock);
pthread_mutex_unlock(&init_lock);
}