aboutsummaryrefslogtreecommitdiff
path: root/embassy-time/src/driver_std.rs
diff options
context:
space:
mode:
authorQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
committerQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
commit6f02403184eb7fb7990fb88fc9df9c4328a690a3 (patch)
tree748f510e190bb2724750507a6e69ed1a8e08cb20 /embassy-time/src/driver_std.rs
parentd896f80405aa8963877049ed999e4aba25d6e2bb (diff)
parent6b5df4523aa1c4902f02e803450ae4b418e0e3ca (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.rs71
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 @@
1use std::cell::UnsafeCell; 1use core::sync::atomic::{AtomicU8, Ordering};
2use std::cell::{RefCell, UnsafeCell};
2use std::mem::MaybeUninit; 3use std::mem::MaybeUninit;
3use std::sync::{Condvar, Mutex, Once}; 4use std::sync::{Condvar, Mutex, Once};
4use std::time::{Duration as StdDuration, Instant as StdInstant}; 5use std::time::{Duration as StdDuration, Instant as StdInstant};
5use std::{mem, ptr, thread}; 6use std::{mem, ptr, thread};
6 7
7use atomic_polyfill::{AtomicU8, Ordering}; 8use critical_section::Mutex as CsMutex;
8 9
9use crate::driver::{AlarmHandle, Driver}; 10use 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 {
53impl TimeDriver { 57impl 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