static LIST_HEAD(unix_unvisited_vertices);
enum unix_vertex_index {
- UNIX_VERTEX_INDEX_UNVISITED,
+ UNIX_VERTEX_INDEX_MARK1,
+ UNIX_VERTEX_INDEX_MARK2,
UNIX_VERTEX_INDEX_START,
};
+static unsigned long unix_vertex_unvisited_index = UNIX_VERTEX_INDEX_MARK1;
+
static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
{
struct unix_vertex *vertex = edge->predecessor->vertex;
if (!vertex) {
vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry);
+ vertex->index = unix_vertex_unvisited_index;
vertex->out_degree = 0;
INIT_LIST_HEAD(&vertex->edges);
}
static LIST_HEAD(unix_visited_vertices);
+static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2;
static void __unix_walk_scc(struct unix_vertex *vertex)
{
LIST_HEAD(edge_stack);
next_vertex:
- /* Push vertex to vertex_stack.
+ /* Push vertex to vertex_stack and mark it as on-stack
+ * (index >= UNIX_VERTEX_INDEX_START).
* The vertex will be popped when finalising SCC later.
*/
- vertex->on_stack = true;
list_add(&vertex->scc_entry, &vertex_stack);
vertex->index = index;
if (!next_vertex)
continue;
- if (next_vertex->index == UNIX_VERTEX_INDEX_UNVISITED) {
+ if (next_vertex->index == unix_vertex_unvisited_index) {
/* Iterative deepening depth first search
*
* 1. Push a forward edge to edge_stack and set
* to skip SCC finalisation.
*/
vertex->lowlink = min(vertex->lowlink, next_vertex->lowlink);
- } else if (next_vertex->on_stack) {
+ } else if (next_vertex->index != unix_vertex_grouped_index) {
/* Loop detected by a back/cross edge.
*
* The successor is on vertex_stack, so two vertices are
/* Don't restart DFS from this vertex in unix_walk_scc(). */
list_move_tail(&vertex->entry, &unix_visited_vertices);
- vertex->on_stack = false;
+ /* Mark vertex as off-stack. */
+ vertex->index = unix_vertex_grouped_index;
}
list_del(&scc);
static void unix_walk_scc(void)
{
- struct unix_vertex *vertex;
-
- list_for_each_entry(vertex, &unix_unvisited_vertices, entry)
- vertex->index = UNIX_VERTEX_INDEX_UNVISITED;
-
/* Visit every vertex exactly once.
* __unix_walk_scc() moves visited vertices to unix_visited_vertices.
*/
while (!list_empty(&unix_unvisited_vertices)) {
+ struct unix_vertex *vertex;
+
vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry);
__unix_walk_scc(vertex);
}
list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices);
+ swap(unix_vertex_unvisited_index, unix_vertex_grouped_index);
}
static LIST_HEAD(gc_candidates);