mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-06 13:30:01 -05:00
context: rework node states some more
Make collect_nodes return a list of all nodes that are in some way linked to the node and need to be scheduled as a group. Move all the collected nodes to a driver, a fallback driver or away from a driver. This fixes some cases where nodes were moved quickly between drivers, causing a lot of activation messages to be sent and fds to be dupped. Nodes should now only move when needed with minimal amount of changes to their state. See #2309
This commit is contained in:
parent
cc7aadde8a
commit
f6dbd75e61
1 changed files with 57 additions and 39 deletions
|
|
@ -915,27 +915,15 @@ static int ensure_state(struct pw_impl_node *node, bool running)
|
||||||
return pw_impl_node_set_state(node, state);
|
return pw_impl_node_set_state(node, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int collect_nodes(struct pw_context *context, struct pw_impl_node *node)
|
static int collect_nodes(struct pw_context *context, struct pw_impl_node *node, struct spa_list *collect)
|
||||||
{
|
{
|
||||||
struct spa_list queue;
|
struct spa_list queue;
|
||||||
struct pw_impl_node *n, *t, *driver;
|
struct pw_impl_node *n, *t;
|
||||||
struct pw_impl_port *p;
|
struct pw_impl_port *p;
|
||||||
struct pw_impl_link *l;
|
struct pw_impl_link *l;
|
||||||
|
|
||||||
pw_log_debug("node %p: '%s'", node, node->name);
|
pw_log_debug("node %p: '%s'", node, node->name);
|
||||||
|
|
||||||
if (node->driver) {
|
|
||||||
driver = node;
|
|
||||||
spa_list_consume(t, &driver->follower_list, follower_link) {
|
|
||||||
spa_list_remove(&t->follower_link);
|
|
||||||
spa_list_init(&t->follower_link);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
driver = node->driver_node;
|
|
||||||
if (driver == NULL)
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start with node in the queue */
|
/* start with node in the queue */
|
||||||
spa_list_init(&queue);
|
spa_list_init(&queue);
|
||||||
spa_list_append(&queue, &node->sort_link);
|
spa_list_append(&queue, &node->sort_link);
|
||||||
|
|
@ -944,8 +932,10 @@ static int collect_nodes(struct pw_context *context, struct pw_impl_node *node)
|
||||||
/* now follow all the links from the nodes in the queue
|
/* now follow all the links from the nodes in the queue
|
||||||
* and add the peers to the queue. */
|
* and add the peers to the queue. */
|
||||||
spa_list_consume(n, &queue, sort_link) {
|
spa_list_consume(n, &queue, sort_link) {
|
||||||
|
pw_log_debug(" next node %p: '%s'", n, n->name);
|
||||||
|
|
||||||
spa_list_remove(&n->sort_link);
|
spa_list_remove(&n->sort_link);
|
||||||
pw_impl_node_set_driver(n, driver);
|
spa_list_append(collect, &n->sort_link);
|
||||||
n->passive = true;
|
n->passive = true;
|
||||||
|
|
||||||
if (!n->active)
|
if (!n->active)
|
||||||
|
|
@ -964,7 +954,7 @@ static int collect_nodes(struct pw_context *context, struct pw_impl_node *node)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!l->passive)
|
if (!l->passive)
|
||||||
node->passive = driver->passive = n->passive = false;
|
node->passive = n->passive = false;
|
||||||
|
|
||||||
if (!t->visited) {
|
if (!t->visited) {
|
||||||
t->visited = true;
|
t->visited = true;
|
||||||
|
|
@ -985,7 +975,7 @@ static int collect_nodes(struct pw_context *context, struct pw_impl_node *node)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!l->passive)
|
if (!l->passive)
|
||||||
node->passive = driver->passive = n->passive = false;
|
node->passive = n->passive = false;
|
||||||
|
|
||||||
if (!t->visited) {
|
if (!t->visited) {
|
||||||
t->visited = true;
|
t->visited = true;
|
||||||
|
|
@ -1011,6 +1001,27 @@ static int collect_nodes(struct pw_context *context, struct pw_impl_node *node)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void move_to_driver(struct pw_context *context, struct spa_list *nodes,
|
||||||
|
struct pw_impl_node *driver)
|
||||||
|
{
|
||||||
|
struct pw_impl_node *n;
|
||||||
|
pw_log_debug("driver: %p %s", driver, driver->name);
|
||||||
|
spa_list_consume(n, nodes, sort_link) {
|
||||||
|
spa_list_remove(&n->sort_link);
|
||||||
|
pw_log_debug(" follower: %p %s", n, n->name);
|
||||||
|
pw_impl_node_set_driver(n, driver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void remove_from_driver(struct pw_context *context, struct spa_list *nodes)
|
||||||
|
{
|
||||||
|
struct pw_impl_node *n;
|
||||||
|
spa_list_consume(n, nodes, sort_link) {
|
||||||
|
spa_list_remove(&n->sort_link);
|
||||||
|
pw_impl_node_set_driver(n, NULL);
|
||||||
|
ensure_state(n, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void get_quantums(struct pw_context *context, uint32_t *def,
|
static inline void get_quantums(struct pw_context *context, uint32_t *def,
|
||||||
uint32_t *min, uint32_t *max, uint32_t *limit, uint32_t *rate)
|
uint32_t *min, uint32_t *max, uint32_t *limit, uint32_t *rate)
|
||||||
{
|
{
|
||||||
|
|
@ -1113,6 +1124,7 @@ int pw_context_recalc_graph(struct pw_context *context, const char *reason)
|
||||||
uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum;
|
uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum;
|
||||||
uint32_t *rates, n_rates, def_rate;
|
uint32_t *rates, n_rates, def_rate;
|
||||||
bool freewheel = false, global_force_rate, force_rate, force_quantum, global_force_quantum;
|
bool freewheel = false, global_force_rate, force_rate, force_quantum, global_force_quantum;
|
||||||
|
struct spa_list collect;
|
||||||
|
|
||||||
pw_log_info("%p: busy:%d reason:%s", context, impl->recalc, reason);
|
pw_log_info("%p: busy:%d reason:%s", context, impl->recalc, reason);
|
||||||
|
|
||||||
|
|
@ -1140,9 +1152,11 @@ again:
|
||||||
if (n->exported)
|
if (n->exported)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!n->visited)
|
if (!n->visited) {
|
||||||
collect_nodes(context, n);
|
spa_list_init(&collect);
|
||||||
|
collect_nodes(context, n, &collect);
|
||||||
|
move_to_driver(context, &collect, n);
|
||||||
|
}
|
||||||
/* from now on we are only interested in active driving nodes.
|
/* from now on we are only interested in active driving nodes.
|
||||||
* We're going to see if there are active followers. */
|
* We're going to see if there are active followers. */
|
||||||
if (!n->driving || !n->active)
|
if (!n->driving || !n->active)
|
||||||
|
|
@ -1179,35 +1193,39 @@ again:
|
||||||
|
|
||||||
/* now go through all available nodes. The ones we didn't visit
|
/* now go through all available nodes. The ones we didn't visit
|
||||||
* in collect_nodes() are not linked to any driver. We assign them
|
* in collect_nodes() are not linked to any driver. We assign them
|
||||||
* to either an active driver or the first driver */
|
* to either an active driver or the first driver if they are in a
|
||||||
|
* group that needs a driver. Else we remove them from a driver
|
||||||
|
* and stop them. */
|
||||||
spa_list_for_each(n, &context->node_list, link) {
|
spa_list_for_each(n, &context->node_list, link) {
|
||||||
struct pw_impl_node *t;
|
struct pw_impl_node *t, *driver;
|
||||||
|
|
||||||
if (n->exported || n->visited)
|
if (n->exported || n->visited)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pw_log_debug("%p: unassigned node %p: '%s' active:%d want_driver:%d target:%p",
|
pw_log_debug("%p: unassigned node %p: '%s' active:%d want_driver:%d target:%p",
|
||||||
context, n, n->name, n->active, n->want_driver, target);
|
context, n, n->name, n->active, n->want_driver, target);
|
||||||
|
|
||||||
t = n->want_driver && n->active ? target : NULL;
|
/* collect all nodes in this group */
|
||||||
if (t != NULL) {
|
spa_list_init(&collect);
|
||||||
pw_impl_node_set_driver(n, t);
|
collect_nodes(context, n, &collect);
|
||||||
/* we configured a driver, move all linked
|
|
||||||
* nodes to it as well */
|
driver = NULL;
|
||||||
if (n->always_process)
|
spa_list_for_each(t, &collect, sort_link) {
|
||||||
t->passive = false;
|
/* is any active and want a driver or it want process */
|
||||||
collect_nodes(context, n);
|
if ((t->want_driver && t->active && !n->passive) ||
|
||||||
if (!n->always_process && n->passive)
|
t->always_process)
|
||||||
/* nothing active and node doesn't need to be
|
driver = target;
|
||||||
* scheduled, remove from driver again and
|
|
||||||
* stop */
|
|
||||||
t = NULL;
|
|
||||||
}
|
}
|
||||||
if (t == NULL) {
|
if (driver != NULL) {
|
||||||
/* no driver, make sure the node stops */
|
/* driver needed for this group */
|
||||||
pw_impl_node_set_driver(n, NULL);
|
driver->passive = false;
|
||||||
ensure_state(n, false);
|
move_to_driver(context, &collect, driver);
|
||||||
|
} else {
|
||||||
|
/* no driver, make sure the nodes stops */
|
||||||
|
remove_from_driver(context, &collect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* clean up the visited flag now */
|
||||||
spa_list_for_each(n, &context->node_list, link)
|
spa_list_for_each(n, &context->node_list, link)
|
||||||
n->visited = false;
|
n->visited = false;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue