diff --git a/crates/domain/src/endpoint/mod.rs b/crates/domain/src/endpoint/mod.rs index 438d51d..823558f 100644 --- a/crates/domain/src/endpoint/mod.rs +++ b/crates/domain/src/endpoint/mod.rs @@ -66,6 +66,39 @@ impl Endpoint { } } +const MAX_ENDPOINTS: usize = 256; + +pub struct EndpointTable { + endpoints: [Option; MAX_ENDPOINTS], +} + +impl EndpointTable { + pub fn new() -> Self { + Self { + endpoints: [const { None }; MAX_ENDPOINTS], + } + } + + pub fn create(&mut self) -> Option { + let idx = self.endpoints.iter().position(|s| s.is_none())?; + let id = EndpointId::from_raw(idx as u16); + self.endpoints[idx] = Some(Endpoint::new(id)); + Some(id) + } + + pub fn get(&self, id: EndpointId) -> Option<&Endpoint> { + self.endpoints.get(id.raw() as usize).and_then(|s| s.as_ref()) + } + + pub fn get_mut(&mut self, id: EndpointId) -> Option<&mut Endpoint> { + self.endpoints.get_mut(id.raw() as usize).and_then(|s| s.as_mut()) + } + + pub fn destroy(&mut self, id: EndpointId) -> Option { + self.endpoints.get_mut(id.raw() as usize).and_then(|s| s.take()) + } +} + pub trait MessagePassing { fn send( &mut self, diff --git a/crates/domain/src/endpoint/tests.rs b/crates/domain/src/endpoint/tests.rs index 76e8261..94a42d3 100644 --- a/crates/domain/src/endpoint/tests.rs +++ b/crates/domain/src/endpoint/tests.rs @@ -135,3 +135,46 @@ fn rendezvous_receiver_first() { let receiver = ep.dequeue_receiver().unwrap(); assert_eq!(receiver, thread(1)); } + +// --- EndpointTable tests --- + +#[test] +fn table_create_and_lookup() { + let mut table = EndpointTable::new(); + let id = table.create().unwrap(); + assert!(table.get(id).is_some()); +} + +#[test] +fn table_create_returns_unique_ids() { + let mut table = EndpointTable::new(); + let a = table.create().unwrap(); + let b = table.create().unwrap(); + assert_ne!(a, b); +} + +#[test] +fn table_destroy_then_get_fails() { + let mut table = EndpointTable::new(); + let id = table.create().unwrap(); + let removed = table.destroy(id); + assert!(removed.is_some()); + assert!(table.get(id).is_none()); +} + +#[test] +fn table_get_mut_allows_enqueue() { + let mut table = EndpointTable::new(); + let id = table.create().unwrap(); + table.get_mut(id).unwrap().enqueue_sender(thread(1)).unwrap(); + assert!(table.get(id).unwrap().has_waiting_sender()); +} + +#[test] +fn table_destroy_reuses_slot() { + let mut table = EndpointTable::new(); + let id = table.create().unwrap(); + table.destroy(id); + let new_id = table.create().unwrap(); + assert_eq!(id, new_id); +} diff --git a/crates/domain/src/error.rs b/crates/domain/src/error.rs index 0563f9c..4080f38 100644 --- a/crates/domain/src/error.rs +++ b/crates/domain/src/error.rs @@ -1,6 +1,6 @@ use types::{ bounded::CapSlot, - id::{ProcessId, ThreadId}, + id::{EndpointId, IrqId, ProcessId, ThreadId}, permission::Permission, }; @@ -18,4 +18,9 @@ pub enum KernelError { InvalidThread(ThreadId), TooManyThreads, OutOfMemory, + InvalidEndpoint(EndpointId), + InvalidIrq(IrqId), + EndpointFull, + ProcessCreateDenied, + IrqAlreadyOwned(IrqId), } diff --git a/crates/domain/src/irq.rs b/crates/domain/src/irq.rs new file mode 100644 index 0000000..4839573 --- /dev/null +++ b/crates/domain/src/irq.rs @@ -0,0 +1,87 @@ +use types::id::{IrqId, ThreadId}; + +use crate::error::KernelError; + +const MAX_IRQS: usize = 256; + +pub struct IrqRoutingTable { + owners: [Option; MAX_IRQS], +} + +impl IrqRoutingTable { + pub fn new() -> Self { + Self { + owners: [None; MAX_IRQS], + } + } + + pub fn register(&mut self, irq: IrqId, thread: ThreadId) -> Result<(), KernelError> { + let idx = irq.raw() as usize; + if self.owners[idx].is_some() { + return Err(KernelError::IrqAlreadyOwned(irq)); + } + self.owners[idx] = Some(thread); + Ok(()) + } + + pub fn unregister(&mut self, irq: IrqId) { + self.owners[irq.raw() as usize] = None; + } + + pub fn owner(&self, irq: IrqId) -> Option { + self.owners[irq.raw() as usize] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn irq(id: u16) -> IrqId { + IrqId::from_raw(id) + } + + fn thread(id: u16) -> ThreadId { + ThreadId::from_raw(id) + } + + #[test] + fn new_table_has_no_owners() { + let table = IrqRoutingTable::new(); + assert!(table.owner(irq(0)).is_none()); + assert!(table.owner(irq(10)).is_none()); + } + + #[test] + fn register_and_lookup() { + let mut table = IrqRoutingTable::new(); + table.register(irq(5), thread(1)).unwrap(); + assert_eq!(table.owner(irq(5)), Some(thread(1))); + } + + #[test] + fn register_already_owned_fails() { + let mut table = IrqRoutingTable::new(); + table.register(irq(5), thread(1)).unwrap(); + assert!(table.register(irq(5), thread(2)).is_err()); + } + + #[test] + fn unregister_then_reregister() { + let mut table = IrqRoutingTable::new(); + table.register(irq(5), thread(1)).unwrap(); + table.unregister(irq(5)); + assert!(table.owner(irq(5)).is_none()); + table.register(irq(5), thread(2)).unwrap(); + assert_eq!(table.owner(irq(5)), Some(thread(2))); + } + + #[test] + fn different_irqs_independent() { + let mut table = IrqRoutingTable::new(); + table.register(irq(0), thread(10)).unwrap(); + table.register(irq(1), thread(20)).unwrap(); + assert_eq!(table.owner(irq(0)), Some(thread(10))); + assert_eq!(table.owner(irq(1)), Some(thread(20))); + } +} diff --git a/crates/domain/src/lib.rs b/crates/domain/src/lib.rs index 20141d1..47e94a2 100644 --- a/crates/domain/src/lib.rs +++ b/crates/domain/src/lib.rs @@ -4,6 +4,7 @@ pub mod capability; pub mod endpoint; pub mod error; pub mod fault; +pub mod irq; pub mod memory; pub mod message; pub mod process;