starry_process/
process.rs1use alloc::{
2 collections::btree_set::BTreeSet,
3 sync::{Arc, Weak},
4 vec::Vec,
5};
6use core::{
7 fmt,
8 sync::atomic::{AtomicBool, Ordering},
9};
10
11use ax_kspin::SpinNoIrq;
12use ax_lazyinit::LazyInit;
13use weak_map::StrongMap;
14
15use crate::{Pid, ProcessGroup, Session};
16
17#[derive(Default)]
18pub(crate) struct ThreadGroup {
19 pub(crate) threads: BTreeSet<Pid>,
20 pub(crate) exit_code: i32,
21 pub(crate) group_exited: bool,
22}
23
24pub struct Process {
26 pid: Pid,
27 is_zombie: AtomicBool,
28 is_child_subreaper: AtomicBool,
29 pub(crate) tg: SpinNoIrq<ThreadGroup>,
30
31 children: SpinNoIrq<StrongMap<Pid, Arc<Process>>>,
32 parent: SpinNoIrq<Weak<Process>>,
33
34 group: SpinNoIrq<Arc<ProcessGroup>>,
35}
36
37impl Process {
38 pub fn pid(&self) -> Pid {
40 self.pid
41 }
42
43 pub fn is_init(self: &Arc<Self>) -> bool {
49 Arc::ptr_eq(self, INIT_PROC.get().unwrap())
50 }
51
52 pub fn is_child_subreaper(&self) -> bool {
58 self.is_child_subreaper.load(Ordering::Acquire)
59 }
60
61 pub fn set_child_subreaper(&self, enabled: bool) {
63 self.is_child_subreaper.store(enabled, Ordering::Release);
64 }
65}
66
67impl Process {
69 pub fn parent(&self) -> Option<Arc<Process>> {
71 self.parent.lock().upgrade()
72 }
73
74 pub fn children(&self) -> Vec<Arc<Process>> {
76 self.children.lock().values().cloned().collect()
77 }
78}
79
80impl Process {
82 pub fn group(&self) -> Arc<ProcessGroup> {
84 self.group.lock().clone()
85 }
86
87 fn set_group(self: &Arc<Self>, group: &Arc<ProcessGroup>) {
88 let mut self_group = self.group.lock();
89
90 self_group.processes.lock().remove(&self.pid);
91
92 group.processes.lock().insert(self.pid, self);
93
94 *self_group = group.clone();
95 }
96
97 pub fn create_session(self: &Arc<Self>) -> Option<(Arc<Session>, Arc<ProcessGroup>)> {
111 if self.group.lock().session.sid() == self.pid {
112 return None;
113 }
114
115 let new_session = Session::new(self.pid);
116 let new_group = ProcessGroup::new(self.pid, &new_session);
117 self.set_group(&new_group);
118
119 Some((new_session, new_group))
120 }
121
122 pub fn create_group(self: &Arc<Self>) -> Option<Arc<ProcessGroup>> {
132 if self.group.lock().pgid() == self.pid {
133 return None;
134 }
135
136 let new_group = ProcessGroup::new(self.pid, &self.group.lock().session);
137 self.set_group(&new_group);
138
139 Some(new_group)
140 }
141
142 pub fn move_to_group(self: &Arc<Self>, group: &Arc<ProcessGroup>) -> bool {
150 if Arc::ptr_eq(&self.group.lock(), group) {
151 return true;
152 }
153
154 if !Arc::ptr_eq(&self.group.lock().session, &group.session) {
155 return false;
156 }
157
158 self.set_group(group);
159 true
160 }
161}
162
163impl Process {
165 pub fn add_thread(self: &Arc<Self>, tid: Pid) {
167 self.tg.lock().threads.insert(tid);
168 }
169
170 pub fn exit_thread(self: &Arc<Self>, tid: Pid, exit_code: i32) -> bool {
175 let mut tg = self.tg.lock();
176 if !tg.group_exited {
177 tg.exit_code = exit_code;
178 }
179 tg.threads.remove(&tid);
180 tg.threads.is_empty()
181 }
182
183 pub fn threads(&self) -> Vec<Pid> {
185 self.tg.lock().threads.iter().cloned().collect()
186 }
187
188 pub fn rename_thread(self: &Arc<Self>, old_tid: Pid, new_tid: Pid) {
196 let mut tg = self.tg.lock();
197 tg.threads.remove(&old_tid);
198 tg.threads.insert(new_tid);
199 }
200
201 pub fn is_group_exited(&self) -> bool {
203 self.tg.lock().group_exited
204 }
205
206 pub fn start_group_exit(&self, exit_code: i32) -> Option<Vec<Pid>> {
212 let mut tg = self.tg.lock();
213 if tg.group_exited {
214 return None;
215 }
216 tg.group_exited = true;
217 tg.exit_code = exit_code;
218 Some(tg.threads.iter().cloned().collect())
219 }
220
221 pub fn group_exit(&self) {
223 self.tg.lock().group_exited = true;
224 }
225
226 pub fn exit_code(&self) -> i32 {
228 self.tg.lock().exit_code
229 }
230}
231
232impl Process {
234 fn orphan_reaper(self: &Arc<Self>) -> Arc<Process> {
235 let init_proc = INIT_PROC.get().unwrap();
236 let mut cursor = self.parent();
237
238 while let Some(proc) = cursor {
239 if Arc::ptr_eq(&proc, init_proc) {
240 break;
241 }
242 if proc.is_child_subreaper() && !proc.is_zombie() {
243 return proc;
244 }
245 cursor = proc.parent();
246 }
247
248 init_proc.clone()
249 }
250
251 pub fn is_zombie(&self) -> bool {
253 self.is_zombie.load(Ordering::Acquire)
254 }
255
256 pub fn exit(self: &Arc<Self>) {
263 if self.is_init() {
264 return;
265 }
266
267 let reaper_proc = self.orphan_reaper();
268 let reaper_parent = Arc::downgrade(&reaper_proc);
269 let children = {
270 let mut children = self.children.lock();
271 core::mem::take(&mut *children)
272 };
273
274 let mut reaper_children = reaper_proc.children.lock();
275 for (pid, child) in children {
276 *child.parent.lock() = reaper_parent.clone();
277 reaper_children.insert(pid, child);
278 }
279 drop(reaper_children);
280
281 self.is_zombie.store(true, Ordering::Release);
282 }
283
284 pub fn free(&self) {
288 assert!(self.is_zombie(), "only zombie process can be freed");
289
290 if let Some(parent) = self.parent() {
291 parent.children.lock().remove(&self.pid);
292 }
293 }
294}
295
296impl fmt::Debug for Process {
297 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298 let mut builder = f.debug_struct("Process");
299 builder.field("pid", &self.pid);
300
301 let tg = self.tg.lock();
302 if tg.group_exited {
303 builder.field("group_exited", &tg.group_exited);
304 }
305 if self.is_zombie() {
306 builder.field("exit_code", &tg.exit_code);
307 }
308
309 if let Some(parent) = self.parent() {
310 builder.field("parent", &parent.pid());
311 }
312 builder.field("group", &self.group());
313 builder.finish()
314 }
315}
316
317impl Process {
319 fn new(pid: Pid, parent: Option<Arc<Process>>) -> Arc<Process> {
320 let group = parent.as_ref().map_or_else(
321 || {
322 let session = Session::new(pid);
323 ProcessGroup::new(pid, &session)
324 },
325 |p| p.group(),
326 );
327
328 let process = Arc::new(Process {
329 pid,
330 is_zombie: AtomicBool::new(false),
331 is_child_subreaper: AtomicBool::new(false),
332 tg: SpinNoIrq::new(ThreadGroup::default()),
333 children: SpinNoIrq::new(StrongMap::new()),
334 parent: SpinNoIrq::new(parent.as_ref().map(Arc::downgrade).unwrap_or_default()),
335 group: SpinNoIrq::new(group.clone()),
336 });
337
338 group.processes.lock().insert(pid, &process);
339
340 if let Some(parent) = parent {
341 parent.children.lock().insert(pid, process.clone());
342 } else {
343 INIT_PROC.init_once(process.clone());
344 }
345
346 process
347 }
348
349 pub fn new_init(pid: Pid) -> Arc<Process> {
354 Self::new(pid, None)
355 }
356
357 pub fn fork(self: &Arc<Process>, pid: Pid) -> Arc<Process> {
359 Self::new(pid, Some(self.clone()))
360 }
361}
362
363static INIT_PROC: LazyInit<Arc<Process>> = LazyInit::new();
364
365pub fn init_proc() -> Arc<Process> {
369 INIT_PROC.get().unwrap().clone()
370}