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 group_exit(&self) {
208 self.tg.lock().group_exited = true;
209 }
210
211 pub fn exit_code(&self) -> i32 {
213 self.tg.lock().exit_code
214 }
215}
216
217impl Process {
219 fn orphan_reaper(self: &Arc<Self>) -> Arc<Process> {
220 let init_proc = INIT_PROC.get().unwrap();
221 let mut cursor = self.parent();
222
223 while let Some(proc) = cursor {
224 if Arc::ptr_eq(&proc, init_proc) {
225 break;
226 }
227 if proc.is_child_subreaper() && !proc.is_zombie() {
228 return proc;
229 }
230 cursor = proc.parent();
231 }
232
233 init_proc.clone()
234 }
235
236 pub fn is_zombie(&self) -> bool {
238 self.is_zombie.load(Ordering::Acquire)
239 }
240
241 pub fn exit(self: &Arc<Self>) {
248 if self.is_init() {
249 return;
250 }
251
252 let reaper_proc = self.orphan_reaper();
253 let reaper_parent = Arc::downgrade(&reaper_proc);
254 let children = {
255 let mut children = self.children.lock();
256 core::mem::take(&mut *children)
257 };
258
259 let mut reaper_children = reaper_proc.children.lock();
260 for (pid, child) in children {
261 *child.parent.lock() = reaper_parent.clone();
262 reaper_children.insert(pid, child);
263 }
264 drop(reaper_children);
265
266 self.is_zombie.store(true, Ordering::Release);
267 }
268
269 pub fn free(&self) {
273 assert!(self.is_zombie(), "only zombie process can be freed");
274
275 if let Some(parent) = self.parent() {
276 parent.children.lock().remove(&self.pid);
277 }
278 }
279}
280
281impl fmt::Debug for Process {
282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 let mut builder = f.debug_struct("Process");
284 builder.field("pid", &self.pid);
285
286 let tg = self.tg.lock();
287 if tg.group_exited {
288 builder.field("group_exited", &tg.group_exited);
289 }
290 if self.is_zombie() {
291 builder.field("exit_code", &tg.exit_code);
292 }
293
294 if let Some(parent) = self.parent() {
295 builder.field("parent", &parent.pid());
296 }
297 builder.field("group", &self.group());
298 builder.finish()
299 }
300}
301
302impl Process {
304 fn new(pid: Pid, parent: Option<Arc<Process>>) -> Arc<Process> {
305 let group = parent.as_ref().map_or_else(
306 || {
307 let session = Session::new(pid);
308 ProcessGroup::new(pid, &session)
309 },
310 |p| p.group(),
311 );
312
313 let process = Arc::new(Process {
314 pid,
315 is_zombie: AtomicBool::new(false),
316 is_child_subreaper: AtomicBool::new(false),
317 tg: SpinNoIrq::new(ThreadGroup::default()),
318 children: SpinNoIrq::new(StrongMap::new()),
319 parent: SpinNoIrq::new(parent.as_ref().map(Arc::downgrade).unwrap_or_default()),
320 group: SpinNoIrq::new(group.clone()),
321 });
322
323 group.processes.lock().insert(pid, &process);
324
325 if let Some(parent) = parent {
326 parent.children.lock().insert(pid, process.clone());
327 } else {
328 INIT_PROC.init_once(process.clone());
329 }
330
331 process
332 }
333
334 pub fn new_init(pid: Pid) -> Arc<Process> {
339 Self::new(pid, None)
340 }
341
342 pub fn fork(self: &Arc<Process>, pid: Pid) -> Arc<Process> {
344 Self::new(pid, Some(self.clone()))
345 }
346}
347
348static INIT_PROC: LazyInit<Arc<Process>> = LazyInit::new();
349
350pub fn init_proc() -> Arc<Process> {
354 INIT_PROC.get().unwrap().clone()
355}