From 42ed5ade294f1c52709886c1f83ff4dccc2c0b2c Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sat, 17 Oct 2026 23:27:28 +0200 Subject: [PATCH] feat(domain): add ProcessTable with create, get, and destroy --- crates/domain/src/error.rs | 1 + crates/domain/src/process/mod.rs | 59 ++++++++++++++++++++++++++++-- crates/domain/src/process/tests.rs | 52 ++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 3 deletions(-) diff --git a/crates/domain/src/error.rs b/crates/domain/src/error.rs index 6272965..134cd86 100644 --- a/crates/domain/src/error.rs +++ b/crates/domain/src/error.rs @@ -9,4 +9,5 @@ pub enum KernelError { InvalidProcess(ProcessId), WouldBlock, TooManyThreadsInProcess, + TooManyProcesses, } diff --git a/crates/domain/src/process/mod.rs b/crates/domain/src/process/mod.rs index cf9c0f2..c717ed8 100644 --- a/crates/domain/src/process/mod.rs +++ b/crates/domain/src/process/mod.rs @@ -3,13 +3,14 @@ use types::{ id::{ProcessId, ThreadId}, }; -use crate::capability::CapabilityTable; +use crate::{capability::CapabilityTable, error::KernelError}; #[cfg(test)] #[path = "tests.rs"] mod tests; pub const MAX_THREADS_PER_PROCESS: usize = 4; +pub const MAX_PROCESSES: usize = 64; pub struct Process { id: ProcessId, @@ -48,12 +49,12 @@ impl Process { self.fault_handler } - pub fn add_thread(&mut self, thread: ThreadId) -> Result<(), crate::error::KernelError> { + pub fn add_thread(&mut self, thread: ThreadId) -> Result<(), KernelError> { let slot = self .threads .iter_mut() .find(|s| s.is_none()) - .ok_or(crate::error::KernelError::TooManyThreadsInProcess)?; + .ok_or(KernelError::TooManyThreadsInProcess)?; *slot = Some(thread); Ok(()) } @@ -71,3 +72,55 @@ impl Process { self.threads.iter().filter_map(|s| *s) } } + +pub struct ProcessTable { + processes: [Option; MAX_PROCESSES], +} + +impl ProcessTable { + pub fn new() -> Self { + Self { + processes: [const { None }; MAX_PROCESSES], + } + } + + pub fn create( + &mut self, + capabilities: CapabilityTable, + fault_handler: Option, + ) -> Result { + let idx = self + .processes + .iter() + .position(|s| s.is_none()) + .ok_or(KernelError::TooManyProcesses)?; + + let id = ProcessId::from_raw(idx as u16); + self.processes[idx] = Some(Process::new(id, capabilities, fault_handler)); + Ok(id) + } + + pub fn get(&self, id: ProcessId) -> Result<&Process, KernelError> { + let idx = id.raw() as usize; + self.processes + .get(idx) + .and_then(|s| s.as_ref()) + .ok_or(KernelError::InvalidProcess(id)) + } + + pub fn get_mut(&mut self, id: ProcessId) -> Result<&mut Process, KernelError> { + let idx = id.raw() as usize; + self.processes + .get_mut(idx) + .and_then(|s| s.as_mut()) + .ok_or(KernelError::InvalidProcess(id)) + } + + pub fn destroy(&mut self, id: ProcessId) -> Result { + let idx = id.raw() as usize; + self.processes + .get_mut(idx) + .and_then(|s| s.take()) + .ok_or(KernelError::InvalidProcess(id)) + } +} diff --git a/crates/domain/src/process/tests.rs b/crates/domain/src/process/tests.rs index 3071dcc..8de051d 100644 --- a/crates/domain/src/process/tests.rs +++ b/crates/domain/src/process/tests.rs @@ -76,3 +76,55 @@ fn capabilities_mut_accessible() { let mut p = test_process(0); let _caps = p.capabilities_mut(); } + +// --- ProcessTable tests --- + +#[test] +fn table_create_and_lookup() { + let mut table = ProcessTable::new(); + let id = table.create(CapabilityTable::new(), None).unwrap(); + assert_eq!(table.get(id).unwrap().id(), id); +} + +#[test] +fn table_create_returns_unique_ids() { + let mut table = ProcessTable::new(); + let a = table.create(CapabilityTable::new(), None).unwrap(); + let b = table.create(CapabilityTable::new(), None).unwrap(); + assert_ne!(a, b); +} + +#[test] +fn table_destroy_then_get_fails() { + let mut table = ProcessTable::new(); + let id = table.create(CapabilityTable::new(), None).unwrap(); + table.destroy(id).unwrap(); + assert!(table.get(id).is_err()); +} + +#[test] +fn table_full_returns_error() { + let mut table = ProcessTable::new(); + for _ in 0..MAX_PROCESSES { + table.create(CapabilityTable::new(), None).unwrap(); + } + assert!(table.create(CapabilityTable::new(), None).is_err()); +} + +#[test] +fn table_destroy_reuses_slot() { + let mut table = ProcessTable::new(); + let id = table.create(CapabilityTable::new(), None).unwrap(); + table.destroy(id).unwrap(); + let new_id = table.create(CapabilityTable::new(), None).unwrap(); + assert_eq!(id, new_id); +} + +#[test] +fn table_get_mut_allows_modification() { + let mut table = ProcessTable::new(); + let id = table.create(CapabilityTable::new(), None).unwrap(); + let p = table.get_mut(id).unwrap(); + p.add_thread(thread(0)).unwrap(); + assert_eq!(table.get(id).unwrap().thread_ids().count(), 1); +}