sparreal_kernel/os/time/
timer.rs1use 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: 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
49struct 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 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 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 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 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 self.arm_hardware_timer();
143
144 expired
145 }
146
147 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 let freq = crate::hal::al::cpu::systick_frequency();
156 let min_delay = (freq / 10_000).max(1); 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 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_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
212pub 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
224pub 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
238pub fn cancel(handle: TimerHandle) -> bool {
240 with_manager_mut(|mgr| mgr.cancel(handle)).unwrap_or(false)
241}
242
243pub fn time_list() -> Vec<TimeListEntry> {
245 with_manager(|mgr| mgr.snapshot()).unwrap_or_default()
246}
247
248pub fn is_ready() -> bool {
250 TIMER_READY.load(Ordering::Acquire)
251}
252
253fn systimer_irq_handler() {
254 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}