use core::sync::atomic::{AtomicU64, Ordering};
use kernel_guard::NoOp;
use lazyinit::LazyInit;
use timer_list::{TimeValue, TimerEvent, TimerList};
use axhal::time::wall_time;
use crate::{AxTaskRef, select_run_queue};
static TIMER_TICKET_ID: AtomicU64 = AtomicU64::new(1);
percpu_static! {
TIMER_LIST: LazyInit<TimerList<TaskWakeupEvent>> = LazyInit::new(),
}
struct TaskWakeupEvent {
ticket_id: u64,
task: AxTaskRef,
}
impl TimerEvent for TaskWakeupEvent {
fn callback(self, _now: TimeValue) {
if self.task.timer_ticket() != self.ticket_id {
return;
}
select_run_queue::<NoOp>(&self.task).unblock_task(self.task, true)
}
}
pub fn set_alarm_wakeup(deadline: TimeValue, task: AxTaskRef) {
TIMER_LIST.with_current(|timer_list| {
let ticket_id = TIMER_TICKET_ID.fetch_add(1, Ordering::AcqRel);
task.set_timer_ticket(ticket_id);
timer_list.set(deadline, TaskWakeupEvent { ticket_id, task });
})
}
pub fn check_events() {
loop {
let now = wall_time();
let event = unsafe {
TIMER_LIST.current_ref_mut_raw()
}
.expire_one(now);
if let Some((_deadline, event)) = event {
event.callback(now);
} else {
break;
}
}
}
pub fn init() {
TIMER_LIST.with_current(|timer_list| {
timer_list.init_once(TimerList::new());
});
}