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.
This commit is contained in:
Jonas Holmberg 2022-11-30 16:33:37 +01:00
parent 75007ae94f
commit 968508cf4d

View file

@ -158,11 +158,49 @@ static void remove_node(struct pw_impl_node *this)
this->rt.driver_target.node = NULL; 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) static void node_deactivate(struct pw_impl_node *this)
{ {
struct pw_impl_port *port; struct pw_impl_port *port;
struct pw_impl_link *link; 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); pw_log_debug("%p: deactivate", this);
spa_list_for_each(port, &this->input_ports, link) { spa_list_for_each(port, &this->input_ports, link) {
spa_list_for_each(link, &port->links, input_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) 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); 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); node->driver, node->exported, driver, status, node->added);
if (!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; return -EIO;
} }