veridian_kernel/process/
table.rs1#[cfg(feature = "alloc")]
7extern crate alloc;
8
9#[cfg(feature = "alloc")]
10use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
11
12use spin::Mutex;
13
14use super::{pcb::ProcessState, Process, ProcessId};
15#[allow(unused_imports)]
16use crate::{error::KernelError, println};
17
18#[cfg(feature = "alloc")]
20pub struct ProcessEntry {
21 pub process: Box<Process>,
23 pub ref_count: usize,
25}
26
27pub struct ProcessTable {
29 #[cfg(feature = "alloc")]
31 entries: Mutex<BTreeMap<ProcessId, ProcessEntry>>,
32
33 #[cfg(not(feature = "alloc"))]
35 entries: Mutex<ProcessArray>,
36
37 pub process_count: core::sync::atomic::AtomicUsize,
39}
40
41#[cfg(not(feature = "alloc"))]
43pub struct ProcessArray {
44 processes: [Option<Process>; super::MAX_PROCESSES],
45 count: usize,
46}
47
48#[cfg(not(feature = "alloc"))]
49impl ProcessArray {
50 const fn new() -> Self {
51 Self {
52 processes: [const { None }; super::MAX_PROCESSES],
53 count: 0,
54 }
55 }
56}
57
58impl Default for ProcessTable {
59 fn default() -> Self {
60 Self {
61 #[cfg(feature = "alloc")]
62 entries: Mutex::new(BTreeMap::new()),
63 #[cfg(not(feature = "alloc"))]
64 entries: Mutex::new(ProcessArray::new()),
65 process_count: core::sync::atomic::AtomicUsize::new(0),
66 }
67 }
68}
69
70impl ProcessTable {
71 pub const fn new() -> Self {
73 Self {
74 #[cfg(feature = "alloc")]
75 entries: Mutex::new(BTreeMap::new()),
76 #[cfg(not(feature = "alloc"))]
77 entries: Mutex::new(ProcessArray::new()),
78 process_count: core::sync::atomic::AtomicUsize::new(0),
79 }
80 }
81
82 #[cfg(feature = "alloc")]
84 pub fn add_process(&self, process: Process) -> Result<ProcessId, KernelError> {
85 let pid = process.pid;
86 let mut entries = self.entries.lock();
87
88 if entries.contains_key(&pid) {
89 return Err(KernelError::AlreadyExists {
90 resource: "process",
91 id: pid.0,
92 });
93 }
94
95 entries.insert(
96 pid,
97 ProcessEntry {
98 process: Box::new(process),
99 ref_count: 1,
100 },
101 );
102
103 self.process_count
104 .fetch_add(1, core::sync::atomic::Ordering::Relaxed);
105 Ok(pid)
106 }
107
108 #[cfg(not(feature = "alloc"))]
110 pub fn add_process(&self, process: Process) -> Result<ProcessId, KernelError> {
111 let pid = process.pid;
112 let mut entries = self.entries.lock();
113
114 if entries.count >= super::MAX_PROCESSES {
115 return Err(KernelError::ResourceExhausted {
116 resource: "process table",
117 });
118 }
119
120 for i in 0..super::MAX_PROCESSES {
122 if entries.processes[i].is_none() {
123 entries.processes[i] = Some(process);
124 entries.count += 1;
125 self.process_count
126 .fetch_add(1, core::sync::atomic::Ordering::Relaxed);
127 return Ok(pid);
128 }
129 }
130
131 Err(KernelError::ResourceExhausted {
132 resource: "process table",
133 })
134 }
135
136 #[cfg(feature = "alloc")]
138 pub fn remove_process(&self, pid: ProcessId) -> Option<Box<Process>> {
139 let mut entries = self.entries.lock();
140
141 if let Some(entry) = entries.remove(&pid) {
142 self.process_count
143 .fetch_sub(1, core::sync::atomic::Ordering::Relaxed);
144 Some(entry.process)
145 } else {
146 None
147 }
148 }
149
150 #[cfg(not(feature = "alloc"))]
152 pub fn remove_process(&self, pid: ProcessId) -> Option<Process> {
153 let mut entries = self.entries.lock();
154
155 for i in 0..super::MAX_PROCESSES {
156 if let Some(ref process) = entries.processes[i] {
157 if process.pid == pid {
158 let process = entries.processes[i].take();
159 entries.count -= 1;
160 self.process_count
161 .fetch_sub(1, core::sync::atomic::Ordering::Relaxed);
162 return process;
163 }
164 }
165 }
166
167 None
168 }
169
170 #[cfg(feature = "alloc")]
172 pub fn get_process(&self, pid: ProcessId) -> Option<&'static Process> {
173 let entries = self.entries.lock();
174
175 entries.get(&pid).map(|entry| {
176 unsafe { &*(entry.process.as_ref() as *const Process) }
182 })
183 }
184
185 #[cfg(not(feature = "alloc"))]
187 pub fn get_process(&self, pid: ProcessId) -> Option<&'static Process> {
188 let entries = self.entries.lock();
189
190 for i in 0..super::MAX_PROCESSES {
191 if let Some(ref process) = entries.processes[i] {
192 if process.pid == pid {
193 return Some(unsafe { &*(process as *const Process) });
198 }
199 }
200 }
201
202 None
203 }
204
205 #[cfg(feature = "alloc")]
207 pub fn get_process_mut(&self, pid: ProcessId) -> Option<&'static mut Process> {
208 let mut entries = self.entries.lock();
209
210 entries.get_mut(&pid).map(|entry| {
211 unsafe { &mut *(entry.process.as_mut() as *mut Process) }
217 })
218 }
219
220 pub fn exists(&self, pid: ProcessId) -> bool {
222 #[cfg(feature = "alloc")]
223 {
224 self.entries.lock().contains_key(&pid)
225 }
226
227 #[cfg(not(feature = "alloc"))]
228 {
229 let entries = self.entries.lock();
230 for i in 0..super::MAX_PROCESSES {
231 if let Some(ref process) = entries.processes[i] {
232 if process.pid == pid {
233 return true;
234 }
235 }
236 }
237 false
238 }
239 }
240
241 pub fn count(&self) -> usize {
243 self.process_count
244 .load(core::sync::atomic::Ordering::Relaxed)
245 }
246
247 #[cfg(feature = "alloc")]
249 pub fn find_children(&self, parent_pid: ProcessId) -> Vec<ProcessId> {
250 let entries = self.entries.lock();
251 let mut children = Vec::new();
252
253 for (pid, entry) in entries.iter() {
254 if entry.process.parent == Some(parent_pid) {
255 children.push(*pid);
256 }
257 }
258
259 children
260 }
261
262 #[cfg(feature = "alloc")]
264 pub fn for_each<F>(&self, mut f: F)
265 where
266 F: FnMut(&Process),
267 {
268 let entries = self.entries.lock();
269 for (_, entry) in entries.iter() {
270 f(&entry.process);
271 }
272 }
273
274 #[cfg(feature = "alloc")]
276 pub fn find_by_state(&self, state: ProcessState) -> Vec<ProcessId> {
277 let entries = self.entries.lock();
278 let mut results = Vec::new();
279
280 for (pid, entry) in entries.iter() {
281 if entry.process.get_state() == state {
282 results.push(*pid);
283 }
284 }
285
286 results
287 }
288
289 #[cfg(feature = "alloc")]
291 pub fn reap_zombies(&self) -> Vec<(ProcessId, i32)> {
292 let mut results = Vec::new();
293 let zombies = self.find_by_state(ProcessState::Zombie);
294
295 for pid in zombies {
296 if let Some(process) = self.remove_process(pid) {
297 results.push((pid, process.get_exit_code()));
298 }
299 }
300
301 results
302 }
303}
304
305pub(crate) static PROCESS_TABLE: ProcessTable = ProcessTable::new();
307
308pub fn init() {
310 println!("[PROCESS] Process table initialized");
311}
312
313pub fn get_process(pid: ProcessId) -> Option<&'static Process> {
315 PROCESS_TABLE.get_process(pid)
316}
317
318#[cfg(feature = "alloc")]
320pub fn get_process_mut(pid: ProcessId) -> Option<&'static mut Process> {
321 PROCESS_TABLE.get_process_mut(pid)
322}
323
324pub fn add_process(process: Process) -> Result<ProcessId, KernelError> {
326 PROCESS_TABLE.add_process(process)
327}
328
329#[cfg(feature = "alloc")]
331pub fn remove_process(pid: ProcessId) -> Option<Box<Process>> {
332 PROCESS_TABLE.remove_process(pid)
333}
334
335pub fn process_exists(pid: ProcessId) -> bool {
337 PROCESS_TABLE.exists(pid)
338}
339
340pub fn process_count() -> usize {
342 PROCESS_TABLE.count()
343}