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

@@ -0,0 +1,90 @@
//! Events the kernel reports as notification signals: a watched process
//! dying, a timer's deadline passing (see `domain::timer`).
use domain::{error::KernelError, resource::Resource, timer::Target};
use platform::Platform;
use types::{bounded::CapSlot, id::ProcessId, permission::Permission, time::Ticks};
use crate::Kernel;
impl<P: Platform> Kernel<P> {
/// Signalling a notification is the Write right on it.
fn target(&self, pid: ProcessId, slot: CapSlot) -> Result<Target, KernelError> {
let (notification, badge, generation) =
self.notification_cap(pid, slot, Permission::Write)?;
Ok(Target {
notification,
generation,
badge,
})
}
/// Signals `target` unless its notification has died since.
fn fire(&mut self, target: Target) {
if self.notifications.generation(target.notification) == Some(target.generation) {
self.signal_notification(target.notification, target.badge);
}
}
pub(crate) fn watch_death(
&mut self,
pid: ProcessId,
process: CapSlot,
notification: CapSlot,
) -> Result<(), KernelError> {
let watched = match self
.check_cap(pid, process, Permission::Execute)?
.resource()
{
Resource::Process(p) => *p,
_ => return Err(KernelError::WrongObject),
};
let target = self.target(pid, notification)?;
let slot = self
.death_watchers
.get_mut(watched.raw() as usize)
.ok_or(KernelError::InvalidProcess(watched))?;
*slot = Some(target);
Ok(())
}
/// A process is dying: tell its watcher, forget its own timer.
pub(crate) fn report_death(&mut self, pid: ProcessId) {
self.timers.clear(pid);
if let Some(target) = self
.death_watchers
.get_mut(pid.raw() as usize)
.and_then(Option::take)
{
self.fire(target);
}
}
pub(crate) fn set_timer(
&mut self,
pid: ProcessId,
notification: CapSlot,
deadline: Ticks,
) -> Result<(), KernelError> {
let target = self.target(pid, notification)?;
if deadline.raw() == 0 {
self.timers.clear(pid);
return Ok(());
}
self.timers.set(pid, deadline, target);
self.fire_timers();
Ok(())
}
/// Signals every timer that is due and has this core woken for the next
/// one. Call on every timer interrupt, whether or not a thread is running.
pub fn fire_timers(&mut self) {
let now = self.platform.current_ticks();
while let Some(target) = self.timers.take_expired(now) {
self.fire(target);
}
if let Some(next) = self.timers.earliest() {
self.platform.wake_at(next);
}
}
}

View File

@@ -1,6 +1,7 @@
//! Endpoint IPC, notifications and interrupt delivery (see docs/ipc.md).
mod endpoint;
mod events;
mod irq;
mod notification;

View File

@@ -102,6 +102,20 @@ impl<P: Platform> Kernel<P> {
self.region_address_cap(pid, region)
.map(|pa| SyscallResult::Value(pa.raw())),
),
Syscall::WatchDeath {
process,
notification,
} => complete(
self.watch_death(pid, process, notification)
.map(|()| SyscallResult::Ok),
),
Syscall::SetTimer {
notification,
deadline,
} => complete(
self.set_timer(pid, notification, deadline)
.map(|()| SyscallResult::Ok),
),
Syscall::Delegate {
slot,
to_endpoint,