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

@@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2024"
[dependencies]
types = { workspace = true }

View File

@@ -0,0 +1,33 @@
use types::{
bounded::CapSlot,
id::ProcessId,
permission::{Permission, PermissionSet},
};
use crate::{capability::Capability, error::KernelError, resource::Resource};
pub trait CapabilityAuthority {
fn grant(
&mut self,
to: ProcessId,
resource: Resource,
permissions: PermissionSet,
) -> Result<CapSlot, KernelError>;
fn revoke(&mut self, owner: ProcessId, slot: CapSlot) -> Result<(), KernelError>;
fn delegate(
&mut self,
from: ProcessId,
slot: CapSlot,
to: ProcessId,
restrict: PermissionSet,
) -> Result<CapSlot, KernelError>;
fn check(
&self,
caller: ProcessId,
slot: CapSlot,
needed: Permission,
) -> Result<&Capability, KernelError>;
}

View File

@@ -0,0 +1,82 @@
use types::{bounded::CapSlot, generation::Generation, permission::PermissionSet};
pub mod authority;
use crate::{error::KernelError, resource::Resource};
#[cfg(test)]
#[path = "tests.rs"]
mod tests;
const MAX_CAPS_PER_PROCESS: usize = 16;
pub struct Capability {
resource: Resource,
permissions: PermissionSet,
generation: Generation,
}
impl Capability {
pub(crate) fn new(
resource: Resource,
permissions: PermissionSet,
generation: Generation,
) -> Self {
Self {
resource,
permissions,
generation,
}
}
pub fn resource(&self) -> &Resource {
&self.resource
}
pub fn permissions(&self) -> &PermissionSet {
&self.permissions
}
pub fn generation(&self) -> &Generation {
&self.generation
}
}
pub struct CapabilityTable {
slots: [Option<Capability>; MAX_CAPS_PER_PROCESS],
}
impl CapabilityTable {
pub fn new() -> Self {
Self {
slots: [const { None }; MAX_CAPS_PER_PROCESS],
}
}
pub fn get(&self, slot: CapSlot) -> Result<&Capability, KernelError> {
let idx = slot.value() as usize;
self.slots[idx]
.as_ref()
.ok_or(KernelError::InvalidSlot(slot))
}
pub fn insert(&mut self, cap: Capability) -> Result<CapSlot, KernelError> {
let idx = self
.slots
.iter()
.position(|s| s.is_none())
.ok_or(KernelError::NoFreeSlot)?;
self.slots[idx] = Some(cap);
CapSlot::new(idx as u8).ok_or(KernelError::NoFreeSlot)
}
pub fn remove(&mut self, slot: CapSlot) -> Result<(), KernelError> {
let idx = slot.value() as usize;
if self.slots[idx].is_none() {
return Err(KernelError::InvalidSlot(slot));
}
self.slots[idx] = None;
Ok(())
}
}

View File

