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

@@ -1,4 +1,10 @@
use core::sync::atomic::{AtomicU64, Ordering};
use crate::board;
use crate::smp::{MAX_HARTS, hart_id};
/// When each hart's timer is set to go off next.
static NEXT: [AtomicU64; MAX_HARTS] = [const { AtomicU64::new(u64::MAX) }; MAX_HARTS];
pub fn read_time() -> u64 {
let time: u64;
@@ -21,15 +27,27 @@ fn sbi_set_timer(stime: u64) {
}
pub fn init() {
let now = read_time();
sbi_set_timer(now + board::TICK_INTERVAL);
set_next(read_time() + board::TICK_INTERVAL);
}
pub fn set_next(deadline: u64) {
if let Some(next) = NEXT.get(hart_id()) {
next.store(deadline, Ordering::Relaxed);
}
sbi_set_timer(deadline);
}
pub fn handle_interrupt() {
let now = read_time();
sbi_set_timer(now + board::TICK_INTERVAL);
/// Goes off at `deadline` too, if that is before the next tick.
pub fn wake_at(deadline: u64) {
if NEXT
.get(hart_id())
.is_some_and(|n| deadline < n.load(Ordering::Relaxed))
{
set_next(deadline);
}
}
/// Re-arms the tick; the kernel then re-arms for its earliest timer.
pub fn handle_interrupt() {
set_next(read_time() + board::TICK_INTERVAL);
}

View File

@@ -4,10 +4,9 @@ use types::{
address::{EntryPoint, PhysicalAddress, StackPointer, VirtualAddress},
id::{CoreId, IrqId, ProcessId},
mapping::PagePerms,
time::{Ticks, TimerDuration},
time::Ticks,
};
use crate::board;
use crate::hw::{plic::Plic, timer};
use crate::mmu;
use crate::smp;
@@ -136,9 +135,8 @@ impl Platform for RiscVPlatform {
}
}
fn set_timer(&mut self, _duration: TimerDuration) {
let now = timer::read_time();
timer::set_next(now + board::TICK_INTERVAL);
fn wake_at(&mut self, deadline: Ticks) {
timer::wake_at(deadline.raw());
}
fn current_ticks(&self) -> Ticks {

View File

@@ -104,6 +104,7 @@ fn handle_interrupt(frame: &mut TrapFrame, cause: usize) {
CAUSE_S_TIMER => {
crate::hw::timer::handle_interrupt();
let kern = kern();
kern.fire_timers();
if let Some(current_tid) = kern.current_thread() {
let decision = kern.handle_tick(this_core());
if let domain::scheduler::SchedulerDecision::Preempt(next) = decision {

View File

@@ -70,6 +70,7 @@ fn next_runnable() -> types::id::ThreadId {
if sip & (1 << CAUSE_S_TIMER) != 0 {
// No thread is running, so there is no time slice to charge.
crate::hw::timer::handle_interrupt();
kern().fire_timers();
}
if sip & (1 << CAUSE_S_EXTERNAL) != 0 {
dispatch_external();