capsules_core/virtualizers/
virtual_alarm.rs1use core::cell::Cell;
9
10use kernel::collections::list::{List, ListLink, ListNode};
11use kernel::hil::time::{self, Alarm, Ticks, Time};
12use kernel::utilities::cells::OptionalCell;
13use kernel::ErrorCode;
14
15#[derive(Copy, Clone)]
16struct TickDtReference<T: Ticks> {
17 reference: T,
19 dt: T,
22 extended: bool,
26}
27
28impl<T: Ticks> TickDtReference<T> {
29 #[inline]
30 fn reference_plus_dt(&self) -> T {
31 self.reference.wrapping_add(self.dt)
32 }
33}
34
35pub struct VirtualMuxAlarm<'a, A: Alarm<'a>> {
38 mux: &'a MuxAlarm<'a, A>,
40 dt_reference: Cell<TickDtReference<A::Ticks>>,
42 armed: Cell<bool>,
45 next: ListLink<'a, VirtualMuxAlarm<'a, A>>,
47 client: OptionalCell<&'a dyn time::AlarmClient>,
49}
50
51impl<'a, A: Alarm<'a>> ListNode<'a, VirtualMuxAlarm<'a, A>> for VirtualMuxAlarm<'a, A> {
52 fn next(&self) -> &'a ListLink<VirtualMuxAlarm<'a, A>> {
53 &self.next
54 }
55}
56
57impl<'a, A: Alarm<'a>> VirtualMuxAlarm<'a, A> {
58 pub fn new(mux_alarm: &'a MuxAlarm<'a, A>) -> VirtualMuxAlarm<'a, A> {
60 let zero = A::Ticks::from(0);
61 VirtualMuxAlarm {
62 mux: mux_alarm,
63 dt_reference: Cell::new(TickDtReference {
64 reference: zero,
65 dt: zero,
66 extended: false,
67 }),
68 armed: Cell::new(false),
69 next: ListLink::empty(),
70 client: OptionalCell::empty(),
71 }
72 }
73
74 pub fn setup(&'a self) {
77 self.mux.virtual_alarms.push_head(self);
78 }
79}
80
81impl<'a, A: Alarm<'a>> Time for VirtualMuxAlarm<'a, A> {
82 type Frequency = A::Frequency;
83 type Ticks = A::Ticks;
84
85 fn now(&self) -> Self::Ticks {
86 self.mux.alarm.now()
87 }
88}
89
90impl<'a, A: Alarm<'a>> Alarm<'a> for VirtualMuxAlarm<'a, A> {
91 fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) {
92 self.client.set(client);
93 }
94
95 fn disarm(&self) -> Result<(), ErrorCode> {
96 if !self.armed.get() {
97 return Ok(());
98 }
99
100 self.armed.set(false);
101
102 let enabled = self.mux.enabled.get() - 1;
103 self.mux.enabled.set(enabled);
104
105 if enabled == 0 {
108 let _ = self.mux.alarm.disarm();
109 }
110 Ok(())
111 }
112
113 fn is_armed(&self) -> bool {
114 self.armed.get()
115 }
116
117 fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
118 let enabled = self.mux.enabled.get();
119 let half_max = Self::Ticks::half_max_value();
120 let dt_reference = if dt > half_max.wrapping_add(self.minimum_dt()) {
125 TickDtReference {
126 reference,
127 dt: dt.wrapping_sub(half_max),
128 extended: true,
129 }
130 } else {
131 TickDtReference {
132 reference,
133 dt,
134 extended: false,
135 }
136 };
137 self.dt_reference.set(dt_reference);
138 let dt = dt_reference.dt;
140
141 if !self.armed.get() {
142 self.mux.enabled.set(enabled + 1);
143 self.armed.set(true);
144 }
145
146 if enabled == 0 {
148 self.mux.set_alarm(reference, dt);
150 } else if !self.mux.firing.get() {
151 let cur_alarm = self.mux.alarm.get_alarm();
165 let now = self.mux.alarm.now();
166 let expiration = reference.wrapping_add(dt);
167 if !cur_alarm.within_range(reference, expiration) {
168 let next = self.mux.next_tick_vals.get();
169 if next.is_none_or(|(next_reference, next_dt)| {
170 now.within_range(next_reference, next_reference.wrapping_add(next_dt))
171 }) {
172 self.mux.set_alarm(reference, dt);
173 }
174 } else {
175 }
177 }
178 }
179
180 fn get_alarm(&self) -> Self::Ticks {
181 let dt_reference = self.dt_reference.get();
182 let extension = if dt_reference.extended {
183 Self::Ticks::half_max_value()
184 } else {
185 Self::Ticks::from(0)
186 };
187 dt_reference.reference_plus_dt().wrapping_add(extension)
188 }
189
190 fn minimum_dt(&self) -> Self::Ticks {
191 self.mux.alarm.minimum_dt()
192 }
193}
194
195impl<'a, A: Alarm<'a>> time::AlarmClient for VirtualMuxAlarm<'a, A> {
196 fn alarm(&self) {
197 self.client.map(|client| client.alarm());
198 }
199}
200
201pub struct MuxAlarm<'a, A: Alarm<'a>> {
203 virtual_alarms: List<'a, VirtualMuxAlarm<'a, A>>,
205 enabled: Cell<usize>,
207 alarm: &'a A,
209 firing: Cell<bool>,
211 next_tick_vals: Cell<Option<(A::Ticks, A::Ticks)>>,
213}
214
215impl<'a, A: Alarm<'a>> MuxAlarm<'a, A> {
216 pub const fn new(alarm: &'a A) -> MuxAlarm<'a, A> {
217 MuxAlarm {
218 virtual_alarms: List::new(),
219 enabled: Cell::new(0),
220 alarm,
221 firing: Cell::new(false),
222 next_tick_vals: Cell::new(None),
223 }
224 }
225
226 pub fn set_alarm(&self, reference: A::Ticks, dt: A::Ticks) {
227 self.next_tick_vals.set(Some((reference, dt)));
228 self.alarm.set_alarm(reference, dt);
229 }
230
231 pub fn disarm(&self) {
232 self.next_tick_vals.set(None);
233 let _ = self.alarm.disarm();
234 }
235}
236
237impl<'a, A: Alarm<'a>> time::AlarmClient for MuxAlarm<'a, A> {
238 fn alarm(&self) {
241 self.firing.set(true);
244 self.virtual_alarms
245 .iter()
246 .filter(|cur| {
247 let dt_ref = cur.dt_reference.get();
248 let now = self.alarm.now();
252 cur.armed.get() && !now.within_range(dt_ref.reference, dt_ref.reference_plus_dt())
253 })
254 .for_each(|cur| {
255 let dt_ref = cur.dt_reference.get();
256 if dt_ref.extended {
257 cur.dt_reference.set(TickDtReference {
260 reference: dt_ref.reference_plus_dt(),
261 dt: A::Ticks::half_max_value(),
262 extended: false,
263 });
264 } else {
265 cur.armed.set(false);
267 self.enabled.set(self.enabled.get() - 1);
268 cur.alarm();
270 }
271 });
272 self.firing.set(false);
273 let now = self.alarm.now();
277 let next = self
278 .virtual_alarms
279 .iter()
280 .filter(|cur| cur.armed.get())
281 .min_by_key(|cur| {
282 let when = cur.dt_reference.get();
283 if !now.within_range(when.reference, when.reference_plus_dt()) {
289 A::Ticks::from(0u32)
290 } else {
291 when.reference_plus_dt().wrapping_sub(now)
292 }
293 });
294
295 if let Some(valrm) = next {
297 let dt_reference = valrm.dt_reference.get();
298 self.set_alarm(dt_reference.reference, dt_reference.dt);
299 } else {
300 self.disarm();
301 }
302 }
303}
304
305#[cfg(test)]
306mod tests {
307 use super::*;
308 use time::*;
309
310 struct FakeAlarm<'a> {
311 now: Cell<Ticks32>,
312 reference: Cell<Ticks32>,
313 dt: Cell<Ticks32>,
314 armed: Cell<bool>,
315 client: OptionalCell<&'a dyn AlarmClient>,
316 }
317
318 impl FakeAlarm<'_> {
319 fn new() -> Self {
320 Self {
321 now: Cell::new(1_000u32.into()),
322 reference: Cell::new(0u32.into()),
323 dt: Cell::new(0u32.into()),
324 armed: Cell::new(false),
325 client: OptionalCell::empty(),
326 }
327 }
328
329 pub fn hardware_delay(&self) -> Ticks32 {
332 Ticks32::from(10)
333 }
334
335 pub fn trigger_next_alarm(&self) -> bool {
338 if !self.is_armed() {
339 return false;
340 }
341 self.now.set(
342 self.reference
343 .get()
344 .wrapping_add(self.dt.get())
345 .wrapping_add(self.hardware_delay()),
346 );
347 self.client.map(|c| c.alarm());
348 self.is_armed()
349 }
350
351 pub fn run_for_ticks(&self, left: Ticks32) {
353 let final_now = self.now.get().wrapping_add(left);
354 let mut left = left.into_u32();
355
356 while self.is_armed() {
357 let ticks_from_reference = self.now.get().wrapping_sub(self.reference.get());
361 let dt = self
362 .dt
363 .get()
364 .into_u32()
365 .saturating_sub(ticks_from_reference.into_u32());
366 if dt <= left {
367 left -= dt;
368 self.trigger_next_alarm();
369 } else {
370 break;
371 }
372 }
373 self.now.set(final_now);
375 }
376 }
377
378 impl Time for FakeAlarm<'_> {
379 type Ticks = Ticks32;
380 type Frequency = Freq1KHz;
381
382 fn now(&self) -> Ticks32 {
383 let new_now = Ticks32::from(self.now.get().into_u32() + 1);
385 self.now.set(new_now);
386 new_now
387 }
388 }
389
390 impl<'a> Alarm<'a> for FakeAlarm<'a> {
391 fn set_alarm_client(&self, client: &'a dyn AlarmClient) {
392 self.client.set(client);
393 }
394
395 fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
396 self.reference.set(reference);
397 self.dt.set(dt);
398 self.armed.set(true);
399 }
400
401 fn get_alarm(&self) -> Self::Ticks {
402 self.reference.get().wrapping_add(self.dt.get())
403 }
404
405 fn disarm(&self) -> Result<(), ErrorCode> {
406 self.armed.set(false);
407 Ok(())
408 }
409
410 fn is_armed(&self) -> bool {
411 self.armed.get()
412 }
413
414 fn minimum_dt(&self) -> Self::Ticks {
415 0u32.into()
416 }
417 }
418
419 struct ClientCounter(Cell<usize>);
420 impl ClientCounter {
421 fn new() -> Self {
422 Self(Cell::new(0))
423 }
424 fn count(&self) -> usize {
425 self.0.get()
426 }
427 }
428 impl AlarmClient for ClientCounter {
429 fn alarm(&self) {
430 self.0.set(self.0.get() + 1);
431 }
432 }
433
434 fn run_until_disarmed(alarm: &FakeAlarm) {
435 for _ in 0..20 {
437 if !alarm.trigger_next_alarm() {
438 return;
439 }
440 }
441 }
442
443 #[test]
444 fn test_single_max_ticks_dt() {
445 let alarm = FakeAlarm::new();
446 let client = ClientCounter::new();
447 let dt = u32::MAX.into();
448
449 let mux = MuxAlarm::new(&alarm);
450 alarm.set_alarm_client(&mux);
451
452 let valarm = VirtualMuxAlarm::new(&mux);
453 valarm.setup();
454 valarm.set_alarm_client(&client);
455 valarm.set_alarm(valarm.now(), dt);
456
457 run_until_disarmed(&alarm);
458
459 assert_eq!(client.count(), 1);
460 }
461
462 #[test]
463 fn test_multiple_max_ticks_dt() {
464 let alarm = FakeAlarm::new();
465 let client = ClientCounter::new();
466 let dt = u32::MAX.into();
467
468 let mux = MuxAlarm::new(&alarm);
469 alarm.set_alarm_client(&mux);
470
471 let v_alarms = &[
472 VirtualMuxAlarm::new(&mux),
473 VirtualMuxAlarm::new(&mux),
474 VirtualMuxAlarm::new(&mux),
475 ];
476
477 for (i, v) in v_alarms.iter().enumerate() {
478 v.setup();
479 v.set_alarm_client(&client);
480 v.set_alarm((i as u32).into(), dt);
482 }
483 run_until_disarmed(&alarm);
484
485 assert_eq!(client.count(), 3);
486 }
487
488 struct SetAlarmClient<'a> {
489 alarm: &'a VirtualMuxAlarm<'a, FakeAlarm<'a>>,
490 dt: u32,
491 }
492
493 impl<'a> SetAlarmClient<'a> {
494 fn new(alarm: &'a VirtualMuxAlarm<'a, FakeAlarm<'a>>, dt: u32) -> Self {
495 Self { alarm, dt }
496 }
497 }
498
499 impl AlarmClient for SetAlarmClient<'_> {
500 fn alarm(&self) {
501 self.alarm.set_alarm(self.alarm.now(), self.dt.into());
502 }
503 }
504
505 #[test]
506 fn test_second_alarm_set_during_first_alarm_firing() {
507 let alarm = FakeAlarm::new();
508 let mux = MuxAlarm::new(&alarm);
509 alarm.set_alarm_client(&mux);
510
511 let v_alarms = &[VirtualMuxAlarm::new(&mux), VirtualMuxAlarm::new(&mux)];
513 v_alarms[1].setup();
514 v_alarms[0].setup();
515
516 let set_v1_alarm = SetAlarmClient::new(&v_alarms[1], 100);
517 v_alarms[0].set_alarm_client(&set_v1_alarm);
518
519 let counter = ClientCounter::new();
520 v_alarms[1].set_alarm_client(&counter);
521
522 v_alarms[0].set_alarm(0.into(), 10.into());
525 let still_armed = alarm.trigger_next_alarm();
526
527 assert!(alarm.now().into_u32() < 100);
529 assert_eq!(counter.count(), 0);
530 assert!(still_armed);
531
532 let still_armed = alarm.trigger_next_alarm();
533
534 assert!(alarm.now().into_u32() > 100);
535 assert_eq!(counter.count(), 1);
536 assert!(!still_armed);
537 }
538
539 #[test]
540 fn test_quick_alarms_not_skipped() {
541 let alarm = FakeAlarm::new();
542 let client = ClientCounter::new();
543
544 let mux = MuxAlarm::new(&alarm);
545 alarm.set_alarm_client(&mux);
546
547 let v_alarms = &[
548 VirtualMuxAlarm::new(&mux),
549 VirtualMuxAlarm::new(&mux),
550 VirtualMuxAlarm::new(&mux),
551 VirtualMuxAlarm::new(&mux),
552 VirtualMuxAlarm::new(&mux),
553 VirtualMuxAlarm::new(&mux),
554 ];
555
556 let now = alarm.now();
561 let dt = alarm
562 .hardware_delay()
563 .wrapping_add(Ticks32::from(v_alarms.len() as u32));
564
565 for v in v_alarms {
566 v.setup();
567 v.set_alarm_client(&client);
568 v.set_alarm(now, dt);
569 }
570
571 v_alarms[0].set_alarm(now, 0.into());
574 v_alarms[1].set_alarm(now, 1_000.into());
575
576 alarm.run_for_ticks(Ticks32::from(750));
579 assert_eq!(client.count(), v_alarms.len() - 1);
580 alarm.run_for_ticks(Ticks32::from(750));
582 assert_eq!(client.count(), v_alarms.len());
583 }
584}