Implement domain and endpoint modules with capability management, message passing, and scheduling features

This commit is contained in:
2026-10-17 23:09:21 +02:00
parent 667bc7f7f7
commit 06b51b6712
25 changed files with 1064 additions and 24 deletions

View File

@@ -0,0 +1,78 @@
use types::{
bounded::CapSlot,
generation::Generation,
id::{EndpointId, ProcessId, ThreadId},
};
use crate::{endpoint::wait_queue::WaitQueue, error::KernelError, message::Message};
pub mod wait_queue;
#[cfg(test)]
#[path = "tests.rs"]
mod tests;
pub struct Endpoint {
id: EndpointId,
waiting_senders: WaitQueue,
waiting_receivers: WaitQueue,
generation: Generation,
}
impl Endpoint {
pub fn new(id: EndpointId) -> Self {
Self {
id,
waiting_senders: WaitQueue::new(),
waiting_receivers: WaitQueue::new(),
generation: Generation::initial(),
}
}
pub fn id(&self) -> &EndpointId {
&self.id
}
pub fn generation(&self) -> &Generation {
&self.generation
}
pub fn enqueue_sender(&mut self, thread: ThreadId) -> Option<()> {
self.waiting_senders.push(thread)
}
pub fn dequeue_sender(&mut self) -> Option<ThreadId> {
self.waiting_senders.pop()
}
pub fn enqueue_receiver(&mut self, thread: ThreadId) -> Option<()> {
self.waiting_receivers.push(thread)
}
pub fn dequeue_receiver(&mut self) -> Option<ThreadId> {
self.waiting_receivers.pop()
}
pub fn has_waiting_sender(&self) -> bool {
!self.waiting_senders.is_empty()
}
pub fn has_waiting_receiver(&self) -> bool {
!self.waiting_receivers.is_empty()
}
pub fn revoke(&mut self) {
self.generation = self.generation.next();
}
}
pub trait MessagePassing {
fn send(
&mut self,
sender: ProcessId,
endpoint: CapSlot,
message: Message,
) -> Result<(), KernelError>;
fn receive(&mut self, receiver: ProcessId, endpoint: CapSlot) -> Result<Message, KernelError>;
}

View File

@@ -0,0 +1,137 @@
use crate::endpoint::wait_queue::MAX_WAITERS;
use super::*;
use types::id::{EndpointId, ThreadId};
fn thread(id: u16) -> ThreadId {
ThreadId::from_raw(id)
}
fn test_endpoint() -> Endpoint {
Endpoint::new(EndpointId::from_raw(1))
}
// --- WaitQueue tests ---
#[test]
fn empty_queue_pop_returns_none() {
let mut queue = WaitQueue::new();
assert!(queue.pop().is_none());
assert!(queue.is_empty());
}
#[test]
fn push_then_pop_returns_same_thread() {
let mut queue = WaitQueue::new();
queue.push(thread(1)).unwrap();
assert_eq!(queue.pop(), Some(thread(1)));
}
#[test]
fn pop_order_is_fifo() {
let mut queue = WaitQueue::new();
queue.push(thread(1)).unwrap();
queue.push(thread(2)).unwrap();
queue.push(thread(3)).unwrap();
assert_eq!(queue.pop(), Some(thread(1)));
assert_eq!(queue.pop(), Some(thread(2)));
assert_eq!(queue.pop(), Some(thread(3)));
assert!(queue.pop().is_none());
}
#[test]
fn full_queue_rejects_push() {
let mut queue = WaitQueue::new();
for i in 0..MAX_WAITERS {
assert!(queue.push(thread(i as u16)).is_some());
}
assert!(queue.push(thread(999)).is_none());
}
#[test]
fn is_empty_after_drain() {
let mut queue = WaitQueue::new();
queue.push(thread(1)).unwrap();
queue.push(thread(2)).unwrap();
queue.pop();
queue.pop();
assert!(queue.is_empty());
}
// --- Endpoint tests ---
#[test]
fn new_endpoint_has_no_waiters() {
let ep = test_endpoint();
assert!(!ep.has_waiting_sender());
assert!(!ep.has_waiting_receiver());
}
#[test]
fn sender_waits_then_dequeues() {
let mut ep = test_endpoint();
ep.enqueue_sender(thread(1)).unwrap();
assert!(ep.has_waiting_sender());
assert_eq!(ep.dequeue_sender(), Some(thread(1)));
assert!(!ep.has_waiting_sender());
}
#[test]
fn receiver_waits_then_dequeues() {
let mut ep = test_endpoint();
ep.enqueue_receiver(thread(1)).unwrap();
assert!(ep.has_waiting_receiver());
assert_eq!(ep.dequeue_receiver(), Some(thread(1)));
assert!(!ep.has_waiting_receiver());
}
#[test]
fn senders_and_receivers_are_independent() {
let mut ep = test_endpoint();
ep.enqueue_sender(thread(1)).unwrap();
ep.enqueue_receiver(thread(2)).unwrap();
assert_eq!(ep.dequeue_sender(), Some(thread(1)));
assert_eq!(ep.dequeue_receiver(), Some(thread(2)));
}
#[test]
fn revoke_bumps_generation() {
let mut ep = test_endpoint();
let gen_before = *ep.generation();
ep.revoke();
let gen_after = *ep.generation();
assert!(!gen_before.is_valid_against(&gen_after));
}
#[test]
fn rendezvous_sender_first() {
let mut ep = test_endpoint();
// sender arrives first, no receiver waiting
ep.enqueue_sender(thread(1)).unwrap();
assert!(!ep.has_waiting_receiver());
// receiver arrives, finds a sender
assert!(ep.has_waiting_sender());
let sender = ep.dequeue_sender().unwrap();
assert_eq!(sender, thread(1));
}
#[test]
fn rendezvous_receiver_first() {
let mut ep = test_endpoint();
// receiver arrives first, no sender waiting
ep.enqueue_receiver(thread(1)).unwrap();
assert!(!ep.has_waiting_sender());
// sender arrives, finds a receiver
assert!(ep.has_waiting_receiver());
let receiver = ep.dequeue_receiver().unwrap();
assert_eq!(receiver, thread(1));
}

View File

@@ -0,0 +1,35 @@
use types::id::ThreadId;
pub const MAX_WAITERS: usize = 16;
pub struct WaitQueue {
entries: [Option<ThreadId>; MAX_WAITERS],
count: u8,
}
impl WaitQueue {
pub fn new() -> Self {
Self {
entries: [None; MAX_WAITERS],
count: 0,
}
}
pub fn push(&mut self, thread: ThreadId) -> Option<()> {
let slot = self.entries.iter_mut().find(|s| s.is_none())?;
*slot = Some(thread);
self.count += 1;
Some(())
}
pub fn pop(&mut self) -> Option<ThreadId> {
let slot = self.entries.iter_mut().find(|s| s.is_some())?;
let thread = slot.take();
self.count -= 1;
thread
}
pub fn is_empty(&self) -> bool {
self.count == 0
}
}