Skip to main content

sparreal_kernel/os/time/
timer.rs

1use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
2use core::{
3    sync::atomic::{AtomicBool, Ordering},
4    time::Duration,
5};
6
7use super::{duration_to_ticks, ticks};
8use crate::os::sync::IrqSpinlock;
9
10type TimerCallback = Box<dyn FnMut() + Send + 'static>;
11
12static TIMER_MANAGER: IrqSpinlock<Option<TimerManager>> = IrqSpinlock::new(None);
13static TIMER_READY: AtomicBool = AtomicBool::new(false);
14
15pub type TimerResult<T> = core::result::Result<T, TimerError>;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum TimerError {
19    NotReady,
20    Overflow,
21}
22
23#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
24pub struct TimerHandle(TimerId);
25
26impl TimerHandle {
27    pub fn cancel(self) -> bool {
28        cancel(self)
29    }
30}
31
32#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
33struct TimerId(u64);
34
35#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
36struct TimerKey {
37    // deadline in ticks
38    deadline: usize,
39    id: TimerId,
40}
41
42#[derive(Debug, Clone, Copy)]
43pub struct TimeListEntry {
44    pub handle: TimerHandle,
45    pub deadline: usize,
46    pub remaining: usize,
47}
48
49/// Software timer core that keeps a sorted list of one-shot callbacks.
50/// Uses on-demand hardware timer interrupts instead of periodic ticks.
51struct TimerManager {
52    next_id: u64,
53    timers: BTreeMap<TimerKey, TimerCallback>,
54    index: BTreeMap<TimerId, usize>,
55}
56
57impl TimerManager {
58    fn new() -> Self {
59        Self {
60            next_id: 1,
61            timers: BTreeMap::new(),
62            index: BTreeMap::new(),
63        }
64    }
65
66    fn schedule_after<F>(&mut self, delay: usize, callback: F) -> TimerResult<TimerHandle>
67    where
68        F: FnOnce() + Send + 'static,
69    {
70        let now = ticks();
71        let deadline = now.checked_add(delay).ok_or(TimerError::Overflow)?;
72        Ok(self.schedule_at_internal(deadline, callback))
73    }
74
75    fn schedule_at<F>(&mut self, deadline: usize, callback: F) -> TimerHandle
76    where
77        F: FnOnce() + Send + 'static,
78    {
79        self.schedule_at_internal(deadline, callback)
80    }
81
82    fn schedule_at_internal<F>(&mut self, deadline: usize, callback: F) -> TimerHandle
83    where
84        F: FnOnce() + Send + 'static,
85    {
86        let id = self.next_timer_id();
87        let key = TimerKey { deadline, id };
88
89        // Check if this is the new earliest deadline
90        let is_earliest = self
91            .timers
92            .keys()
93            .next()
94            .is_none_or(|k| deadline < k.deadline);
95
96        self.timers.insert(key, into_callback(callback));
97
98        self.index.insert(id, deadline);
99        // If this is the earliest timer, reprogram hardware timer
100
101        if is_earliest {
102            self.arm_hardware_timer();
103        }
104
105        TimerHandle(id)
106    }
107
108    fn cancel(&mut self, handle: TimerHandle) -> bool {
109        if let Some(deadline) = self.index.remove(&handle.0) {
110            let key = TimerKey {
111                deadline,
112                id: handle.0,
113            };
114            let was_first = self.timers.keys().next().is_some_and(|k| *k == key);
115            self.timers.remove(&key);
116
117            // If we removed the earliest timer, reprogram for the next one
118            if was_first {
119                self.arm_hardware_timer();
120            }
121            return true;
122        }
123        false
124    }
125
126    fn handle_irq(&mut self) -> Vec<TimerCallback> {
127        let now = ticks();
128        let mut expired = Vec::new();
129
130        // Collect all expired timers
131        while let Some(key) = self.timers.keys().next().cloned() {
132            if key.deadline > now {
133                break;
134            }
135            if let Some(cb) = self.timers.remove(&key) {
136                expired.push(cb);
137            }
138            self.index.remove(&key.id);
139        }
140
141        // Arm hardware timer for next deadline (if any)
142        self.arm_hardware_timer();
143
144        expired
145    }
146
147    /// Program the hardware timer for the next deadline
148    fn arm_hardware_timer(&self) {
149        if let Some(key) = self.timers.keys().next() {
150            let now = ticks();
151            let delay = key.deadline.saturating_sub(now);
152
153            // Keep a small but non-trivial minimum delay to avoid programming
154            // a deadline that expires before IRQ unmasking takes effect.
155            let freq = crate::hal::al::cpu::systick_frequency();
156            let min_delay = (freq / 10_000).max(1); // ~=100us
157            let delay = delay.max(min_delay);
158
159            crate::hal::al::cpu::systick_set_interval(delay);
160            crate::hal::al::cpu::systick_irq_enable();
161        } else {
162            // No pending timers, disable hardware timer
163            crate::hal::al::cpu::systick_set_interval(usize::MAX);
164            crate::hal::al::cpu::systick_irq_disable();
165        }
166    }
167
168    fn snapshot(&self) -> Vec<TimeListEntry> {
169        let now = ticks();
170        let mut list = Vec::with_capacity(self.timers.len());
171        for key in self.timers.keys() {
172            let remaining = key.deadline.saturating_sub(now);
173            list.push(TimeListEntry {
174                handle: TimerHandle(key.id),
175                deadline: key.deadline,
176                remaining,
177            });
178        }
179        list
180    }
181
182    // fn next_deadline(&self) -> Option<usize> {
183    //     self.timers.keys().next().map(|k| k.deadline)
184    // }
185
186    fn next_timer_id(&mut self) -> TimerId {
187        loop {
188            let id = TimerId(self.next_id);
189            self.next_id = self.next_id.wrapping_add(1);
190            if !self.index.contains_key(&id) {
191                return id;
192            }
193        }
194    }
195}
196
197pub(crate) fn init() {
198    {
199        let mut guard = TIMER_MANAGER.lock();
200        if guard.is_some() {
201            return;
202        }
203        *guard = Some(TimerManager::new());
204    }
205
206    TIMER_READY.store(true, Ordering::Release);
207
208    let timer_irq = crate::hal::al::cpu::systick_irq_id();
209    crate::os::irq::register_handler(timer_irq, systimer_irq_handler);
210}
211
212/// Schedule a one-shot timer after the provided delay.
213pub fn one_shot_after<F>(delay: Duration, callback: F) -> Result<TimerHandle, TimerError>
214where
215    F: FnOnce() + Send + 'static,
216{
217    if !is_ready() {
218        return Err(TimerError::NotReady);
219    }
220    let delay = duration_to_ticks(delay);
221    with_manager_mut(move |mgr| mgr.schedule_after(delay, callback)).ok_or(TimerError::NotReady)?
222}
223
224/// Schedule a one-shot timer that fires at the absolute deadline.
225pub fn one_shot_at<F>(deadline: Duration, callback: F) -> Result<TimerHandle, TimerError>
226where
227    F: FnOnce() + Send + 'static,
228{
229    if !is_ready() {
230        return Err(TimerError::NotReady);
231    }
232    let mut cb = Some(callback);
233    let deadline = duration_to_ticks(deadline);
234    with_manager_mut(|mgr| mgr.schedule_at(deadline, cb.take().unwrap()))
235        .ok_or(TimerError::NotReady)
236}
237
238/// Cancel a scheduled timer.
239pub fn cancel(handle: TimerHandle) -> bool {
240    with_manager_mut(|mgr| mgr.cancel(handle)).unwrap_or(false)
241}
242
243/// Snapshot the current pending timers for diagnostics.
244pub fn time_list() -> Vec<TimeListEntry> {
245    with_manager(|mgr| mgr.snapshot()).unwrap_or_default()
246}
247
248/// Check if timer subsystem is ready.
249pub fn is_ready() -> bool {
250    TIMER_READY.load(Ordering::Acquire)
251}
252
253fn systimer_irq_handler() {
254    // Acknowledge the timer interrupt first to prevent interrupt storm
255    crate::hal::al::cpu::systick_ack();
256    let callbacks = with_manager_mut(|mgr| mgr.handle_irq()).unwrap_or_default();
257    run_callbacks(callbacks);
258}
259
260fn run_callbacks(callbacks: Vec<TimerCallback>) {
261    for mut cb in callbacks {
262        (cb)();
263    }
264}
265
266fn into_callback<F>(f: F) -> TimerCallback
267where
268    F: FnOnce() + Send + 'static,
269{
270    let mut opt = Some(f);
271    Box::new(move || {
272        if let Some(inner) = opt.take() {
273            inner();
274        }
275    })
276}
277
278fn with_manager<F, R>(f: F) -> Option<R>
279where
280    F: FnOnce(&TimerManager) -> R,
281{
282    let guard = TIMER_MANAGER.lock();
283    guard.as_ref().map(f)
284}
285
286fn with_manager_mut<F, R>(f: F) -> Option<R>
287where
288    F: FnOnce(&mut TimerManager) -> R,
289{
290    let mut guard = TIMER_MANAGER.lock();
291    guard.as_mut().map(f)
292}