From 968508cf4d8be2e11dde437cca4acb0b2890d9a9 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Wed, 30 Nov 2022 16:33:37 +0100 Subject: [PATCH] impl-node: Don't schedule non-active node Avoid scheduling non-active nodes by removing the eventfd source from the data loop when the node is deactivated. Read any old value from the eventfd when starting the node again in case it has been written to while the source was removed from the loop. The ready callback can still be called when the node isn't active since it is not called via the eventfd. --- src/pipewire/impl-node.c | 68 +++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index 5480d273e..4a07ac8be 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -158,11 +158,49 @@ static void remove_node(struct pw_impl_node *this) this->rt.driver_target.node = NULL; } +static int +do_node_add(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct pw_impl_node *this = user_data; + struct pw_impl_node *driver = this->driver_node; + + this->added = true; + if (this->source.loop == NULL) { + struct spa_system *data_system = this->context->data_system; + uint64_t dummy; + int res; + + /* clear the eventfd in case it was written to while the node was stopped */ + res = spa_system_eventfd_read(data_system, this->source.fd, &dummy); + if (SPA_UNLIKELY(res != -EAGAIN && res != 0)) + pw_log_warn("%p: read failed %m", this); + + spa_loop_add_source(loop, &this->source); + add_node(this, driver); + } + return 0; +} + +static int +do_node_remove(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct pw_impl_node *this = user_data; + if (this->source.loop != NULL) { + spa_loop_remove_source(loop, &this->source); + remove_node(this); + } + this->added = false; + return 0; +} + static void node_deactivate(struct pw_impl_node *this) { struct pw_impl_port *port; struct pw_impl_link *link; + /* make sure the node doesn't get woken up while not active */ + pw_loop_invoke(this->data_loop, do_node_remove, 1, NULL, 0, true, this); + pw_log_debug("%p: deactivate", this); spa_list_for_each(port, &this->input_ports, link) { spa_list_for_each(link, &port->links, input_link) @@ -325,34 +363,6 @@ static void emit_params(struct pw_impl_node *node, uint32_t *changed_ids, uint32 } } -static int -do_node_add(struct spa_loop *loop, - bool async, uint32_t seq, const void *data, size_t size, void *user_data) -{ - struct pw_impl_node *this = user_data; - struct pw_impl_node *driver = this->driver_node; - - if (this->source.loop == NULL) { - spa_loop_add_source(loop, &this->source); - add_node(this, driver); - } - this->added = true; - return 0; -} - -static int -do_node_remove(struct spa_loop *loop, - bool async, uint32_t seq, const void *data, size_t size, void *user_data) -{ - struct pw_impl_node *this = user_data; - if (this->source.loop != NULL) { - spa_loop_remove_source(loop, &this->source); - remove_node(this); - } - this->added = false; - return 0; -} - static void node_update_state(struct pw_impl_node *node, enum pw_node_state state, int res, char *error) { struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); @@ -1636,7 +1646,7 @@ static int node_ready(void *data, int status) node->driver, node->exported, driver, status, node->added); if (!node->added) { - pw_log_warn("%p: ready non-active node", node); + pw_log_warn("%p: ready non-active node %s in state %d", node, node->name, node->info.state); return -EIO; }