From 961d0cfdc16ef517b46ac00adadef58ce3bd6b8d Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Mon, 1 Jan 2024 21:11:18 +0200 Subject: [PATCH] log: make pw_log_topic_register/unregister threadsafe Make the topic registration/unregistration threadsafe, as they can be called from constructors of static objects which don't necessarily run in the main loop thread. --- src/pipewire/log.c | 29 +++++++++++++++++++++++++++-- src/pipewire/log.h | 3 ++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/pipewire/log.c b/src/pipewire/log.c index 4e92517af..a2ce73f9f 100644 --- a/src/pipewire/log.c +++ b/src/pipewire/log.c @@ -4,6 +4,7 @@ #include #include +#include #include @@ -43,6 +44,8 @@ struct pattern { static struct spa_list topics = SPA_LIST_INIT(&topics); static struct spa_list patterns = SPA_LIST_INIT(&patterns); +static pthread_mutex_t topics_lock = PTHREAD_MUTEX_INITIALIZER; + PW_LOG_TOPIC(log_buffers, "pw.buffers"); PW_LOG_TOPIC(log_client, "pw.client"); PW_LOG_TOPIC(log_conf, "pw.conf"); @@ -120,8 +123,12 @@ static void update_all_topic_levels(void) { struct topic *topic; + pthread_mutex_lock(&topics_lock); + spa_list_for_each(topic, &topics, link) update_topic_level(topic->t); + + pthread_mutex_unlock(&topics_lock); } SPA_EXPORT @@ -129,15 +136,20 @@ void pw_log_topic_register(struct spa_log_topic *t) { struct topic *topic; + pthread_mutex_lock(&topics_lock); + topic = find_topic(t); if (!topic) { update_topic_level(t); topic = add_topic(t); if (!topic) - return; + goto done; } ++topic->refcnt; + +done: + pthread_mutex_unlock(&topics_lock); } SPA_EXPORT @@ -145,14 +157,19 @@ void pw_log_topic_unregister(struct spa_log_topic *t) { struct topic *topic; + pthread_mutex_lock(&topics_lock); + topic = find_topic(t); if (!topic) - return; + goto done; if (topic->refcnt-- <= 1) { spa_list_remove(&topic->link); free(topic); } + +done: + pthread_mutex_unlock(&topics_lock); } void pw_log_topic_register_enum(const struct spa_log_topic_enum *e) @@ -313,6 +330,8 @@ int pw_log_set_level_string(const char *str) pw_log_level = level; global_log->level = level; + pthread_mutex_lock(&topics_lock); + spa_list_consume(pattern, &patterns, link) { spa_list_remove(&pattern->link); free(pattern); @@ -320,6 +339,8 @@ int pw_log_set_level_string(const char *str) spa_list_insert_list(&patterns, &new_patterns); + pthread_mutex_unlock(&topics_lock); + update_all_topic_levels(); return 0; } @@ -476,11 +497,15 @@ pw_log_deinit(void) { struct pattern *pattern; + pthread_mutex_lock(&topics_lock); + spa_list_consume(pattern, &patterns, link) { spa_list_remove(&pattern->link); free(pattern); } + pthread_mutex_unlock(&topics_lock); + /* don't free log topics, since they usually won't get re-registered */ pw_log_set(NULL); diff --git a/src/pipewire/log.h b/src/pipewire/log.h index 4816d4d2c..e6f000b8b 100644 --- a/src/pipewire/log.h +++ b/src/pipewire/log.h @@ -136,13 +136,14 @@ pw_log_logv(enum spa_log_level level, * Register log topic with the logger, to enable dynamic log levels. * Topic must be unregistered before freeing it or plugin unload. * May be used instead of \ref PW_LOG_TOPIC_INIT + * This function is threadsafe. * * \since 1.1.0 */ void pw_log_topic_register(struct spa_log_topic *t); /** - * Unregister log topic + * Unregister log topic. This function is threadsafe. * * \since 1.1.0 */