@@ -0,0 +1,152 @@
use super::*;
use types::generation::Generation;
use types::id::{EndpointId, RegionId};
use types::permission::{Permission, PermissionSet};
fn perms(permissions: &[Permission]) -> PermissionSet {
permissions
.iter()
.fold(PermissionSet::empty(), |set, &p| set.with(p))
}
fn endpoint_cap(id: u16, permissions: &[Permission]) -> Capability {
Capability::new(
Resource::Endpoint(EndpointId::from_raw(id)),
perms(permissions),
Generation::initial(),
)
}
fn memory_cap(id: u16, permissions: &[Permission]) -> Capability {
Capability::new(
Resource::Memory(RegionId::from_raw(id)),
perms(permissions),
Generation::initial(),
)
}
#[test]
fn new_table_is_empty() {
let table = CapabilityTable::new();
let slot = CapSlot::new(0).unwrap();
assert!(table.get(slot).is_err());
}
#[test]
fn insert_and_get() {
let mut table = CapabilityTable::new();
let slot = table.insert(endpoint_cap(1, &[Permission::Read])).unwrap();
let retrieved = table.get(slot).unwrap();
assert!(retrieved.permissions().allows(Permission::Read));
assert!(!retrieved.permissions().allows(Permission::Write));
}
#[test]
fn remove_then_get_fails() {
let mut table = CapabilityTable::new();
let slot = table.insert(endpoint_cap(1, &[Permission::Read])).unwrap();
table.remove(slot).unwrap();
assert!(table.get(slot).is_err());
}
#[test]
fn remove_invalid_slot_fails() {
let mut table = CapabilityTable::new();
let slot = CapSlot::new(5).unwrap();
assert!(table.remove(slot).is_err());
}
#[test]
fn insert_reuses_removed_slot() {
let mut table = CapabilityTable::new();
let slot = table.insert(endpoint_cap(1, &[Permission::Read])).unwrap();
table.remove(slot).unwrap();
let new_slot = table.insert(endpoint_cap(2, &[Permission::Write])).unwrap();
assert_eq!(slot, new_slot);
}
#[test]
fn full_table_returns_no_free_slot() {
let mut table = CapabilityTable::new();
for i in 0..MAX_CAPS_PER_PROCESS {
assert!(
table
.insert(endpoint_cap(i as u16, &[Permission::Read]))
.is_ok()
);
}
assert!(table.insert(endpoint_cap(999, &[])).is_err());
}
#[test]
fn generation_mismatch_detected() {
let gen_v1 = Generation::initial();
let gen_v2 = gen_v1.next();
assert!(gen_v1.is_valid_against(&gen_v1));
assert!(!gen_v1.is_valid_against(&gen_v2));
}
#[test]
fn restrict_to_never_escalates() {
let full = perms(&[Permission::Read, Permission::Write, Permission::Execute]);
let read_only = perms(&[Permission::Read]);
let restricted = full.restrict_to(&read_only);
assert!(restricted.allows(Permission::Read));
assert!(!restricted.allows(Permission::Write));
assert!(!restricted.allows(Permission::Execute));
}
#[test]
fn restrict_to_cannot_add_permissions() {
let read_only = perms(&[Permission::Read]);
let wants_everything = perms(&[
Permission::Read,
Permission::Write,
Permission::Execute,
Permission::Delegate,
Permission::Revoke,
]);
let result = read_only.restrict_to(&wants_everything);
assert!(result.allows(Permission::Read));
assert!(!result.allows(Permission::Write));
assert!(!result.allows(Permission::Execute));
assert!(!result.allows(Permission::Delegate));
assert!(!result.allows(Permission::Revoke));
}
#[test]
fn is_subset_of() {
let rw = perms(&[Permission::Read, Permission::Write]);
let read_only = perms(&[Permission::Read]);
assert!(read_only.is_subset_of(&rw));
assert!(!rw.is_subset_of(&read_only));
}
#[test]
fn empty_permission_set_allows_nothing() {
let empty = PermissionSet::empty();
assert!(!empty.allows(Permission::Read));
assert!(!empty.allows(Permission::Write));
assert!(!empty.allows(Permission::Execute));
assert!(!empty.allows(Permission::Delegate));
assert!(!empty.allows(Permission::Revoke));
}
#[test]
fn capability_preserves_resource_and_permissions() {
let permissions = [Permission::Read, Permission::Write];
let expected_permissions = perms(&permissions);
let cap = memory_cap(42, &permissions);
assert_eq!(cap.permissions(), &expected_permissions);
assert_eq!(cap.generation(), &Generation::initial());
}

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
}
}

View File

@@ -0,0 +1,11 @@
use types::{bounded::CapSlot, id::ProcessId, permission::Permission};
#[derive(Debug)]
pub enum KernelError {
InvalidSlot(CapSlot),
RevokedCapability(CapSlot),
PermissionDenied { slot: CapSlot, needed: Permission },
NoFreeSlot,
InvalidProcess(ProcessId),
WouldBlock,
}

