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.
This commit is contained in:
Pauli Virtanen 2022-02-03 21:16:39 +02:00 committed by Wim Taymans
parent 8205bd811a
commit e737e14e8b

View file

@ -4701,8 +4701,8 @@ static void handle_module_loaded(struct module *module, struct client *client, u
spa_assert(!SPA_RESULT_IS_ASYNC(result)); spa_assert(!SPA_RESULT_IS_ASYNC(result));
if (SPA_RESULT_IS_OK(result)) { if (SPA_RESULT_IS_OK(result)) {
pw_log_info("[%s] loaded module index:%u name:%s", pw_log_info("[%s] loaded module index:%u name:%s tag:%d",
client_name, module->index, module->name); client_name, module->index, module->name, tag);
module->loaded = true; module->loaded = true;
@ -4721,9 +4721,9 @@ static void handle_module_loaded(struct module *module, struct client *client, u
} }
} }
else { 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, impl, client_name,
module->index, module->name, module->index, module->name, tag,
result, spa_strerror(result)); result, spa_strerror(result));
module_schedule_unload(module); module_schedule_unload(module);
@ -4740,34 +4740,92 @@ struct pending_module {
struct module *module; struct module *module;
struct spa_hook module_listener; struct spa_hook module_listener;
struct spa_hook manager_listener;
uint32_t tag; 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) static void on_module_loaded(void *data, int result)
{ {
struct pending_module *pm = data; struct pending_module *pm = data;
if (pm->client != NULL) pw_log_debug("pending module %p: loaded, result:%d tag:%d",
spa_hook_remove(&pm->client_listener); 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) 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) static void on_client_disconnect(void *data)
{ {
struct pending_module *pm = 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->client_listener);
spa_hook_remove(&pm->manager_listener);
pm->client = NULL; 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) 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, VERSION_CLIENT_EVENTS,
.disconnect = on_client_disconnect, .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; const char *name, *argument;
struct module *module; struct module *module;
struct pending_module *pm;
int r; int r;
if (message_get(m, 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) if (module == NULL)
return -errno; 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); 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; module_add_listener(module, &pm->module_listener, &module_events, pm);
pm->client = client; client_add_listener(client, &pm->client_listener, &client_events, pm);
pm->module = module; pw_manager_add_listener(client->manager, &pm->manager_listener, &manager_events, pm);
module_add_listener(module, &pm->module_listener, &module_events, pm); if (!SPA_RESULT_IS_ASYNC(r))
client_add_listener(client, &pm->client_listener, &client_events, pm); on_module_loaded(pm, r);
} else {
handle_module_loaded(module, client, tag, r);
}
/* /*
* return 0 to prevent `handle_packet()` from sending a reply * return 0 to prevent `handle_packet()` from sending a reply