impl-link: improve feedback loop check

Mark peer nodes as visited and only visit them once. Reduces the
complexity a lot.
Limit the number of hops we check to 32 to avoid excessive work.
This commit is contained in:
Wim Taymans 2021-07-07 12:54:09 +02:00
parent 298dfa7da4
commit 6600d93d5d

View file

@ -41,6 +41,8 @@
#define NAME "link"
#define MAX_HOPS 32
#define pw_link_resource_info(r,...) pw_resource_call(r,struct pw_link_events,info,0,__VA_ARGS__)
/** \cond */
@ -928,26 +930,30 @@ static const struct pw_impl_node_events output_node_events = {
.active_changed = node_active_changed,
};
static bool pw_impl_node_can_reach(struct pw_impl_node *output, struct pw_impl_node *input)
static bool pw_impl_node_can_reach(struct pw_impl_node *output, struct pw_impl_node *input, int hop)
{
struct pw_impl_port *p;
struct pw_impl_link *l;
output->visited = true;
if (output == input)
return true;
spa_list_for_each(p, &output->output_ports, link) {
struct pw_impl_link *l;
if (hop == MAX_HOPS) {
pw_log_warn("exceeded hops (%d) %s -> %s", hop, output->name, input->name);
return false;
}
spa_list_for_each(p, &output->output_ports, link) {
spa_list_for_each(l, &p->links, output_link)
l->input->node->visited = l->feedback;
}
spa_list_for_each(p, &output->output_ports, link) {
spa_list_for_each(l, &p->links, output_link) {
if (l->feedback)
if (l->input->node->visited)
continue;
if (l->input->node == input)
return true;
}
spa_list_for_each(l, &p->links, output_link) {
if (l->feedback)
continue;
if (pw_impl_node_can_reach(l->input->node, input))
if (pw_impl_node_can_reach(l->input->node, input, hop+1))
return true;
}
}
@ -1091,7 +1097,7 @@ struct pw_impl_link *pw_context_create_link(struct pw_context *context,
goto error_no_mem;
this = &impl->this;
this->feedback = pw_impl_node_can_reach(input_node, output_node);
this->feedback = pw_impl_node_can_reach(input_node, output_node, 0);
pw_properties_set(properties, PW_KEY_LINK_FEEDBACK, this->feedback ? "true" : NULL);
pw_log_debug(NAME" %p: new out-port:%p -> in-port:%p", this, output, input);