View File

@@ -0,0 +1,10 @@
use types::{address::VirtualAddress, bounded::CapSlot, permission::Permission};
pub enum Fault {
CapabilityViolation { slot: CapSlot, needed: Permission },
InvalidCapability { slot: CapSlot },
RevokedCapability { slot: CapSlot },
InvalidSyscall,
MemoryFault { address: VirtualAddress },
IllegalInstruction,
}

View File

@@ -1,14 +1,12 @@
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#![no_std]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
pub mod capability;
pub mod endpoint;
pub mod error;
pub mod fault;
pub mod message;
pub mod process;
pub mod resource;
pub mod scheduler;
pub mod syscall;
pub mod thread;

View File

@@ -0,0 +1,9 @@
use types::bounded::CapSlot;
pub const MAX_MESSAGE_WORDS: usize = 4;
pub const MAX_CAP_TRANSFERS: usize = 4;
pub struct Message {
words: [usize; MAX_MESSAGE_WORDS],
caps: [Option<CapSlot>; MAX_CAP_TRANSFERS],
}

View File

@@ -0,0 +1,15 @@
use types::{
bounded::CapSlot,
id::{ProcessId, ThreadId},
};
use crate::capability::CapabilityTable;
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>,
}

View File

@@ -0,0 +1,22 @@
use types::{
address::VirtualAddress,
bounded::PageCount,
generation::Generation,
id::{EndpointId, IrqId, ProcessId, RegionId},
};
#[derive(Clone)]
pub enum Resource {
Memory(RegionId),
Endpoint(EndpointId),
Process(ProcessId),
Interrupt(IrqId),
ProcessCreate,
}
pub struct MemoryRegion {
id: RegionId,
base: VirtualAddress,
size: PageCount,
generation: Generation,
}

View File

@@ -0,0 +1,24 @@
use types::{
bounded::Priority,
id::{CoreId, ThreadId},
};
pub mod per_core;
pub mod priority_queue;
#[cfg(test)]
#[path = "tests.rs"]
mod tests;
pub enum SchedulerDecision {
Continue,
Preempt(ThreadId),
}
pub trait Scheduler {
fn add(&mut self, thread: ThreadId, priority: Priority, core: CoreId);
fn remove(&mut self, thread: ThreadId);
fn next(&mut self, core: CoreId) -> Option<ThreadId>;
fn tick(&mut self, core: CoreId, current: ThreadId) -> SchedulerDecision;
fn balance(&mut self);
}

View File

@@ -0,0 +1,52 @@
use super::priority_queue::PriorityQueue;
use types::bounded::Priority;
use types::id::{CoreId, ThreadId};
pub struct PerCoreScheduler {
core: CoreId,
queue: PriorityQueue,
current: Option<ThreadId>,
}
impl PerCoreScheduler {
pub fn new(core: CoreId) -> Self {
Self {
core,
queue: PriorityQueue::new(),
current: None,
}
}
pub fn core(&self) -> CoreId {
self.core
}
pub fn current(&self) -> Option<ThreadId> {
self.current
}
pub fn add(&mut self, thread: ThreadId, priority: Priority) {
self.queue.add(thread, priority);
}
pub fn remove(&mut self, thread: ThreadId, priority: Priority) {
self.queue.remove(thread, priority);
}
pub fn pick_next(&mut self) -> Option<ThreadId> {
let (thread, _priority) = self.queue.next()?;
self.current = Some(thread);
Some(thread)
}
pub fn clear_current(&mut self) {
self.current = None;
}
pub fn len(&self) -> usize {
// for load balancing — count of ready threads
// could track this incrementally instead of computing
// but for now, bitmap popcount works
self.queue.bitmap().count_ones() as usize
}
}

View File

