|
| 1 | +use core::sync::atomic::AtomicUsize; |
| 2 | +use core::sync::atomic::Ordering; |
| 3 | + |
| 4 | +use axhal; |
| 5 | + |
| 6 | +use alloc::boxed::Box; |
| 7 | +use kspin::SpinNoIrq; |
| 8 | +use lazyinit::LazyInit; |
| 9 | +use timer_list::{TimeValue, TimerEvent, TimerList}; |
| 10 | + |
| 11 | +static TOKEN: AtomicUsize = AtomicUsize::new(0); |
| 12 | +// const PERIODIC_INTERVAL_NANOS: u64 = axhal::time::NANOS_PER_SEC / axconfig::TICKS_PER_SEC as u64; |
| 13 | + |
| 14 | +/// Represents a timer event in the virtual machine monitor (VMM). |
| 15 | +/// |
| 16 | +/// This struct holds a unique token for the timer and a callback function |
| 17 | +/// that will be executed when the timer expires. |
| 18 | +pub struct VmmTimerEvent { |
| 19 | + // Unique identifier for the timer event |
| 20 | + token: usize, |
| 21 | + // Callback function to be executed when the timer expires |
| 22 | + timer_callback: Box<dyn FnOnce(TimeValue) + Send + 'static>, |
| 23 | +} |
| 24 | + |
| 25 | +impl VmmTimerEvent { |
| 26 | + fn new<F>(token: usize, f: F) -> Self |
| 27 | + where |
| 28 | + F: FnOnce(TimeValue) + Send + 'static, |
| 29 | + { |
| 30 | + Self { |
| 31 | + token, |
| 32 | + timer_callback: Box::new(f), |
| 33 | + } |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +impl TimerEvent for VmmTimerEvent { |
| 38 | + fn callback(self, now: TimeValue) { |
| 39 | + (self.timer_callback)(now) |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +#[percpu::def_percpu] |
| 44 | +static TIMER_LIST: LazyInit<SpinNoIrq<TimerList<VmmTimerEvent>>> = LazyInit::new(); |
| 45 | + |
| 46 | +/// Registers a new timer that will execute at the specified deadline |
| 47 | +/// |
| 48 | +/// # Arguments |
| 49 | +/// - `deadline`: The absolute time in nanoseconds when the timer should trigger |
| 50 | +/// - `handler`: The callback function to execute when the timer expires |
| 51 | +/// |
| 52 | +/// # Returns |
| 53 | +/// A unique token that can be used to cancel this timer later |
| 54 | +pub fn register_timer<F>(deadline: u64, handler: F) -> usize |
| 55 | +where |
| 56 | + F: FnOnce(TimeValue) + Send + 'static, |
| 57 | +{ |
| 58 | + trace!("Registering timer..."); |
| 59 | + trace!( |
| 60 | + "deadline is {:#?} = {:#?}", |
| 61 | + deadline, |
| 62 | + TimeValue::from_nanos(deadline) |
| 63 | + ); |
| 64 | + let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() }; |
| 65 | + let mut timers = timer_list.lock(); |
| 66 | + let token = TOKEN.fetch_add(1, Ordering::Release); |
| 67 | + let event = VmmTimerEvent::new(token, handler); |
| 68 | + timers.set(TimeValue::from_nanos(deadline), event); |
| 69 | + token |
| 70 | +} |
| 71 | + |
| 72 | +/// Cancels a timer with the specified token. |
| 73 | +/// |
| 74 | +/// # Parameters |
| 75 | +/// - `token`: The unique token of the timer to cancel. |
| 76 | +pub fn cancel_timer(token: usize) { |
| 77 | + let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() }; |
| 78 | + let mut timers = timer_list.lock(); |
| 79 | + timers.cancel(|event| event.token == token); |
| 80 | +} |
| 81 | + |
| 82 | +/// Check and process any pending timer events |
| 83 | +pub fn check_events() { |
| 84 | + // info!("Checking timer events..."); |
| 85 | + // info!("now is {:#?}", axhal::time::wall_time()); |
| 86 | + let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() }; |
| 87 | + loop { |
| 88 | + let now = axhal::time::wall_time(); |
| 89 | + let event = timer_list.lock().expire_one(now); |
| 90 | + if let Some((_deadline, event)) = event { |
| 91 | + trace!("pick one {_deadline:#?} to handle!!!"); |
| 92 | + event.callback(now); |
| 93 | + } else { |
| 94 | + break; |
| 95 | + } |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +// /// Schedule the next timer event based on the periodic interval |
| 100 | +// pub fn scheduler_next_event() { |
| 101 | +// trace!("Scheduling next event..."); |
| 102 | +// let now_ns = axhal::time::monotonic_time_nanos(); |
| 103 | +// let deadline = now_ns + PERIODIC_INTERVAL_NANOS; |
| 104 | +// debug!("PHY deadline {} !!!", deadline); |
| 105 | +// axhal::time::set_oneshot_timer(deadline); |
| 106 | +// } |
| 107 | + |
| 108 | +/// Initialize the hypervisor timer system |
| 109 | +pub fn init_percpu() { |
| 110 | + info!("Initing HV Timer..."); |
| 111 | + let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() }; |
| 112 | + timer_list.init_once(SpinNoIrq::new(TimerList::new())); |
| 113 | +} |
0 commit comments