feat(kernel): WatchDeath + SetTimer events as notification signals; adapter wakes at earliest deadline
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user