diff options
| author | Quentin Smith <[email protected]> | 2023-07-17 21:31:43 -0400 |
|---|---|---|
| committer | Quentin Smith <[email protected]> | 2023-07-17 21:31:43 -0400 |
| commit | 6f02403184eb7fb7990fb88fc9df9c4328a690a3 (patch) | |
| tree | 748f510e190bb2724750507a6e69ed1a8e08cb20 /embassy-time/src/driver_std.rs | |
| parent | d896f80405aa8963877049ed999e4aba25d6e2bb (diff) | |
| parent | 6b5df4523aa1c4902f02e803450ae4b418e0e3ca (diff) | |
Merge remote-tracking branch 'origin/main' into nrf-pdm
Diffstat (limited to 'embassy-time/src/driver_std.rs')
| -rw-r--r-- | embassy-time/src/driver_std.rs | 71 |
1 files changed, 47 insertions, 24 deletions
diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index 2ddb2e604..32db47a37 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs | |||
| @@ -1,10 +1,11 @@ | |||
| 1 | use std::cell::UnsafeCell; | 1 | use core::sync::atomic::{AtomicU8, Ordering}; |
| 2 | use std::cell::{RefCell, UnsafeCell}; | ||
| 2 | use std::mem::MaybeUninit; | 3 | use std::mem::MaybeUninit; |
| 3 | use std::sync::{Condvar, Mutex, Once}; | 4 | use std::sync::{Condvar, Mutex, Once}; |
| 4 | use std::time::{Duration as StdDuration, Instant as StdInstant}; | 5 | use std::time::{Duration as StdDuration, Instant as StdInstant}; |
| 5 | use std::{mem, ptr, thread}; | 6 | use std::{mem, ptr, thread}; |
| 6 | 7 | ||
| 7 | use atomic_polyfill::{AtomicU8, Ordering}; | 8 | use critical_section::Mutex as CsMutex; |
| 8 | 9 | ||
| 9 | use crate::driver::{AlarmHandle, Driver}; | 10 | use crate::driver::{AlarmHandle, Driver}; |
| 10 | 11 | ||
| @@ -35,7 +36,10 @@ struct TimeDriver { | |||
| 35 | alarm_count: AtomicU8, | 36 | alarm_count: AtomicU8, |
| 36 | 37 | ||
| 37 | once: Once, | 38 | once: Once, |
| 38 | alarms: UninitCell<Mutex<[AlarmState; ALARM_COUNT]>>, | 39 | // The STD Driver implementation requires the alarms' mutex to be reentrant, which the STD Mutex isn't |
| 40 | // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections | ||
| 41 | // themselves are reentrant | ||
| 42 | alarms: UninitCell<CsMutex<RefCell<[AlarmState; ALARM_COUNT]>>>, | ||
| 39 | zero_instant: UninitCell<StdInstant>, | 43 | zero_instant: UninitCell<StdInstant>, |
| 40 | signaler: UninitCell<Signaler>, | 44 | signaler: UninitCell<Signaler>, |
| 41 | } | 45 | } |
| @@ -53,7 +57,7 @@ crate::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { | |||
| 53 | impl TimeDriver { | 57 | impl TimeDriver { |
| 54 | fn init(&self) { | 58 | fn init(&self) { |
| 55 | self.once.call_once(|| unsafe { | 59 | self.once.call_once(|| unsafe { |
| 56 | self.alarms.write(Mutex::new([ALARM_NEW; ALARM_COUNT])); | 60 | self.alarms.write(CsMutex::new(RefCell::new([ALARM_NEW; ALARM_COUNT]))); |
| 57 | self.zero_instant.write(StdInstant::now()); | 61 | self.zero_instant.write(StdInstant::now()); |
| 58 | self.signaler.write(Signaler::new()); | 62 | self.signaler.write(Signaler::new()); |
| 59 | 63 | ||
| @@ -66,25 +70,38 @@ impl TimeDriver { | |||
| 66 | loop { | 70 | loop { |
| 67 | let now = DRIVER.now(); | 71 | let now = DRIVER.now(); |
| 68 | 72 | ||
| 69 | let mut next_alarm = u64::MAX; | 73 | let next_alarm = critical_section::with(|cs| { |
| 70 | { | 74 | let alarms = unsafe { DRIVER.alarms.as_ref() }.borrow(cs); |
| 71 | let alarms = &mut *unsafe { DRIVER.alarms.as_ref() }.lock().unwrap(); | 75 | loop { |
| 72 | for alarm in alarms { | 76 | let pending = alarms |
| 73 | if alarm.timestamp <= now { | 77 | .borrow_mut() |
| 74 | alarm.timestamp = u64::MAX; | 78 | .iter_mut() |
| 79 | .find(|alarm| alarm.timestamp <= now) | ||
| 80 | .map(|alarm| { | ||
| 81 | alarm.timestamp = u64::MAX; | ||
| 75 | 82 | ||
| 76 | // Call after clearing alarm, so the callback can set another alarm. | 83 | (alarm.callback, alarm.ctx) |
| 84 | }); | ||
| 77 | 85 | ||
| 86 | if let Some((callback, ctx)) = pending { | ||
| 78 | // safety: | 87 | // safety: |
| 79 | // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`. | 88 | // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`. |
| 80 | // - other than that we only store valid function pointers into alarm.callback | 89 | // - other than that we only store valid function pointers into alarm.callback |
| 81 | let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback) }; | 90 | let f: fn(*mut ()) = unsafe { mem::transmute(callback) }; |
| 82 | f(alarm.ctx); | 91 | f(ctx); |
| 83 | } else { | 92 | } else { |
| 84 | next_alarm = next_alarm.min(alarm.timestamp); | 93 | // No alarm due |
| 94 | break; | ||
| 85 | } | 95 | } |
| 86 | } | 96 | } |
| 87 | } | 97 | |
| 98 | alarms | ||
| 99 | .borrow() | ||
| 100 | .iter() | ||
| 101 | .map(|alarm| alarm.timestamp) | ||
| 102 | .min() | ||
| 103 | .unwrap_or(u64::MAX) | ||
| 104 | }); | ||
| 88 | 105 | ||
| 89 | // Ensure we don't overflow | 106 | // Ensure we don't overflow |
| 90 | let until = zero | 107 | let until = zero |
| @@ -121,18 +138,24 @@ impl Driver for TimeDriver { | |||
| 121 | 138 | ||
| 122 | fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { | 139 | fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { |
| 123 | self.init(); | 140 | self.init(); |
| 124 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); | 141 | critical_section::with(|cs| { |
| 125 | let alarm = &mut alarms[alarm.id() as usize]; | 142 | let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs); |
| 126 | alarm.callback = callback as *const (); | 143 | let alarm = &mut alarms[alarm.id() as usize]; |
| 127 | alarm.ctx = ctx; | 144 | alarm.callback = callback as *const (); |
| 145 | alarm.ctx = ctx; | ||
| 146 | }); | ||
| 128 | } | 147 | } |
| 129 | 148 | ||
| 130 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 149 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 131 | self.init(); | 150 | self.init(); |
| 132 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); | 151 | critical_section::with(|cs| { |
| 133 | let alarm = &mut alarms[alarm.id() as usize]; | 152 | let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs); |
| 134 | alarm.timestamp = timestamp; | 153 | let alarm = &mut alarms[alarm.id() as usize]; |
| 135 | unsafe { self.signaler.as_ref() }.signal(); | 154 | alarm.timestamp = timestamp; |
| 155 | unsafe { self.signaler.as_ref() }.signal(); | ||
| 156 | }); | ||
| 157 | |||
| 158 | true | ||
| 136 | } | 159 | } |
| 137 | } | 160 | } |
| 138 | 161 | ||
