From 62dd58a6049d1b41895aa21917ef46ae5e8aac0b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jun 2020 10:57:15 +0200 Subject: [PATCH] client: remove busy state from client in resource destroy When a resource is doing an operation that sets the client in the busy state, make sure we unblock the client again when the resource is destroyed before we could complete the operation or else the client is stuck forever. --- src/modules/module-metadata/metadata.c | 20 +++++++++--- src/pipewire/impl-device.c | 34 +++++++++++++-------- src/pipewire/impl-node.c | 42 ++++++++++++++++++++++---- 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/modules/module-metadata/metadata.c b/src/modules/module-metadata/metadata.c index d26b0278c..56a98331b 100644 --- a/src/modules/module-metadata/metadata.c +++ b/src/modules/module-metadata/metadata.c @@ -112,19 +112,31 @@ static const struct pw_resource_events resource_events = { .destroy = global_unbind, }; -static void impl_resource_pong(void *data, int seq) +static void remove_pending(struct resource_data *d) { - struct resource_data *d = data; - - if (d->pong_seq == seq) { + if (d->pong_seq != 0) { pw_impl_client_set_busy(pw_resource_get_client(d->resource), false); d->pong_seq = 0; d->impl->pending--; } } +static void impl_resource_destroy(void *data) +{ + struct resource_data *d = data; + remove_pending(d); +} + +static void impl_resource_pong(void *data, int seq) +{ + struct resource_data *d = data; + if (d->pong_seq == seq) + remove_pending(d); +} + static const struct pw_resource_events impl_resource_events = { PW_VERSION_RESOURCE_EVENTS, + .destroy = impl_resource_destroy, .pong = impl_resource_pong, }; diff --git a/src/pipewire/impl-device.c b/src/pipewire/impl-device.c index 5c4a4296f..2135e2380 100644 --- a/src/pipewire/impl-device.c +++ b/src/pipewire/impl-device.c @@ -202,7 +202,22 @@ void pw_impl_device_destroy(struct pw_impl_device *device) free(device); } -static void device_pong(void *data, int seq) +static void remove_busy_resource(struct resource_data *d) +{ + if (d->end != -1) { + spa_hook_remove(&d->listener); + d->end = -1; + pw_impl_client_set_busy(d->resource->client, false); + } +} + +static void resource_destroy(void *data) +{ + struct resource_data *d = data; + remove_busy_resource(d); +} + +static void resource_pong(void *data, int seq) { struct resource_data *d = data; struct pw_resource *resource = d->resource; @@ -212,7 +227,8 @@ static void device_pong(void *data, int seq) static const struct pw_resource_events resource_events = { PW_VERSION_RESOURCE_EVENTS, - .pong = device_pong, + .destroy = resource_destroy, + .pong = resource_pong, }; static void result_device_params(void *data, int seq, int res, uint32_t type, const void *result) @@ -280,11 +296,8 @@ static void result_device_params_async(void *data, int seq, int res, uint32_t ty pw_log_debug(NAME" %p: async result %d %d (%d/%d)", d->device, res, seq, d->seq, d->end); - if (seq == d->end) { - spa_hook_remove(&d->listener); - d->end = -1; - pw_impl_client_set_busy(d->resource->client, false); - } + if (seq == d->end) + remove_busy_resource(d); if (seq == d->seq) result_device_params(&d->data, seq, res, type, result); @@ -350,11 +363,8 @@ static void result_device_done(void *data, int seq, int res, uint32_t type, cons pw_log_debug(NAME" %p: async result %d %d (%d/%d)", d->device, res, seq, d->seq, d->end); - if (seq == d->end) { - spa_hook_remove(&d->listener); - d->end = -1; - pw_impl_client_set_busy(d->resource->client, false); - } + if (seq == d->end) + remove_busy_resource(d); } static int device_set_param(void *object, uint32_t id, uint32_t flags, diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index 91723b85a..fb415cdb7 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -58,8 +58,9 @@ struct impl { struct resource_data { struct pw_impl_node *node; - struct pw_resource *resource; + struct pw_resource *resource; + struct spa_hook resource_listener; struct spa_hook object_listener; uint32_t subscribe_ids[MAX_PARAMS]; @@ -414,16 +415,22 @@ static int node_subscribe_params(void *object, uint32_t *ids, uint32_t n_ids) return 0; } +static void remove_busy_resource(struct resource_data *d) +{ + if (d->end != -1) { + spa_hook_remove(&d->listener); + d->end = -1; + pw_impl_client_set_busy(d->resource->client, false); + } +} + static void result_node_sync(void *data, int seq, int res, uint32_t type, const void *result) { struct resource_data *d = data; pw_log_debug(NAME" %p: sync result %d %d (%d/%d)", d->node, res, seq, d->seq, d->end); - if (seq == d->end) { - spa_hook_remove(&d->listener); - d->end = -1; - pw_impl_client_set_busy(d->resource->client, false); - } + if (seq == d->end) + remove_busy_resource(d); } static int node_set_param(void *object, uint32_t id, uint32_t flags, @@ -484,6 +491,26 @@ static const struct pw_node_methods node_methods = { .send_command = node_send_command }; +static void resource_destroy(void *data) +{ + struct resource_data *d = data; + remove_busy_resource(d); +} + +static void resource_pong(void *data, int seq) +{ + struct resource_data *d = data; + struct pw_resource *resource = d->resource; + pw_log_debug(NAME" %p: resource %p: got pong %d", d->node, + resource, seq); +} + +static const struct pw_resource_events resource_events = { + PW_VERSION_RESOURCE_EVENTS, + .destroy = resource_destroy, + .pong = resource_pong, +}; + static int global_bind(void *_data, struct pw_impl_client *client, uint32_t permissions, uint32_t version, uint32_t id) @@ -502,6 +529,9 @@ global_bind(void *_data, struct pw_impl_client *client, uint32_t permissions, data->resource = resource; data->end = -1; + pw_resource_add_listener(resource, + &data->resource_listener, + &resource_events, data); pw_resource_add_object_listener(resource, &data->object_listener, &node_methods, data);