use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
use alloc::boxed::Box;
use ax_hal;
use ax_kspin::SpinNoIrq;
use ax_lazyinit::LazyInit;
use ax_timer_list::{TimeValue, TimerEvent, TimerList};
static TOKEN: AtomicUsize = AtomicUsize::new(0);
pub struct VmmTimerEvent {
token: usize,
timer_callback: Box<dyn FnOnce(TimeValue) + Send + 'static>,
}
impl VmmTimerEvent {
fn new<F>(token: usize, f: F) -> Self
where
F: FnOnce(TimeValue) + Send + 'static,
{
Self {
token,
timer_callback: Box::new(f),
}
}
}
impl TimerEvent for VmmTimerEvent {
fn callback(self, now: TimeValue) {
(self.timer_callback)(now)
}
}
#[ax_percpu::def_percpu]
static TIMER_LIST: LazyInit<SpinNoIrq<TimerList<VmmTimerEvent>>> = LazyInit::new();
pub fn register_timer<F>(deadline: u64, handler: F) -> usize
where
F: FnOnce(TimeValue) + Send + 'static,
{
trace!("Registering timer...");
trace!(
"deadline is {:#?} = {:#?}",
deadline,
TimeValue::from_nanos(deadline)
);
let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() };
let mut timers = timer_list.lock();
let token = TOKEN.fetch_add(1, Ordering::Release);
let event = VmmTimerEvent::new(token, handler);
timers.set(TimeValue::from_nanos(deadline), event);
token
}
pub fn cancel_timer(token: usize) {
let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() };
let mut timers = timer_list.lock();
timers.cancel(|event| event.token == token);
}
pub fn check_events() {
let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() };
loop {
let now = ax_hal::time::wall_time();
let event = timer_list.lock().expire_one(now);
if let Some((_deadline, event)) = event {
trace!("pick one {_deadline:#?} to handle!!!");
event.callback(now);
} else {
break;
}
}
}
pub fn init_percpu() {
info!("Initing HV Timer...");
let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() };
timer_list.init_once(SpinNoIrq::new(TimerList::new()));
}