aboutsummaryrefslogtreecommitdiff
path: root/embassy-time/src/queue_generic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-time/src/queue_generic.rs')
-rw-r--r--embassy-time/src/queue_generic.rs348
1 files changed, 0 insertions, 348 deletions
diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs
deleted file mode 100644
index 4882afd3e..000000000
--- a/embassy-time/src/queue_generic.rs
+++ /dev/null
@@ -1,348 +0,0 @@
1use core::cell::RefCell;
2use core::cmp::{min, Ordering};
3use core::task::Waker;
4
5use critical_section::Mutex;
6use embassy_time_driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle};
7use embassy_time_queue_driver::TimerQueue;
8use heapless::Vec;
9
10use crate::Instant;
11
12#[cfg(feature = "generic-queue-8")]
13const QUEUE_SIZE: usize = 8;
14#[cfg(feature = "generic-queue-16")]
15const QUEUE_SIZE: usize = 16;
16#[cfg(feature = "generic-queue-32")]
17const QUEUE_SIZE: usize = 32;
18#[cfg(feature = "generic-queue-64")]
19const QUEUE_SIZE: usize = 64;
20#[cfg(feature = "generic-queue-128")]
21const QUEUE_SIZE: usize = 128;
22#[cfg(not(any(
23 feature = "generic-queue-8",
24 feature = "generic-queue-16",
25 feature = "generic-queue-32",
26 feature = "generic-queue-64",
27 feature = "generic-queue-128"
28)))]
29const QUEUE_SIZE: usize = 64;
30
31#[derive(Debug)]
32struct Timer {
33 at: Instant,
34 waker: Waker,
35}
36
37impl PartialEq for Timer {
38 fn eq(&self, other: &Self) -> bool {
39 self.at == other.at
40 }
41}
42
43impl Eq for Timer {}
44
45impl PartialOrd for Timer {
46 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
47 self.at.partial_cmp(&other.at)
48 }
49}
50
51impl Ord for Timer {
52 fn cmp(&self, other: &Self) -> Ordering {
53 self.at.cmp(&other.at)
54 }
55}
56
57struct InnerQueue {
58 queue: Vec<Timer, QUEUE_SIZE>,
59 alarm: AlarmHandle,
60}
61
62impl InnerQueue {
63 fn schedule_wake(&mut self, at: Instant, waker: &Waker) {
64 self.queue
65 .iter_mut()
66 .find(|timer| timer.waker.will_wake(waker))
67 .map(|timer| {
68 timer.at = min(timer.at, at);
69 })
70 .unwrap_or_else(|| {
71 let mut timer = Timer {
72 waker: waker.clone(),
73 at,
74 };
75
76 loop {
77 match self.queue.push(timer) {
78 Ok(()) => break,
79 Err(e) => timer = e,
80 }
81
82 self.queue.pop().unwrap().waker.wake();
83 }
84 });
85
86 // Don't wait for the alarm callback to trigger and directly
87 // dispatch all timers that are already due
88 //
89 // Then update the alarm if necessary
90 self.dispatch();
91 }
92
93 fn dispatch(&mut self) {
94 loop {
95 let now = Instant::now();
96
97 let mut next_alarm = Instant::MAX;
98
99 let mut i = 0;
100 while i < self.queue.len() {
101 let timer = &self.queue[i];
102 if timer.at <= now {
103 let timer = self.queue.swap_remove(i);
104 timer.waker.wake();
105 } else {
106 next_alarm = min(next_alarm, timer.at);
107 i += 1;
108 }
109 }
110
111 if self.update_alarm(next_alarm) {
112 break;
113 }
114 }
115 }
116
117 fn update_alarm(&mut self, next_alarm: Instant) -> bool {
118 if next_alarm == Instant::MAX {
119 true
120 } else {
121 set_alarm(self.alarm, next_alarm.as_ticks())
122 }
123 }
124
125 fn handle_alarm(&mut self) {
126 self.dispatch();
127 }
128}
129
130struct Queue {
131 inner: Mutex<RefCell<Option<InnerQueue>>>,
132}
133
134impl Queue {
135 const fn new() -> Self {
136 Self {
137 inner: Mutex::new(RefCell::new(None)),
138 }
139 }
140
141 fn schedule_wake(&'static self, at: Instant, waker: &Waker) {
142 critical_section::with(|cs| {
143 let mut inner = self.inner.borrow_ref_mut(cs);
144
145 if inner.is_none() {}
146
147 inner
148 .get_or_insert_with(|| {
149 let handle = unsafe { allocate_alarm() }.unwrap();
150 set_alarm_callback(handle, Self::handle_alarm_callback, self as *const _ as _);
151 InnerQueue {
152 queue: Vec::new(),
153 alarm: handle,
154 }
155 })
156 .schedule_wake(at, waker)
157 });
158 }
159
160 fn handle_alarm(&self) {
161 critical_section::with(|cs| self.inner.borrow_ref_mut(cs).as_mut().unwrap().handle_alarm())
162 }
163
164 fn handle_alarm_callback(ctx: *mut ()) {
165 unsafe { (ctx as *const Self).as_ref().unwrap() }.handle_alarm();
166 }
167}
168
169impl TimerQueue for Queue {
170 fn schedule_wake(&'static self, at: u64, waker: &Waker) {
171 Queue::schedule_wake(self, Instant::from_ticks(at), waker);
172 }
173}
174
175embassy_time_queue_driver::timer_queue_impl!(static QUEUE: Queue = Queue::new());
176
177#[cfg(test)]
178#[cfg(feature = "mock-driver")]
179mod tests {
180 use core::sync::atomic::{AtomicBool, Ordering};
181 use core::task::Waker;
182 use std::sync::Arc;
183 use std::task::Wake;
184
185 use serial_test::serial;
186
187 use crate::driver_mock::MockDriver;
188 use crate::queue_generic::QUEUE;
189 use crate::{Duration, Instant};
190
191 struct TestWaker {
192 pub awoken: AtomicBool,
193 }
194
195 impl Wake for TestWaker {
196 fn wake(self: Arc<Self>) {
197 self.awoken.store(true, Ordering::Relaxed);
198 }
199
200 fn wake_by_ref(self: &Arc<Self>) {
201 self.awoken.store(true, Ordering::Relaxed);
202 }
203 }
204
205 fn test_waker() -> (Arc<TestWaker>, Waker) {
206 let arc = Arc::new(TestWaker {
207 awoken: AtomicBool::new(false),
208 });
209 let waker = Waker::from(arc.clone());
210
211 (arc, waker)
212 }
213
214 fn setup() {
215 MockDriver::get().reset();
216 critical_section::with(|cs| *QUEUE.inner.borrow_ref_mut(cs) = None);
217 }
218
219 fn queue_len() -> usize {
220 critical_section::with(|cs| {
221 QUEUE
222 .inner
223 .borrow_ref(cs)
224 .as_ref()
225 .map(|inner| inner.queue.iter().count())
226 .unwrap_or(0)
227 })
228 }
229
230 #[test]
231 #[serial]
232 fn test_schedule() {
233 setup();
234
235 assert_eq!(queue_len(), 0);
236
237 let (flag, waker) = test_waker();
238
239 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
240
241 assert!(!flag.awoken.load(Ordering::Relaxed));
242 assert_eq!(queue_len(), 1);
243 }
244
245 #[test]
246 #[serial]
247 fn test_schedule_same() {
248 setup();
249
250 let (_flag, waker) = test_waker();
251
252 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
253
254 assert_eq!(queue_len(), 1);
255
256 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
257
258 assert_eq!(queue_len(), 1);
259
260 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
261
262 assert_eq!(queue_len(), 1);
263
264 let (_flag2, waker2) = test_waker();
265
266 QUEUE.schedule_wake(Instant::from_secs(100), &waker2);
267
268 assert_eq!(queue_len(), 2);
269 }
270
271 #[test]
272 #[serial]
273 fn test_trigger() {
274 setup();
275
276 let (flag, waker) = test_waker();
277
278 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
279
280 assert!(!flag.awoken.load(Ordering::Relaxed));
281
282 MockDriver::get().advance(Duration::from_secs(99));
283
284 assert!(!flag.awoken.load(Ordering::Relaxed));
285
286 assert_eq!(queue_len(), 1);
287
288 MockDriver::get().advance(Duration::from_secs(1));
289
290 assert!(flag.awoken.load(Ordering::Relaxed));
291
292 assert_eq!(queue_len(), 0);
293 }
294
295 #[test]
296 #[serial]
297 fn test_immediate_trigger() {
298 setup();
299
300 let (flag, waker) = test_waker();
301
302 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
303
304 MockDriver::get().advance(Duration::from_secs(50));
305
306 let (flag2, waker2) = test_waker();
307
308 QUEUE.schedule_wake(Instant::from_secs(40), &waker2);
309
310 assert!(!flag.awoken.load(Ordering::Relaxed));
311 assert!(flag2.awoken.load(Ordering::Relaxed));
312 assert_eq!(queue_len(), 1);
313 }
314
315 #[test]
316 #[serial]
317 fn test_queue_overflow() {
318 setup();
319
320 for i in 1..super::QUEUE_SIZE {
321 let (flag, waker) = test_waker();
322
323 QUEUE.schedule_wake(Instant::from_secs(310), &waker);
324
325 assert_eq!(queue_len(), i);
326 assert!(!flag.awoken.load(Ordering::Relaxed));
327 }
328
329 let (flag, waker) = test_waker();
330
331 QUEUE.schedule_wake(Instant::from_secs(300), &waker);
332
333 assert_eq!(queue_len(), super::QUEUE_SIZE);
334 assert!(!flag.awoken.load(Ordering::Relaxed));
335
336 let (flag2, waker2) = test_waker();
337
338 QUEUE.schedule_wake(Instant::from_secs(305), &waker2);
339
340 assert_eq!(queue_len(), super::QUEUE_SIZE);
341 assert!(flag.awoken.load(Ordering::Relaxed));
342
343 let (_flag3, waker3) = test_waker();
344 QUEUE.schedule_wake(Instant::from_secs(320), &waker3);
345 assert_eq!(queue_len(), super::QUEUE_SIZE);
346 assert!(flag2.awoken.load(Ordering::Relaxed));
347 }
348}