1use alloc::{collections::BTreeMap, string::String, vec, vec::Vec};
6use core::sync::atomic::{AtomicU64, Ordering};
7
8use spin::RwLock;
9
10use crate::{
11 error::KernelError,
12 process::{ProcessId, ProcessPriority},
13};
14
15#[derive(Debug, Clone)]
17pub struct ResourceLimits {
18 pub max_memory: u64, pub max_cpu_time: u64, pub max_files: u32, pub max_threads: u32, pub nice_value: i8, pub stack_size: u64, pub core_size: u64, }
26
27impl Default for ResourceLimits {
28 fn default() -> Self {
29 Self {
30 max_memory: 256 * 1024 * 1024, max_cpu_time: u64::MAX, max_files: 1024, max_threads: 256, nice_value: 0, stack_size: 8 * 1024 * 1024, core_size: 0, }
38 }
39}
40
41#[derive(Debug, Clone)]
43pub struct ProcessInfo {
44 pub pid: ProcessId,
45 pub ppid: ProcessId,
46 pub name: String,
47 pub state: ProcessState,
48 pub uid: u32,
49 pub gid: u32,
50 pub start_time: u64,
51 pub cpu_time: u64,
52 pub memory_usage: u64,
53 pub thread_count: u32,
54 pub priority: ProcessPriority,
55 pub exit_code: Option<i32>,
56 pub command_line: Vec<String>,
57 pub environment: Vec<String>,
58 pub working_directory: String,
59 pub session_id: u32,
60 pub terminal: Option<String>,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum ProcessState {
66 Running,
67 Sleeping,
68 Waiting,
69 Stopped,
70 Zombie,
71 Dead,
72}
73
74#[derive(Debug, Clone)]
76pub struct Session {
77 pub sid: u32,
78 pub leader: ProcessId,
79 pub terminal: Option<String>,
80 pub processes: Vec<ProcessId>,
81}
82
83#[derive(Debug, Clone)]
85pub struct ProcessGroup {
86 pub pgid: u32,
87 pub leader: ProcessId,
88 pub session_id: u32,
89 pub processes: Vec<ProcessId>,
90}
91
92pub struct ProcessServer {
94 processes: RwLock<BTreeMap<u64, ProcessInfo>>,
96
97 resource_limits: RwLock<BTreeMap<u64, ResourceLimits>>,
99
100 sessions: RwLock<BTreeMap<u32, Session>>,
102
103 process_groups: RwLock<BTreeMap<u32, ProcessGroup>>,
105
106 next_pid: AtomicU64,
108
109 next_sid: AtomicU64,
111
112 next_pgid: AtomicU64,
114
115 orphans: RwLock<Vec<ProcessId>>,
117
118 total_processes_created: AtomicU64,
120 total_processes_exited: AtomicU64,
121}
122
123impl ProcessServer {
124 pub fn new() -> Self {
126 crate::println!("[PROCESS_SERVER] Creating new ProcessServer...");
127
128 crate::println!("[PROCESS_SERVER] Creating BTreeMaps...");
129 let processes = RwLock::new(BTreeMap::new());
130 let resource_limits = RwLock::new(BTreeMap::new());
131 let sessions = RwLock::new(BTreeMap::new());
132 let process_groups = RwLock::new(BTreeMap::new());
133
134 crate::println!("[PROCESS_SERVER] Creating Vec...");
135 let orphans = RwLock::new(Vec::new());
136
137 crate::println!("[PROCESS_SERVER] Creating atomics...");
138 let next_pid = AtomicU64::new(2); let next_sid = AtomicU64::new(1);
140 let next_pgid = AtomicU64::new(1);
141 let total_processes_created = AtomicU64::new(0);
142 let total_processes_exited = AtomicU64::new(0);
143
144 crate::println!("[PROCESS_SERVER] Constructing ProcessServer...");
145 let server = Self {
146 processes,
147 resource_limits,
148 sessions,
149 process_groups,
150 next_pid,
151 next_sid,
152 next_pgid,
153 orphans,
154 total_processes_created,
155 total_processes_exited,
156 };
157
158 crate::println!("[PROCESS_SERVER] ProcessServer created successfully");
159 server
160 }
161}
162
163impl Default for ProcessServer {
164 fn default() -> Self {
165 Self::new()
166 }
167}
168
169impl ProcessServer {
170 pub fn create_process(
172 &self,
173 parent_pid: ProcessId,
174 name: String,
175 uid: u32,
176 gid: u32,
177 command_line: Vec<String>,
178 environment: Vec<String>,
179 ) -> Result<ProcessId, KernelError> {
180 let pid = ProcessId(self.next_pid.fetch_add(1, Ordering::SeqCst));
181
182 let (session_id, pgid) = {
184 let processes = self.processes.read();
185 if let Some(parent) = processes.get(&parent_pid.0) {
186 (parent.session_id, parent.session_id) } else {
188 (0, 0) }
190 };
191
192 let info = ProcessInfo {
193 pid,
194 ppid: parent_pid,
195 name: name.clone(),
196 state: ProcessState::Running,
197 uid,
198 gid,
199 start_time: self.get_system_time(),
200 cpu_time: 0,
201 memory_usage: 0,
202 thread_count: 1,
203 priority: ProcessPriority::Normal,
204 exit_code: None,
205 command_line,
206 environment,
207 working_directory: String::from("/"),
208 session_id,
209 terminal: None,
210 };
211
212 let limits = ResourceLimits::default();
214
215 self.processes.write().insert(pid.0, info);
217 self.resource_limits.write().insert(pid.0, limits);
218
219 if session_id > 0 {
221 if let Some(session) = self.sessions.write().get_mut(&session_id) {
222 session.processes.push(pid);
223 }
224 }
225
226 if pgid > 0 {
228 if let Some(pg) = self.process_groups.write().get_mut(&pgid) {
229 pg.processes.push(pid);
230 }
231 }
232
233 self.total_processes_created.fetch_add(1, Ordering::Relaxed);
234
235 crate::println!("[PROCESS_SERVER] Created process {} ({})", pid.0, name);
236 Ok(pid)
237 }
238
239 pub fn terminate_process(&self, pid: ProcessId, exit_code: i32) -> Result<(), KernelError> {
241 let mut processes = self.processes.write();
242
243 if let Some(process) = processes.get_mut(&pid.0) {
244 process.state = ProcessState::Zombie;
245 process.exit_code = Some(exit_code);
246
247 let children: Vec<ProcessId> = processes
249 .values()
250 .filter(|p| p.ppid == pid)
251 .map(|p| p.pid)
252 .collect();
253
254 for child_pid in children {
255 if let Some(child) = processes.get_mut(&child_pid.0) {
256 child.ppid = ProcessId(1); if child.state == ProcessState::Zombie {
260 self.orphans.write().push(child_pid);
261 }
262 }
263 }
264
265 self.total_processes_exited.fetch_add(1, Ordering::Relaxed);
266
267 crate::println!(
268 "[PROCESS_SERVER] Process {} terminated with code {}",
269 pid.0,
270 exit_code
271 );
272 Ok(())
273 } else {
274 Err(KernelError::ProcessNotFound { pid: pid.0 })
275 }
276 }
277
278 pub fn wait_for_child(
280 &self,
281 parent_pid: ProcessId,
282 specific_pid: Option<ProcessId>,
283 ) -> Result<(ProcessId, i32), KernelError> {
284 let mut processes = self.processes.write();
285
286 let zombie_child = processes
288 .values()
289 .find(|p| {
290 p.ppid == parent_pid
291 && p.state == ProcessState::Zombie
292 && (specific_pid.is_none() || specific_pid == Some(p.pid))
293 })
294 .map(|p| (p.pid, p.exit_code.unwrap_or(0)));
295
296 if let Some((child_pid, exit_code)) = zombie_child {
297 processes.remove(&child_pid.0);
299 self.resource_limits.write().remove(&child_pid.0);
300
301 self.remove_from_session_and_group(child_pid);
303
304 crate::println!("[PROCESS_SERVER] Reaped zombie process {}", child_pid.0);
305 Ok((child_pid, exit_code))
306 } else {
307 Err(KernelError::NotFound {
308 resource: "zombie children",
309 id: parent_pid.0,
310 })
311 }
312 }
313
314 pub fn get_process_info(&self, pid: ProcessId) -> Option<ProcessInfo> {
316 self.processes.read().get(&pid.0).cloned()
317 }
318
319 pub fn list_processes(&self) -> Vec<ProcessInfo> {
321 self.processes.read().values().cloned().collect()
322 }
323
324 pub fn set_resource_limits(
326 &self,
327 pid: ProcessId,
328 limits: ResourceLimits,
329 ) -> Result<(), KernelError> {
330 if self.processes.read().contains_key(&pid.0) {
331 self.resource_limits.write().insert(pid.0, limits);
332 Ok(())
333 } else {
334 Err(KernelError::ProcessNotFound { pid: pid.0 })
335 }
336 }
337
338 pub fn get_resource_limits(&self, pid: ProcessId) -> Option<ResourceLimits> {
340 self.resource_limits.read().get(&pid.0).cloned()
341 }
342
343 pub fn create_session(&self, leader_pid: ProcessId) -> Result<u32, KernelError> {
345 let sid = self.next_sid.fetch_add(1, Ordering::SeqCst) as u32;
346
347 let session = Session {
348 sid,
349 leader: leader_pid,
350 terminal: None,
351 processes: vec![leader_pid],
352 };
353
354 self.sessions.write().insert(sid, session);
355
356 if let Some(process) = self.processes.write().get_mut(&leader_pid.0) {
358 process.session_id = sid;
359 }
360
361 Ok(sid)
362 }
363
364 pub fn create_process_group(
366 &self,
367 leader_pid: ProcessId,
368 session_id: u32,
369 ) -> Result<u32, KernelError> {
370 let pgid = self.next_pgid.fetch_add(1, Ordering::SeqCst) as u32;
371
372 let pg = ProcessGroup {
373 pgid,
374 leader: leader_pid,
375 session_id,
376 processes: vec![leader_pid],
377 };
378
379 self.process_groups.write().insert(pgid, pg);
380 Ok(pgid)
381 }
382
383 pub fn send_signal(&self, pid: ProcessId, signal: i32) -> Result<(), KernelError> {
385 if let Some(_process) = self.processes.read().get(&pid.0) {
386 match signal {
387 9 => {
388 self.terminate_process(pid, -signal)?;
390 }
391 15 => {
392 self.terminate_process(pid, 0)?;
394 }
395 19 => {
396 if let Some(process) = self.processes.write().get_mut(&pid.0) {
398 process.state = ProcessState::Stopped;
399 }
400 }
401 18 => {
402 if let Some(process) = self.processes.write().get_mut(&pid.0) {
404 if process.state == ProcessState::Stopped {
405 process.state = ProcessState::Running;
406 }
407 }
408 }
409 _ => {
410 crate::println!(
412 "[PROCESS_SERVER] Signal {} sent to process {}",
413 signal,
414 pid.0
415 );
416 }
417 }
418 Ok(())
419 } else {
420 Err(KernelError::ProcessNotFound { pid: pid.0 })
421 }
422 }
423
424 pub fn update_process_stats(&self, pid: ProcessId, cpu_time: u64, memory_usage: u64) {
426 if let Some(process) = self.processes.write().get_mut(&pid.0) {
427 process.cpu_time = cpu_time;
428 process.memory_usage = memory_usage;
429 }
430 }
431
432 pub fn reap_zombies(&self) -> usize {
434 let mut reaped = 0;
435 let mut processes = self.processes.write();
436 let mut to_remove = Vec::new();
437
438 for (pid, process) in processes.iter() {
440 if process.state == ProcessState::Zombie
441 && (process.ppid.0 == 1 || !processes.contains_key(&process.ppid.0))
442 {
443 to_remove.push(*pid);
444 }
445 }
446
447 for pid in to_remove {
449 processes.remove(&pid);
450 self.resource_limits.write().remove(&pid);
451 self.remove_from_session_and_group(ProcessId(pid));
452 reaped += 1;
453 }
454
455 if reaped > 0 {
456 crate::println!("[PROCESS_SERVER] Reaped {} zombie processes", reaped);
457 }
458
459 reaped
460 }
461
462 pub fn get_statistics(&self) -> ProcessServerStats {
464 let processes = self.processes.read();
465 let mut running = 0;
466 let mut sleeping = 0;
467 let mut stopped = 0;
468 let mut zombies = 0;
469
470 for process in processes.values() {
471 match process.state {
472 ProcessState::Running => running += 1,
473 ProcessState::Sleeping | ProcessState::Waiting => sleeping += 1,
474 ProcessState::Stopped => stopped += 1,
475 ProcessState::Zombie => zombies += 1,
476 ProcessState::Dead => {}
477 }
478 }
479
480 ProcessServerStats {
481 total_processes: processes.len(),
482 running,
483 sleeping,
484 stopped,
485 zombies,
486 total_created: self.total_processes_created.load(Ordering::Relaxed),
487 total_exited: self.total_processes_exited.load(Ordering::Relaxed),
488 sessions: self.sessions.read().len(),
489 process_groups: self.process_groups.read().len(),
490 }
491 }
492
493 pub fn list_process_ids(&self) -> Vec<ProcessId> {
495 self.processes
496 .read()
497 .keys()
498 .map(|&pid| ProcessId(pid))
499 .collect()
500 }
501
502 pub fn notify_capability_revoked(&self, _pid: ProcessId, _cap_id: u64) {
504 crate::security::audit::log_capability_op(_pid.0, _cap_id, 2); }
510
511 fn get_system_time(&self) -> u64 {
514 crate::arch::entropy::read_timestamp() / 2000
517 }
518
519 fn remove_from_session_and_group(&self, pid: ProcessId) {
520 for session in self.sessions.write().values_mut() {
522 session.processes.retain(|&p| p != pid);
523 }
524
525 for pg in self.process_groups.write().values_mut() {
527 pg.processes.retain(|&p| p != pid);
528 }
529 }
530}
531
532#[derive(Debug)]
534pub struct ProcessServerStats {
535 pub total_processes: usize,
536 pub running: usize,
537 pub sleeping: usize,
538 pub stopped: usize,
539 pub zombies: usize,
540 pub total_created: u64,
541 pub total_exited: u64,
542 pub sessions: usize,
543 pub process_groups: usize,
544}
545
546static PROCESS_SERVER: crate::sync::once_lock::OnceLock<ProcessServer> =
548 crate::sync::once_lock::OnceLock::new();
549
550pub fn init() {
552 #[allow(unused_imports)]
553 use crate::println;
554
555 println!("[PROCESS_SERVER] Creating ProcessServer...");
556 let result = PROCESS_SERVER.set(ProcessServer::new());
557 if result.is_err() {
558 println!("[PROCESS_SERVER] WARNING: Already initialized! Skipping re-initialization.");
559 return;
560 }
561 println!("[PROCESS_SERVER] Process server initialized");
562}
563
564pub fn try_get_process_server() -> Option<&'static ProcessServer> {
568 PROCESS_SERVER.get()
569}
570
571pub fn get_process_server() -> &'static ProcessServer {
576 PROCESS_SERVER
577 .get()
578 .expect("Process server not initialized: init() was not called")
579}