From e737e14e8becd121e68f3241f7198961aabcc45a Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Thu, 3 Feb 2022 21:16:39 +0200 Subject: [PATCH] pulse-server: sync client manager before returning from LOAD_MODULE Sync client's manager, before returning from module load, also for async module loads. This is because the module load may have its own core, so even though it has made changes on server, the client manager might not see them yet. Fix this by syncing client->manager before operation return. --- .../module-protocol-pulse/pulse-server.c | 111 ++++++++++++++---- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 4c8ed8b1b..92efda5b5 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -4701,8 +4701,8 @@ static void handle_module_loaded(struct module *module, struct client *client, u spa_assert(!SPA_RESULT_IS_ASYNC(result)); if (SPA_RESULT_IS_OK(result)) { - pw_log_info("[%s] loaded module index:%u name:%s", - client_name, module->index, module->name); + pw_log_info("[%s] loaded module index:%u name:%s tag:%d", + client_name, module->index, module->name, tag); module->loaded = true; @@ -4721,9 +4721,9 @@ static void handle_module_loaded(struct module *module, struct client *client, u } } else { - pw_log_warn("%p: [%s] failed to load module index:%u name:%s result:%d (%s)", + pw_log_warn("%p: [%s] failed to load module index:%u name:%s tag:%d result:%d (%s)", impl, client_name, - module->index, module->name, + module->index, module->name, tag, result, spa_strerror(result)); module_schedule_unload(module); @@ -4740,34 +4740,92 @@ struct pending_module { struct module *module; struct spa_hook module_listener; + struct spa_hook manager_listener; + uint32_t tag; + + int result; + bool wait_sync; }; +static void finish_pending_module(struct pending_module *pm) +{ + spa_hook_remove(&pm->module_listener); + + if (pm->client != NULL) { + spa_hook_remove(&pm->client_listener); + spa_hook_remove(&pm->manager_listener); + } + + handle_module_loaded(pm->module, pm->client, pm->tag, pm->result); + free(pm); +} + +static void on_load_module_manager_sync(void *data) +{ + struct pending_module *pm = data; + + pw_log_debug("pending module %p: manager sync wait_sync:%d tag:%d", + pm, pm->wait_sync, pm->tag); + + if (!pm->wait_sync) + return; + + finish_pending_module(pm); +} + static void on_module_loaded(void *data, int result) { struct pending_module *pm = data; - if (pm->client != NULL) - spa_hook_remove(&pm->client_listener); + pw_log_debug("pending module %p: loaded, result:%d tag:%d", + pm, result, pm->tag); - spa_hook_remove(&pm->module_listener); + pm->result = result; - handle_module_loaded(pm->module, pm->client, pm->tag, result); + /* + * Do manager sync first: the module may have its own core, so + * although things are completed on the server, our client + * might not yet see them. + */ - free(pm); + if (pm->client == NULL) { + finish_pending_module(pm); + } else { + pw_log_debug("pending module %p: wait manager sync tag:%d", pm, pm->tag); + pm->wait_sync = true; + pw_manager_sync(pm->client->manager); + } } static void on_module_destroy(void *data) { - on_module_loaded(data, -ECANCELED); + struct pending_module *pm = data; + + pw_log_debug("pending module %p: destroyed, tag:%d", + pm, pm->tag); + + pm->result = -ECANCELED; + finish_pending_module(pm); } static void on_client_disconnect(void *data) { struct pending_module *pm = data; + pw_log_debug("pending module %p: client disconnect tag:%d", pm, pm->tag); + spa_hook_remove(&pm->client_listener); + spa_hook_remove(&pm->manager_listener); pm->client = NULL; + + if (pm->wait_sync) + finish_pending_module(pm); +} + +static void on_load_module_manager_disconnect(void *data) +{ + on_client_disconnect(data); } static int do_load_module(struct client *client, uint32_t command, uint32_t tag, struct message *m) @@ -4781,9 +4839,15 @@ static int do_load_module(struct client *client, uint32_t command, uint32_t tag, VERSION_CLIENT_EVENTS, .disconnect = on_client_disconnect, }; + static const struct pw_manager_events manager_events = { + PW_VERSION_MANAGER_EVENTS, + .disconnect = on_load_module_manager_disconnect, + .sync = on_load_module_manager_sync, + }; const char *name, *argument; struct module *module; + struct pending_module *pm; int r; if (message_get(m, @@ -4799,21 +4863,24 @@ static int do_load_module(struct client *client, uint32_t command, uint32_t tag, if (module == NULL) return -errno; + pm = calloc(1, sizeof(*pm)); + if (pm == NULL) + return -errno; + + pm->tag = tag; + pm->client = client; + pm->module = module; + + pw_log_debug("pending module %p: start tag:%d", pm, tag); + r = module_load(client, module); - if (SPA_RESULT_IS_ASYNC(r)) { - struct pending_module *pm = calloc(1, sizeof(*pm)); - if (pm == NULL) - return -errno; - pm->tag = tag; - pm->client = client; - pm->module = module; + module_add_listener(module, &pm->module_listener, &module_events, pm); + client_add_listener(client, &pm->client_listener, &client_events, pm); + pw_manager_add_listener(client->manager, &pm->manager_listener, &manager_events, pm); - module_add_listener(module, &pm->module_listener, &module_events, pm); - client_add_listener(client, &pm->client_listener, &client_events, pm); - } else { - handle_module_loaded(module, client, tag, r); - } + if (!SPA_RESULT_IS_ASYNC(r)) + on_module_loaded(pm, r); /* * return 0 to prevent `handle_packet()` from sending a reply