@@ -0,0 +1,108 @@
use types::bounded::Priority;
use types::id::ThreadId;
const NUM_PRIORITIES: usize = 32;
const MAX_THREADS_PER_PRIORITY: usize = 16;
struct RunList {
threads: [Option<ThreadId>; MAX_THREADS_PER_PRIORITY],
head: usize,
tail: usize,
count: u8,
}
impl RunList {
fn new() -> Self {
Self {
threads: [None; MAX_THREADS_PER_PRIORITY],
head: 0,
tail: 0,
count: 0,
}
}
fn push(&mut self, thread: ThreadId) -> bool {
match self.threads.iter_mut().find(|s| s.is_none()) {
Some(slot) => {
*slot = Some(thread);
self.count += 1;
true
}
None => false,
}
}
fn pop(&mut self) -> Option<ThreadId> {
if self.count == 0 {
return None;
}
let slot = self.threads.iter_mut().find(|s| s.is_some())?;
let thread = slot.take();
self.count -= 1;
thread
}
fn remove(&mut self, thread: ThreadId) -> bool {
for slot in &mut self.threads {
if *slot == Some(thread) {
*slot = None;
self.count -= 1;
return true;
}
}
false
}
fn is_empty(&self) -> bool {
self.count == 0
}
}
pub struct PriorityQueue {
queues: [RunList; NUM_PRIORITIES],
bitmap: u32,
}
impl PriorityQueue {
pub fn new() -> Self {
Self {
queues: core::array::from_fn(|_| RunList::new()),
bitmap: 0,
}
}
pub fn bitmap(&self) -> u32 {
self.bitmap
}
pub fn add(&mut self, thread: ThreadId, priority: Priority) {
let idx = priority.value() as usize;
self.queues[idx].push(thread);
self.bitmap |= 1 << idx;
}
pub fn remove(&mut self, thread: ThreadId, priority: Priority) {
let idx = priority.value() as usize;
self.queues[idx].remove(thread);
if self.queues[idx].is_empty() {
self.bitmap &= !(1 << idx);
}
}
pub fn next(&mut self) -> Option<(ThreadId, Priority)> {
if self.bitmap == 0 {
return None;
}
// highest set bit = highest priority
let idx = 31 - self.bitmap.leading_zeros() as usize;
let thread = self.queues[idx].pop()?;
if self.queues[idx].is_empty() {
self.bitmap &= !(1 << idx);
}
Some((thread, Priority::new(idx as u8).unwrap()))
}
pub fn is_empty(&self) -> bool {
self.bitmap == 0
}
}

View File

