1use std::collections::HashMap;
7
8use crate::row::Row;
9use crate::Pid;
10
11pub fn build(rows: &mut [Row]) -> Vec<usize> {
22 let mut by_pid: HashMap<Pid, usize> = HashMap::with_capacity(rows.len());
26 for (idx, row) in rows.iter().enumerate() {
27 if !row.is_thread {
28 by_pid.insert(row.pid, idx);
29 }
30 }
31
32 let mut children: Vec<Vec<usize>> = vec![Vec::new(); rows.len()];
33 let mut is_root = vec![true; rows.len()];
34
35 for idx in 0..rows.len() {
36 if rows[idx].is_thread {
37 match by_pid.get(&rows[idx].tgid).copied() {
40 Some(p) if p != idx => {
41 children[p].push(idx);
42 is_root[idx] = false;
43 }
44 _ => is_root[idx] = true,
45 }
46 continue;
47 }
48
49 let ppid = rows[idx].ppid;
50 let parent = by_pid.get(&ppid).copied();
51 match parent {
52 Some(p) if p != idx => {
53 children[p].push(idx);
54 is_root[idx] = false;
55 }
56 _ => is_root[idx] = true,
58 }
59 }
60
61 let mut seen = vec![false; rows.len()];
63 let mut order = Vec::with_capacity(rows.len());
64
65 for root in 0..rows.len() {
66 if is_root[root] {
67 rows[root].is_last_child = false;
68 walk(root, 0, &children, rows, &mut order, &mut seen);
69 }
70 }
71 for idx in 0..rows.len() {
73 if !seen[idx] {
74 rows[idx].depth = 0;
75 rows[idx].is_last_child = false;
76 walk(idx, 0, &children, rows, &mut order, &mut seen);
77 }
78 }
79
80 order
81}
82
83fn walk(
84 idx: usize,
85 depth: u16,
86 children: &[Vec<usize>],
87 rows: &mut [Row],
88 order: &mut Vec<usize>,
89 seen: &mut [bool],
90) {
91 if seen[idx] {
92 return;
93 }
94 seen[idx] = true;
95
96 let kids = &children[idx];
97 rows[idx].depth = depth;
98 rows[idx].has_children = !kids.is_empty();
99 order.push(idx);
102
103 let n = kids.len();
104 for (i, &child) in kids.iter().enumerate() {
105 if seen[child] {
106 continue;
107 }
108 rows[child].is_last_child = i + 1 == n;
109 walk(child, depth.saturating_add(1), children, rows, order, seen);
110 }
111}
112
113pub fn subtree(rows: &[Row], pid: Pid) -> Vec<Pid> {
115 let mut by_pid: HashMap<Pid, usize> = HashMap::with_capacity(rows.len());
116 for (idx, row) in rows.iter().enumerate() {
117 by_pid.insert(row.pid, idx);
118 }
119 let mut children: HashMap<Pid, Vec<Pid>> = HashMap::new();
120 for row in rows {
121 if by_pid.contains_key(&row.ppid) {
122 children.entry(row.ppid).or_default().push(row.pid);
123 }
124 }
125
126 let mut out = Vec::new();
127 let mut stack = vec![pid];
128 let mut guard = 0usize;
129 while let Some(p) = stack.pop() {
130 out.push(p);
131 guard += 1;
132 if guard > rows.len() + 1 {
133 break; }
135 if let Some(kids) = children.get(&p) {
136 stack.extend(kids.iter().copied());
137 }
138 }
139 out
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 fn row(pid: Pid, ppid: Pid) -> Row {
147 let mut r = Row::default_for_test(pid);
148 r.ppid = ppid;
149 r
150 }
151
152 #[test]
153 fn depth_first_order() {
154 let mut rows = vec![row(1, 0), row(2, 1), row(3, 1), row(4, 2)];
156 let order = build(&mut rows);
157 let pids: Vec<Pid> = order.iter().map(|&i| rows[i].pid).collect();
158 assert_eq!(pids, vec![1, 2, 4, 3]);
159 assert_eq!(rows[0].depth, 0, "pid 1 is the root");
160 assert_eq!(rows[1].depth, 1, "pid 2 is a child of 1");
161 assert_eq!(rows[3].depth, 2, "pid 4 is a child of 2");
162 assert!(rows[1].has_children);
163 assert!(!rows[0].is_last_child);
164 assert!(!rows[2].has_children);
167 assert!(order.iter().any(|&i| rows[i].pid == 3));
168 }
169
170 #[test]
171 fn orphan_is_a_root() {
172 let mut rows = vec![row(10, 999)];
173 let order = build(&mut rows);
174 assert_eq!(order.len(), 1);
175 assert_eq!(rows[0].depth, 0);
176 }
177
178 #[test]
179 fn self_parent_does_not_loop() {
180 let mut rows = vec![row(7, 7)];
181 let order = build(&mut rows);
182 assert_eq!(order.len(), 1);
183 }
184
185 #[test]
186 fn cycle_does_not_hang() {
187 let mut rows = vec![row(1, 3), row(2, 1), row(3, 2)];
189 let order = build(&mut rows);
190 assert_eq!(order.len(), 3, "every node must appear exactly once");
191 }
192
193 #[test]
194 fn subtree_walk() {
195 let rows = vec![row(1, 0), row(2, 1), row(3, 1), row(4, 2)];
196 let mut got = subtree(&rows, 1);
197 got.sort_unstable();
198 assert_eq!(got, vec![1, 2, 3, 4]);
199 }
200
201 fn thread_row(pid: Pid, tgid: Pid, id: u64) -> Row {
202 let mut r = Row::default_for_test(pid);
203 r.tgid = tgid;
204 r.ppid = tgid;
205 r.is_thread = true;
206 r.thread_id = Some(id);
207 r
208 }
209
210 #[test]
212 fn threads_nest_under_their_leader() {
213 let mut rows = vec![row(1, 0), thread_row(9001, 1, 1), row(2, 1)];
214 let order = build(&mut rows);
215 let pids: Vec<Pid> = order.iter().map(|&i| rows[i].pid).collect();
216 assert_eq!(pids[0], 1);
218 assert_eq!(pids.len(), 3, "every row appears exactly once");
219 let thread_pos = order
220 .iter()
221 .position(|&i| rows[i].is_thread)
222 .expect("thread present");
223 assert_eq!(rows[order[thread_pos]].depth, 1, "one level under the leader");
224 }
225
226 #[test]
232 fn a_thread_pid_does_not_reparent_an_unrelated_process() {
233 let mut rows = vec![
234 row(1, 0),
235 row(2, 1),
237 thread_row(3, 1, 3),
239 row(3, 2),
241 ];
242 let order = build(&mut rows);
245 assert_eq!(order.len(), 4);
246
247 let real_3 = order
248 .iter()
249 .position(|&i| rows[i].pid == 3 && !rows[i].is_thread)
250 .expect("the real process 3 must be in the tree");
251 assert_eq!(
252 rows[order[real_3]].depth, 2,
253 "process 3 must still be a child of 2, not of the thread"
254 );
255 }
256
257 #[test]
259 fn an_orphan_thread_is_a_root() {
260 let mut rows = vec![thread_row(9001, 424242, 1)];
261 let order = build(&mut rows);
262 assert_eq!(order.len(), 1);
263 assert_eq!(rows[0].depth, 0);
264 }
265}