feat(kernel): WatchDeath + SetTimer events as notification signals; adapter wakes at earliest deadline

This commit is contained in:
2026-10-27 16:06:04 +01:00
parent a4f467f45d
commit 817a38993b
25 changed files with 517 additions and 21 deletions

View File

@@ -32,3 +32,4 @@ pub mod resource;
pub mod scheduler;
pub mod syscall;
pub mod thread;
pub mod timer;

View File

@@ -4,6 +4,7 @@ use types::{
bounded::{CapSlot, PageCount},
mapping::PagePerms,
permission::PermissionSet,
time::Ticks,
};
use crate::message::Message;
@@ -91,6 +92,18 @@ pub enum Syscall {
RegionAddress {
region: CapSlot,
},
/// Signals `notification` when the process behind `process` dies, by
/// exit, fault or kill. One watcher per process; a new one replaces it.
WatchDeath {
process: CapSlot,
notification: CapSlot,
},
/// Signals `notification` once `GetTime` reaches `deadline`; replaces
/// the caller's timer, and a zero deadline cancels it.
SetTimer {
notification: CapSlot,
deadline: Ticks,
},
/// Removes a capability from the caller's own table.
DropCap {
slot: CapSlot,

View File

@@ -0,0 +1,67 @@
//! Events the kernel reports by signalling a notification: a process's
//! death, a deadline passing. One timer per process.
use types::{badge::Badge, generation::Generation, id::NotificationId, id::ProcessId, time::Ticks};
use crate::process::MAX_PROCESSES;
#[cfg(test)]
#[path = "timer_tests.rs"]
mod tests;
/// A notification as a capability named it; once the notification is
/// destroyed (its generation moves on) the target is dead.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Target {
pub notification: NotificationId,
pub generation: Generation,
pub badge: Badge,
}
pub struct Timers {
deadlines: [Option<(Ticks, Target)>; MAX_PROCESSES],
}
impl Timers {
pub const fn new() -> Self {
Self {
deadlines: [None; MAX_PROCESSES],
}
}
/// Replaces `owner`'s timer.
pub fn set(&mut self, owner: ProcessId, deadline: Ticks, target: Target) -> bool {
match self.deadlines.get_mut(owner.raw() as usize) {
Some(slot) => {
*slot = Some((deadline, target));
true
}
None => false,
}
}
pub fn clear(&mut self, owner: ProcessId) {
if let Some(slot) = self.deadlines.get_mut(owner.raw() as usize) {
*slot = None;
}
}
/// Removes and returns one timer whose deadline is at or before `now`.
pub fn take_expired(&mut self, now: Ticks) -> Option<Target> {
let slot = self
.deadlines
.iter_mut()
.find(|s| s.is_some_and(|(d, _)| d <= now))?;
slot.take().map(|(_, t)| t)
}
pub fn earliest(&self) -> Option<Ticks> {
self.deadlines.iter().flatten().map(|(d, _)| *d).min()
}
}
impl Default for Timers {
fn default() -> Self {
Self::new()
}
}

View File

@@ -0,0 +1,37 @@
use super::{Target, Timers};
use types::{badge::Badge, generation::Generation, id::NotificationId, id::ProcessId, time::Ticks};
fn target(n: u16) -> Target {
Target {
notification: NotificationId::from_raw(n),
generation: Generation::initial(),
badge: Badge::NONE,
}
}
fn pid(n: u16) -> ProcessId {
ProcessId::from_raw(n)
}
#[test]
fn only_expired_timers_fire_and_each_fires_once() {
let mut t = Timers::new();
t.set(pid(0), Ticks::from_raw(10), target(0));
t.set(pid(1), Ticks::from_raw(30), target(1));
assert_eq!(t.earliest(), Some(Ticks::from_raw(10)));
assert_eq!(t.take_expired(Ticks::from_raw(9)), None);
assert_eq!(t.take_expired(Ticks::from_raw(10)), Some(target(0)));
assert_eq!(t.take_expired(Ticks::from_raw(29)), None);
assert_eq!(t.earliest(), Some(Ticks::from_raw(30)));
}
#[test]
fn setting_again_replaces_and_clear_cancels() {
let mut t = Timers::new();
t.set(pid(2), Ticks::from_raw(10), target(0));
t.set(pid(2), Ticks::from_raw(50), target(1));
assert_eq!(t.take_expired(Ticks::from_raw(20)), None);
t.clear(pid(2));
assert_eq!(t.earliest(), None);
assert!(!t.set(pid(500), Ticks::from_raw(1), target(0)));
}