@@ -0,0 +1,124 @@
use super::per_core::PerCoreScheduler;
use super::priority_queue::PriorityQueue;
use types::bounded::Priority;
use types::id::{CoreId, ThreadId};
fn thread(id: u16) -> ThreadId {
ThreadId::from_raw(id)
}
fn prio(value: u8) -> Priority {
Priority::new(value).unwrap()
}
// --- PriorityQueue tests ---
#[test]
fn empty_queue_returns_none() {
let mut q = PriorityQueue::new();
assert!(q.next().is_none());
assert!(q.is_empty());
}
#[test]
fn single_thread() {
let mut q = PriorityQueue::new();
q.add(thread(1), prio(10));
let (t, p) = q.next().unwrap();
assert_eq!(t, thread(1));
assert_eq!(p, prio(10));
}
#[test]
fn highest_priority_runs_first() {
let mut q = PriorityQueue::new();
q.add(thread(1), prio(5));
q.add(thread(2), prio(20));
q.add(thread(3), prio(10));
let (t, _) = q.next().unwrap();
assert_eq!(t, thread(2));
}
#[test]
fn same_priority_is_fifo() {
let mut q = PriorityQueue::new();
q.add(thread(1), prio(10));
q.add(thread(2), prio(10));
q.add(thread(3), prio(10));
assert_eq!(q.next().unwrap().0, thread(1));
assert_eq!(q.next().unwrap().0, thread(2));
assert_eq!(q.next().unwrap().0, thread(3));
assert!(q.next().is_none());
}
#[test]
fn remove_thread() {
let mut q = PriorityQueue::new();
q.add(thread(1), prio(10));
q.add(thread(2), prio(10));
q.remove(thread(1), prio(10));
let (t, _) = q.next().unwrap();
assert_eq!(t, thread(2));
assert!(q.next().is_none());
}
#[test]
fn remove_clears_bitmap_when_empty() {
let mut q = PriorityQueue::new();
q.add(thread(1), prio(10));
q.remove(thread(1), prio(10));
assert!(q.is_empty());
}
#[test]
fn drain_all_priorities() {
let mut q = PriorityQueue::new();
q.add(thread(1), prio(0));
q.add(thread(2), prio(15));
q.add(thread(3), prio(31));
assert_eq!(q.next().unwrap().0, thread(3)); // highest first
assert_eq!(q.next().unwrap().0, thread(2));
assert_eq!(q.next().unwrap().0, thread(1)); // lowest last
assert!(q.is_empty());
}
// --- PerCoreScheduler tests ---
#[test]
fn new_core_has_no_current() {
let core = PerCoreScheduler::new(CoreId::from_raw(0));
assert!(core.current().is_none());
}
#[test]
fn pick_next_sets_current() {
let mut core = PerCoreScheduler::new(CoreId::from_raw(0));
core.add(thread(1), prio(10));
let picked = core.pick_next().unwrap();
assert_eq!(picked, thread(1));
assert_eq!(core.current(), Some(thread(1)));
}
#[test]
fn pick_next_on_empty_returns_none() {
let mut core = PerCoreScheduler::new(CoreId::from_raw(0));
assert!(core.pick_next().is_none());
}
#[test]
fn clear_current() {
let mut core = PerCoreScheduler::new(CoreId::from_raw(0));
core.add(thread(1), prio(10));
core.pick_next();
core.clear_current();
assert!(core.current().is_none());
}

View File

@@ -0,0 +1,64 @@
use types::{
address::{DataRef, EntryPoint, StackPointer, VirtualAddress},
bounded::{CapSlot, PageCount},
permission::PermissionSet,
};
use crate::message::Message;
pub struct WaitSet {
endpoints: [Option<CapSlot>; 4],
interrupts: [Option<CapSlot>; 4],
}
pub enum WakeReason {
MessageReady(CapSlot),
InterruptFired(CapSlot),
}
pub enum Syscall {
Send {
endpoint: CapSlot,
message: Message,
},
Receive {
endpoint: CapSlot,
},
Delegate {
slot: CapSlot,
to_endpoint: CapSlot,
permissions: PermissionSet,
},
WaitForInterrupt {
irq: CapSlot,
},
AcknowledgeInterrupt {
irq: CapSlot,
},
WaitAny {
sources: WaitSet,
},
CreateProcess {
create_cap: CapSlot,
image: DataRef,
},
Kill {
process: CapSlot,
},
SpawnThread {
entry: EntryPoint,
stack: StackPointer,
},
ExitThread,
RequestPages {
count: PageCount,
},
ReleasePages {
addr: VirtualAddress,
count: PageCount,
},
GetTime,
GetProcessId,
Yield,
Exit,
}

View File

@@ -0,0 +1,33 @@
use types::{
bounded::{CapSlot, Priority},
id::{CoreId, ProcessId, ThreadId},
time::TimeSlice,
};
pub struct Thread {
id: ThreadId,
process: ProcessId,
state: ThreadState,
saved_context: SavedContext,
priority: Priority,
time_slice: TimeSlice,
core_affinity: Option<CoreId>,
}
pub enum ThreadState {
Ready,
Running(CoreId),
Blocked(BlockReason),
Dead,
}
pub struct SavedContext {
registers: [usize; 32],
}
pub enum BlockReason {
Sending(CapSlot),
Receiving(CapSlot),
WaitingForInterrupt(CapSlot),
WaitingAny,
}