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 kspin::SpinNoIrq;
12use 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 pub(crate) tg: SpinNoIrq<ThreadGroup>,
29
30 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
53impl Process {
55 pub fn parent(&self) -> Option<Arc<Process>> {
57 self.parent.lock().upgrade()
58 }
59
60 pub fn children(&self) -> Vec<Arc<Process>> {
62 self.children.lock().values().cloned().collect()
63 }
64}
65
66impl Process {
68 pub fn group(&self) -> Arc<ProcessGroup> {
70 self.group.lock().clone()
71 }
72
73 fn set_group(self: &Arc<Self>, group: &Arc<ProcessGroup>) {
74 let mut self_group = self.group.lock();
75
76 self_group.processes.lock().remove(&self.pid);
77
78 group.processes.lock().insert(self.pid, self);
79
80 *self_group = group.clone();
81 }
82
83 pub fn create_session(self: &Arc<Self>) -> Option<(Arc<Session>, Arc<ProcessGroup>)> {
97 if self.group.lock().session.sid() == self.pid {
98 return None;
99 }
100
101 let new_session = Session::new(self.pid);
102 let new_group = ProcessGroup::new(self.pid, &new_session);
103 self.set_group(&new_group);
104
105 Some((new_session, new_group))
106 }
107
108 pub fn create_group(self: &Arc<Self>) -> Option<Arc<ProcessGroup>> {
118 if self.group.lock().pgid() == self.pid {
119 return None;
120 }
121
122 let new_group = ProcessGroup::new(self.pid, &self.group.lock().session);
123 self.set_group(&new_group);
124
125 Some(new_group)
126 }
127
128 pub fn move_to_group(self: &Arc<Self>, group: &Arc<ProcessGroup>) -> bool {
136 if Arc::ptr_eq(&self.group.lock(), group) {
137 return true;
138 }
139
140 if !Arc::ptr_eq(&self.group.lock().session, &group.session) {
141 return false;
142 }
143
144 self.set_group(group);
145 true
146 }
147}
148
149impl Process {
151 pub fn add_thread(self: &Arc<Self>, tid: Pid) {
153 self.tg.lock().threads.insert(tid);
154 }
155
156 pub fn exit_thread(self: &Arc<Self>, tid: Pid, exit_code: i32) -> bool {
161 let mut tg = self.tg.lock();
162 if !tg.group_exited {
163 tg.exit_code = exit_code;
164 }
165 tg.threads.remove(&tid);
166 tg.threads.is_empty()
167 }
168
169 pub fn threads(&self) -> Vec<Pid> {
171 self.tg.lock().threads.iter().cloned().collect()
172 }
173
174 pub fn is_group_exited(&self) -> bool {
176 self.tg.lock().group_exited
177 }
178
179 pub fn group_exit(&self) {
181 self.tg.lock().group_exited = true;
182 }
183
184 pub fn exit_code(&self) -> i32 {
186 self.tg.lock().exit_code
187 }
188}
189
190impl Process {
192 pub fn is_zombie(&self) -> bool {
194 self.is_zombie.load(Ordering::Acquire)
195 }
196
197 pub fn exit(self: &Arc<Self>) {
204 let reaper = INIT_PROC.get().unwrap();
206
207 if Arc::ptr_eq(self, reaper) {
208 return;
209 }
210
211 let mut children = self.children.lock(); self.is_zombie.store(true, Ordering::Release);
213
214 let mut reaper_children = reaper.children.lock();
215 let reaper = Arc::downgrade(reaper);
216
217 for (pid, child) in core::mem::take(&mut *children) {
218 *child.parent.lock() = reaper.clone();
219 reaper_children.insert(pid, child);
220 }
221 }
222
223 pub fn free(&self) {
227 assert!(self.is_zombie(), "only zombie process can be freed");
228
229 if let Some(parent) = self.parent() {
230 parent.children.lock().remove(&self.pid);
231 }
232 }
233}
234
235impl fmt::Debug for Process {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 let mut builder = f.debug_struct("Process");
238 builder.field("pid", &self.pid);
239
240 let tg = self.tg.lock();
241 if tg.group_exited {
242 builder.field("group_exited", &tg.group_exited);
243 }
244 if self.is_zombie() {
245 builder.field("exit_code", &tg.exit_code);
246 }
247
248 if let Some(parent) = self.parent() {
249 builder.field("parent", &parent.pid());
250 }
251 builder.field("group", &self.group());
252 builder.finish()
253 }
254}
255
256impl Process {
258 fn new(pid: Pid, parent: Option<Arc<Process>>) -> Arc<Process> {
259 let group = parent.as_ref().map_or_else(
260 || {
261 let session = Session::new(pid);
262 ProcessGroup::new(pid, &session)
263 },
264 |p| p.group(),
265 );
266
267 let process = Arc::new(Process {
268 pid,
269 is_zombie: AtomicBool::new(false),
270 tg: SpinNoIrq::new(ThreadGroup::default()),
271 children: SpinNoIrq::new(StrongMap::new()),
272 parent: SpinNoIrq::new(parent.as_ref().map(Arc::downgrade).unwrap_or_default()),
273 group: SpinNoIrq::new(group.clone()),
274 });
275
276 group.processes.lock().insert(pid, &process);
277
278 if let Some(parent) = parent {
279 parent.children.lock().insert(pid, process.clone());
280 } else {
281 INIT_PROC.init_once(process.clone());
282 }
283
284 process
285 }
286
287 pub fn new_init(pid: Pid) -> Arc<Process> {
292 Self::new(pid, None)
293 }
294
295 pub fn fork(self: &Arc<Process>, pid: Pid) -> Arc<Process> {
297 Self::new(pid, Some(self.clone()))
298 }
299}
300
301static INIT_PROC: LazyInit<Arc<Process>> = LazyInit::new();
302
303pub fn init_proc() -> Arc<Process> {
307 INIT_PROC.get().unwrap().clone()
308}