1use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
7
8#[cfg(feature = "alloc")]
9extern crate alloc;
10
11#[cfg(feature = "alloc")]
12use alloc::{collections::BTreeMap, string::String, vec::Vec};
13
14use spin::Mutex;
15
16use super::thread::{Thread, ThreadId};
17#[allow(unused_imports)]
18use crate::{
19 cap::{CapabilityId, CapabilitySpace},
20 error::KernelError,
21 fs::file::FileTable,
22 ipc::EndpointId,
23 mm::VirtualAddressSpace,
24 println,
25};
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct ProcessId(pub u64);
30
31impl core::fmt::Display for ProcessId {
32 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33 write!(f, "{}", self.0)
34 }
35}
36
37#[repr(u8)]
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum ProcessState {
41 Creating = 0,
43 Ready = 1,
45 Running = 2,
47 Blocked = 3,
49 Sleeping = 4,
51 Zombie = 5,
53 Dead = 6,
55}
56
57#[repr(u8)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
60pub enum ProcessPriority {
61 RealTime = 0,
63 System = 1,
65 Normal = 2,
67 Low = 3,
69 Idle = 4,
71}
72
73pub struct Process {
75 pub pid: ProcessId,
77
78 pub parent: Option<ProcessId>,
80
81 #[cfg(feature = "alloc")]
83 pub name: String,
84
85 pub state: AtomicU32,
87
88 pub priority: Mutex<ProcessPriority>,
90
91 pub memory_space: Mutex<VirtualAddressSpace>,
93
94 pub capability_space: Mutex<CapabilitySpace>,
96
97 pub file_table: Mutex<FileTable>,
99
100 #[cfg(feature = "alloc")]
102 pub threads: Mutex<BTreeMap<ThreadId, Thread>>,
103
104 #[cfg(feature = "alloc")]
106 pub ipc_endpoints: Mutex<BTreeMap<EndpointId, CapabilityId>>,
107
108 #[cfg(feature = "alloc")]
110 pub children: Mutex<Vec<ProcessId>>,
111
112 pub exit_code: AtomicU32,
114
115 pub cpu_time: AtomicU64,
117
118 pub memory_stats: MemoryStats,
120
121 pub created_at: u64,
123
124 pub uid: u32,
126
127 pub gid: u32,
129
130 pub pgid: AtomicU64,
132
133 pub sid: AtomicU64,
135
136 #[cfg(feature = "alloc")]
138 pub env_vars: Mutex<alloc::collections::BTreeMap<String, String>>,
139
140 pub signal_handlers: Mutex<[u64; 32]>,
143
144 pub pending_signals: AtomicU64,
146
147 pub signal_mask: AtomicU64,
149
150 pub umask: AtomicU32,
152
153 pub tls_fs_base: AtomicU64,
157
158 pub container_id: AtomicU64,
161
162 pub clear_child_tid: AtomicU64,
165
166 pub robust_list_head: AtomicU64,
169}
170
171#[derive(Debug, Default)]
173pub struct MemoryStats {
174 pub virtual_size: AtomicU64,
176 pub resident_size: AtomicU64,
178 pub shared_size: AtomicU64,
180}
181
182impl Process {
183 #[cfg(feature = "alloc")]
185 pub fn new(
186 pid: ProcessId,
187 parent: Option<ProcessId>,
188 name: String,
189 priority: ProcessPriority,
190 ) -> Self {
191 Self {
192 pid,
193 parent,
194 name,
195 state: AtomicU32::new(ProcessState::Creating as u32),
196 priority: Mutex::new(priority),
197 memory_space: Mutex::new(VirtualAddressSpace::new()),
198 capability_space: Mutex::new(CapabilitySpace::new()),
199 file_table: Mutex::new(FileTable::new()),
200 threads: Mutex::new(BTreeMap::new()),
201 ipc_endpoints: Mutex::new(BTreeMap::new()),
202 children: Mutex::new(Vec::new()),
203 exit_code: AtomicU32::new(0),
204 cpu_time: AtomicU64::new(0),
205 memory_stats: MemoryStats::default(),
206 created_at: crate::arch::timer::get_ticks(),
207 uid: 0,
208 gid: 0,
209 pgid: AtomicU64::new(pid.0),
210 sid: AtomicU64::new(pid.0),
211 env_vars: Mutex::new(BTreeMap::new()),
212 signal_handlers: Mutex::new([0u64; 32]),
213 pending_signals: AtomicU64::new(0),
214 signal_mask: AtomicU64::new(0),
215 umask: AtomicU32::new(0o022),
216 tls_fs_base: AtomicU64::new(0),
217 container_id: AtomicU64::new(0),
218 clear_child_tid: AtomicU64::new(0),
219 robust_list_head: AtomicU64::new(0),
220 }
221 }
222
223 pub fn get_state(&self) -> ProcessState {
225 match self.state.load(Ordering::Acquire) {
226 0 => ProcessState::Creating,
227 1 => ProcessState::Ready,
228 2 => ProcessState::Running,
229 3 => ProcessState::Blocked,
230 4 => ProcessState::Sleeping,
231 5 => ProcessState::Zombie,
232 6 => ProcessState::Dead,
233 _ => ProcessState::Dead,
234 }
235 }
236
237 pub fn set_state(&self, state: ProcessState) {
239 self.state.store(state as u32, Ordering::Release);
240 }
241
242 #[cfg(feature = "alloc")]
244 pub fn get_main_thread_id(&self) -> Option<ThreadId> {
245 let threads = self.threads.lock();
246 threads.values().min_by_key(|t| t.tid.0).map(|t| t.tid)
248 }
249
250 #[cfg(feature = "alloc")]
252 pub fn add_thread(&self, thread: Thread) -> Result<(), KernelError> {
253 let tid = thread.tid;
254 let mut threads = self.threads.lock();
255
256 if threads.len() >= super::MAX_THREADS_PER_PROCESS {
257 return Err(KernelError::ResourceExhausted {
258 resource: "threads per process",
259 });
260 }
261
262 if threads.contains_key(&tid) {
263 return Err(KernelError::AlreadyExists {
264 resource: "thread",
265 id: tid.0,
266 });
267 }
268
269 threads.insert(tid, thread);
270 Ok(())
271 }
272
273 #[cfg(feature = "alloc")]
275 pub fn remove_thread(&self, tid: ThreadId) -> Option<Thread> {
276 self.threads.lock().remove(&tid)
277 }
278
279 #[cfg(feature = "alloc")]
281 pub fn get_thread(&self, tid: ThreadId) -> Option<&Thread> {
282 unsafe {
290 let threads = self.threads.lock();
291 threads.get(&tid).map(|t| &*(t as *const Thread))
292 }
293 }
294
295 #[cfg(feature = "alloc")]
297 pub fn thread_count(&self) -> usize {
298 self.threads.lock().len()
299 }
300
301 pub fn is_alive(&self) -> bool {
303 !matches!(self.get_state(), ProcessState::Dead | ProcessState::Zombie)
304 }
305
306 pub fn add_cpu_time(&self, microseconds: u64) {
308 self.cpu_time.fetch_add(microseconds, Ordering::Relaxed);
309 }
310
311 pub fn get_cpu_time(&self) -> u64 {
313 self.cpu_time.load(Ordering::Relaxed)
314 }
315
316 pub fn set_exit_code(&self, code: i32) {
318 self.exit_code.store(code as u32, Ordering::Release);
319 }
320
321 pub fn get_exit_code(&self) -> i32 {
323 self.exit_code.load(Ordering::Acquire) as i32
324 }
325
326 pub fn set_priority(&self, new_priority: ProcessPriority) {
328 *self.priority.lock() = new_priority;
329 }
330
331 pub fn set_clear_child_tid(&self, addr: usize) {
336 self.clear_child_tid.store(addr as u64, Ordering::Release);
337 }
338
339 pub fn set_robust_list(&self, addr: usize) {
343 self.robust_list_head.store(addr as u64, Ordering::Release);
344 }
345
346 pub fn memory_space_mut(&mut self) -> Option<&mut VirtualAddressSpace> {
348 Some(self.memory_space.get_mut())
349 }
350
351 #[cfg(feature = "alloc")]
353 pub fn set_name(&mut self, name: String) {
354 self.name = name;
355 }
356
357 #[cfg(feature = "alloc")]
359 pub fn get_main_thread_mut(&mut self) -> Option<&mut Thread> {
360 self.threads.get_mut().values_mut().next()
361 }
362
363 pub fn reset_signal_handlers(&self) {
365 let mut handlers = self.signal_handlers.lock();
366 for handler in handlers.iter_mut() {
367 *handler = 0; }
369 self.pending_signals.store(0, Ordering::Release);
371 }
372
373 pub fn set_signal_handler(&self, signum: usize, handler: u64) -> Result<u64, KernelError> {
376 if signum >= 32 {
377 return Err(KernelError::InvalidArgument {
378 name: "signum",
379 value: "signal number out of range (0-31)",
380 });
381 }
382 if signum == 9 || signum == 19 {
384 return Err(KernelError::PermissionDenied {
385 operation: "change handler for SIGKILL or SIGSTOP",
386 });
387 }
388 let mut handlers = self.signal_handlers.lock();
389 let old = handlers[signum];
390 handlers[signum] = handler;
391 Ok(old)
392 }
393
394 pub fn get_signal_handler(&self, signum: usize) -> Option<u64> {
396 if signum >= 32 {
397 return None;
398 }
399 Some(self.signal_handlers.lock()[signum])
400 }
401
402 pub fn send_signal(&self, signum: usize) -> Result<(), KernelError> {
404 if signum >= 32 {
405 return Err(KernelError::InvalidArgument {
406 name: "signum",
407 value: "signal number out of range (0-31)",
408 });
409 }
410 let mask = 1u64 << signum;
412 self.pending_signals.fetch_or(mask, Ordering::AcqRel);
413 Ok(())
414 }
415
416 pub fn is_signal_pending(&self, signum: usize) -> bool {
418 if signum >= 32 {
419 return false;
420 }
421 let pending = self.pending_signals.load(Ordering::Acquire);
422 let mask = self.signal_mask.load(Ordering::Acquire);
423 let effective_pending = pending & !mask;
424 (effective_pending & (1u64 << signum)) != 0
425 }
426
427 pub fn get_next_pending_signal(&self) -> Option<usize> {
429 let pending = self.pending_signals.load(Ordering::Acquire);
430 let mask = self.signal_mask.load(Ordering::Acquire);
431 let effective_pending = pending & !mask;
432 if effective_pending == 0 {
433 return None;
434 }
435 Some(effective_pending.trailing_zeros() as usize)
437 }
438
439 pub fn clear_pending_signal(&self, signum: usize) {
441 if signum < 32 {
442 let mask = !(1u64 << signum);
443 self.pending_signals.fetch_and(mask, Ordering::AcqRel);
444 }
445 }
446
447 pub fn set_signal_mask(&self, new_mask: u64) -> u64 {
449 let protected = (1u64 << 9) | (1u64 << 19);
451 let actual_mask = new_mask & !protected;
452 self.signal_mask.swap(actual_mask, Ordering::AcqRel)
453 }
454
455 pub fn get_signal_mask(&self) -> u64 {
457 self.signal_mask.load(Ordering::Acquire)
458 }
459}
460
461impl Drop for Process {
462 fn drop(&mut self) {
463 println!("[PROCESS] Dropping process {}", self.pid.0);
464 }
466}
467
468#[cfg(test)]
469mod tests {
470 use super::*;
471
472 fn make_process(pid: u64, name: &str) -> Process {
473 Process::new(
474 ProcessId(pid),
475 None,
476 alloc::string::String::from(name),
477 ProcessPriority::Normal,
478 )
479 }
480
481 #[test]
484 fn test_initial_state_is_creating() {
485 let proc = make_process(1, "test");
486 assert_eq!(proc.get_state(), ProcessState::Creating);
487 }
488
489 #[test]
490 fn test_state_transitions() {
491 let proc = make_process(2, "test_transitions");
492
493 proc.set_state(ProcessState::Ready);
494 assert_eq!(proc.get_state(), ProcessState::Ready);
495
496 proc.set_state(ProcessState::Running);
497 assert_eq!(proc.get_state(), ProcessState::Running);
498
499 proc.set_state(ProcessState::Blocked);
500 assert_eq!(proc.get_state(), ProcessState::Blocked);
501
502 proc.set_state(ProcessState::Sleeping);
503 assert_eq!(proc.get_state(), ProcessState::Sleeping);
504
505 proc.set_state(ProcessState::Zombie);
506 assert_eq!(proc.get_state(), ProcessState::Zombie);
507
508 proc.set_state(ProcessState::Dead);
509 assert_eq!(proc.get_state(), ProcessState::Dead);
510 }
511
512 #[test]
513 fn test_get_state_unknown_value() {
514 let proc = make_process(3, "unknown_state");
515 proc.state.store(255, Ordering::Release);
517 assert_eq!(proc.get_state(), ProcessState::Dead);
519 }
520
521 #[test]
524 fn test_is_alive_creating() {
525 let proc = make_process(4, "alive_test");
526 assert!(proc.is_alive());
527 }
528
529 #[test]
530 fn test_is_alive_ready() {
531 let proc = make_process(5, "alive_ready");
532 proc.set_state(ProcessState::Ready);
533 assert!(proc.is_alive());
534 }
535
536 #[test]
537 fn test_is_alive_running() {
538 let proc = make_process(6, "alive_running");
539 proc.set_state(ProcessState::Running);
540 assert!(proc.is_alive());
541 }
542
543 #[test]
544 fn test_is_not_alive_zombie() {
545 let proc = make_process(7, "zombie");
546 proc.set_state(ProcessState::Zombie);
547 assert!(!proc.is_alive());
548 }
549
550 #[test]
551 fn test_is_not_alive_dead() {
552 let proc = make_process(8, "dead");
553 proc.set_state(ProcessState::Dead);
554 assert!(!proc.is_alive());
555 }
556
557 #[test]
560 fn test_cpu_time_initial_zero() {
561 let proc = make_process(10, "cpu_time");
562 assert_eq!(proc.get_cpu_time(), 0);
563 }
564
565 #[test]
566 fn test_add_cpu_time() {
567 let proc = make_process(11, "cpu_time_add");
568 proc.add_cpu_time(100);
569 assert_eq!(proc.get_cpu_time(), 100);
570 proc.add_cpu_time(200);
571 assert_eq!(proc.get_cpu_time(), 300);
572 }
573
574 #[test]
577 fn test_exit_code_initial_zero() {
578 let proc = make_process(12, "exit_code");
579 assert_eq!(proc.get_exit_code(), 0);
580 }
581
582 #[test]
583 fn test_set_exit_code() {
584 let proc = make_process(13, "exit_set");
585 proc.set_exit_code(42);
586 assert_eq!(proc.get_exit_code(), 42);
587 }
588
589 #[test]
590 fn test_set_exit_code_negative() {
591 let proc = make_process(14, "exit_neg");
592 proc.set_exit_code(-1);
593 assert_eq!(proc.get_exit_code(), -1);
594 }
595
596 #[test]
599 fn test_initial_priority() {
600 let proc = make_process(15, "priority");
601 assert_eq!(*proc.priority.lock(), ProcessPriority::Normal);
602 }
603
604 #[test]
605 fn test_set_priority() {
606 let proc = make_process(16, "priority_set");
607 proc.set_priority(ProcessPriority::RealTime);
608 assert_eq!(*proc.priority.lock(), ProcessPriority::RealTime);
609
610 proc.set_priority(ProcessPriority::Idle);
611 assert_eq!(*proc.priority.lock(), ProcessPriority::Idle);
612 }
613
614 #[test]
617 fn test_signal_handler_default() {
618 let proc = make_process(20, "sig_default");
619 for i in 0..32 {
621 assert_eq!(proc.get_signal_handler(i), Some(0));
622 }
623 }
624
625 #[test]
626 fn test_signal_handler_invalid_signal() {
627 let proc = make_process(21, "sig_invalid");
628 assert_eq!(proc.get_signal_handler(32), None);
629 assert_eq!(proc.get_signal_handler(100), None);
630 }
631
632 #[test]
633 fn test_set_signal_handler() {
634 let proc = make_process(22, "sig_set");
635 let result = proc.set_signal_handler(2, 0xDEAD_BEEF);
636 assert!(result.is_ok());
637 assert_eq!(result.unwrap(), 0); assert_eq!(proc.get_signal_handler(2), Some(0xDEAD_BEEF));
639 }
640
641 #[test]
642 fn test_set_signal_handler_sigkill_refused() {
643 let proc = make_process(23, "sig_kill");
644 let result = proc.set_signal_handler(9, 1); assert!(result.is_err());
646 assert_eq!(
647 result.unwrap_err(),
648 KernelError::PermissionDenied {
649 operation: "change handler for SIGKILL or SIGSTOP",
650 }
651 );
652 }
653
654 #[test]
655 fn test_set_signal_handler_sigstop_refused() {
656 let proc = make_process(24, "sig_stop");
657 let result = proc.set_signal_handler(19, 1); assert!(result.is_err());
659 }
660
661 #[test]
662 fn test_set_signal_handler_out_of_range() {
663 let proc = make_process(25, "sig_range");
664 let result = proc.set_signal_handler(32, 1);
665 assert!(result.is_err());
666 }
667
668 #[test]
669 fn test_send_signal() {
670 let proc = make_process(26, "sig_send");
671 assert!(proc.send_signal(2).is_ok());
672 assert!(proc.is_signal_pending(2));
673 }
674
675 #[test]
676 fn test_send_signal_invalid() {
677 let proc = make_process(27, "sig_send_inv");
678 assert!(proc.send_signal(32).is_err());
679 }
680
681 #[test]
682 fn test_signal_pending_with_mask() {
683 let proc = make_process(28, "sig_mask");
684 proc.send_signal(3).unwrap();
685
686 assert!(proc.is_signal_pending(3));
688
689 proc.set_signal_mask(1u64 << 3);
691
692 assert!(!proc.is_signal_pending(3));
694 }
695
696 #[test]
697 fn test_signal_mask_protects_sigkill_sigstop() {
698 let proc = make_process(29, "sig_mask_protect");
699 let old = proc.set_signal_mask(0xFFFF_FFFF_FFFF_FFFF);
701 assert_eq!(old, 0); let mask = proc.get_signal_mask();
705 assert_eq!(mask & (1u64 << 9), 0, "SIGKILL should not be maskable");
706 assert_eq!(mask & (1u64 << 19), 0, "SIGSTOP should not be maskable");
707 }
708
709 #[test]
710 fn test_get_next_pending_signal() {
711 let proc = make_process(30, "sig_next");
712 assert!(proc.get_next_pending_signal().is_none());
713
714 proc.send_signal(5).unwrap();
715 proc.send_signal(3).unwrap();
716
717 assert_eq!(proc.get_next_pending_signal(), Some(3));
719 }
720
721 #[test]
722 fn test_clear_pending_signal() {
723 let proc = make_process(31, "sig_clear");
724 proc.send_signal(7).unwrap();
725 assert!(proc.is_signal_pending(7));
726
727 proc.clear_pending_signal(7);
728 assert!(!proc.is_signal_pending(7));
729 }
730
731 #[test]
732 fn test_reset_signal_handlers() {
733 let proc = make_process(32, "sig_reset");
734 proc.set_signal_handler(2, 0x1000).unwrap();
736 proc.set_signal_handler(15, 0x2000).unwrap();
737 proc.send_signal(5).unwrap();
738
739 proc.reset_signal_handlers();
740
741 assert_eq!(proc.get_signal_handler(2), Some(0));
743 assert_eq!(proc.get_signal_handler(15), Some(0));
744 assert!(!proc.is_signal_pending(5));
746 }
747
748 #[test]
751 fn test_process_pid() {
752 let proc = make_process(100, "pid_test");
753 assert_eq!(proc.pid, ProcessId(100));
754 }
755
756 #[test]
757 fn test_process_parent() {
758 let proc = Process::new(
759 ProcessId(50),
760 Some(ProcessId(1)),
761 alloc::string::String::from("child"),
762 ProcessPriority::Normal,
763 );
764 assert_eq!(proc.parent, Some(ProcessId(1)));
765 }
766
767 #[test]
768 fn test_process_no_parent() {
769 let proc = make_process(1, "init");
770 assert_eq!(proc.parent, None);
771 }
772
773 #[test]
774 fn test_process_name() {
775 let mut proc = make_process(60, "original_name");
776 assert_eq!(proc.name, "original_name");
777
778 proc.set_name(alloc::string::String::from("new_name"));
779 assert_eq!(proc.name, "new_name");
780 }
781
782 #[test]
785 fn test_thread_count_initially_zero() {
786 let proc = make_process(70, "threads");
787 assert_eq!(proc.thread_count(), 0);
788 }
789
790 #[test]
793 fn test_process_id_display() {
794 let pid = ProcessId(42);
795 let display = alloc::format!("{}", pid);
796 assert_eq!(display, "42");
797 }
798
799 #[test]
802 fn test_priority_ordering() {
803 assert!(ProcessPriority::RealTime < ProcessPriority::System);
804 assert!(ProcessPriority::System < ProcessPriority::Normal);
805 assert!(ProcessPriority::Normal < ProcessPriority::Low);
806 assert!(ProcessPriority::Low < ProcessPriority::Idle);
807 }
808}
809
810#[cfg(feature = "alloc")]
812pub struct ProcessBuilder {
813 name: String,
814 parent: Option<ProcessId>,
815 priority: ProcessPriority,
816 uid: u32,
817 gid: u32,
818}
819
820#[cfg(feature = "alloc")]
821impl ProcessBuilder {
822 pub fn new(name: String) -> Self {
824 Self {
825 name,
826 parent: None,
827 priority: ProcessPriority::Normal,
828 uid: 0,
829 gid: 0,
830 }
831 }
832
833 pub fn parent(mut self, pid: ProcessId) -> Self {
835 self.parent = Some(pid);
836 self
837 }
838
839 pub fn priority(mut self, priority: ProcessPriority) -> Self {
841 self.priority = priority;
842 self
843 }
844
845 pub fn uid(mut self, uid: u32) -> Self {
847 self.uid = uid;
848 self
849 }
850
851 pub fn gid(mut self, gid: u32) -> Self {
853 self.gid = gid;
854 self
855 }
856
857 pub fn build(self) -> Process {
865 let pid = super::alloc_pid();
866 let mut process = Process::new(pid, self.parent, self.name, self.priority);
867 process.uid = self.uid;
868 process.gid = self.gid;
869 process
870 }
871
872 pub fn build_with_address_space(self) -> Result<Process, KernelError> {
878 let pid = super::alloc_pid();
879 let mut process = Process::new(pid, self.parent, self.name, self.priority);
880 process.uid = self.uid;
881 process.gid = self.gid;
882
883 {
886 let mut memory_space = process.memory_space.lock();
887 memory_space.init()?;
888 }
889
890 println!(
891 "[PROCESS] Created process {} with initialized address space",
892 pid.0
893 );
894
895 Ok(process)
896 }
897}