feat(domain): add Process constructor, accessors, and thread slot management
This commit is contained in:
@@ -8,4 +8,5 @@ pub enum KernelError {
|
|||||||
NoFreeSlot,
|
NoFreeSlot,
|
||||||
InvalidProcess(ProcessId),
|
InvalidProcess(ProcessId),
|
||||||
WouldBlock,
|
WouldBlock,
|
||||||
|
TooManyThreadsInProcess,
|
||||||
}
|
}
|
||||||
|
|||||||
73
crates/domain/src/process/mod.rs
Normal file
73
crates/domain/src/process/mod.rs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
use types::{
|
||||||
|
bounded::CapSlot,
|
||||||
|
id::{ProcessId, ThreadId},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::capability::CapabilityTable;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "tests.rs"]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub const MAX_THREADS_PER_PROCESS: usize = 4;
|
||||||
|
|
||||||
|
pub struct Process {
|
||||||
|
id: ProcessId,
|
||||||
|
capabilities: CapabilityTable,
|
||||||
|
threads: [Option<ThreadId>; MAX_THREADS_PER_PROCESS],
|
||||||
|
fault_handler: Option<CapSlot>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Process {
|
||||||
|
pub fn new(
|
||||||
|
id: ProcessId,
|
||||||
|
capabilities: CapabilityTable,
|
||||||
|
fault_handler: Option<CapSlot>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
capabilities,
|
||||||
|
threads: [None; MAX_THREADS_PER_PROCESS],
|
||||||
|
fault_handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> ProcessId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn capabilities(&self) -> &CapabilityTable {
|
||||||
|
&self.capabilities
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn capabilities_mut(&mut self) -> &mut CapabilityTable {
|
||||||
|
&mut self.capabilities
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fault_handler(&self) -> Option<CapSlot> {
|
||||||
|
self.fault_handler
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_thread(&mut self, thread: ThreadId) -> Result<(), crate::error::KernelError> {
|
||||||
|
let slot = self
|
||||||
|
.threads
|
||||||
|
.iter_mut()
|
||||||
|
.find(|s| s.is_none())
|
||||||
|
.ok_or(crate::error::KernelError::TooManyThreadsInProcess)?;
|
||||||
|
*slot = Some(thread);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_thread(&mut self, thread: ThreadId) {
|
||||||
|
for slot in &mut self.threads {
|
||||||
|
if *slot == Some(thread) {
|
||||||
|
*slot = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn thread_ids(&self) -> impl Iterator<Item = ThreadId> + '_ {
|
||||||
|
self.threads.iter().filter_map(|s| *s)
|
||||||
|
}
|
||||||
|
}
|
||||||
78
crates/domain/src/process/tests.rs
Normal file
78
crates/domain/src/process/tests.rs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::capability::CapabilityTable;
|
||||||
|
use types::bounded::CapSlot;
|
||||||
|
use types::id::{ProcessId, ThreadId};
|
||||||
|
|
||||||
|
fn thread(id: u16) -> ThreadId {
|
||||||
|
ThreadId::from_raw(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_process(id: u16) -> Process {
|
||||||
|
Process::new(ProcessId::from_raw(id), CapabilityTable::new(), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new_process_has_no_threads() {
|
||||||
|
let p = test_process(0);
|
||||||
|
assert_eq!(p.thread_ids().count(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn id_matches_construction() {
|
||||||
|
let p = test_process(42);
|
||||||
|
assert_eq!(p.id(), ProcessId::from_raw(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fault_handler_none_by_default() {
|
||||||
|
let p = test_process(0);
|
||||||
|
assert!(p.fault_handler().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fault_handler_preserved() {
|
||||||
|
let slot = CapSlot::new(5).unwrap();
|
||||||
|
let p = Process::new(ProcessId::from_raw(0), CapabilityTable::new(), Some(slot));
|
||||||
|
assert_eq!(p.fault_handler(), Some(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_and_iterate_threads() {
|
||||||
|
let mut p = test_process(0);
|
||||||
|
p.add_thread(thread(0)).unwrap();
|
||||||
|
p.add_thread(thread(1)).unwrap();
|
||||||
|
assert_eq!(p.thread_ids().count(), 2);
|
||||||
|
assert!(p.thread_ids().any(|t| t == thread(0)));
|
||||||
|
assert!(p.thread_ids().any(|t| t == thread(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_thread_beyond_max_fails() {
|
||||||
|
let mut p = test_process(0);
|
||||||
|
for i in 0..MAX_THREADS_PER_PROCESS {
|
||||||
|
p.add_thread(thread(i as u16)).unwrap();
|
||||||
|
}
|
||||||
|
assert!(p.add_thread(thread(99)).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_thread_frees_slot() {
|
||||||
|
let mut p = test_process(0);
|
||||||
|
p.add_thread(thread(0)).unwrap();
|
||||||
|
p.remove_thread(thread(0));
|
||||||
|
assert_eq!(p.thread_ids().count(), 0);
|
||||||
|
p.add_thread(thread(1)).unwrap();
|
||||||
|
assert_eq!(p.thread_ids().count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capabilities_accessible() {
|
||||||
|
let p = test_process(0);
|
||||||
|
let _caps = p.capabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capabilities_mut_accessible() {
|
||||||
|
let mut p = test_process(0);
|
||||||
|
let _caps = p.capabilities_mut();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user