aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/time/driver_std.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/time/driver_std.rs')
-rw-r--r--embassy-executor/src/time/driver_std.rs208
1 files changed, 0 insertions, 208 deletions
diff --git a/embassy-executor/src/time/driver_std.rs b/embassy-executor/src/time/driver_std.rs
deleted file mode 100644
index cb66f7c19..000000000
--- a/embassy-executor/src/time/driver_std.rs
+++ /dev/null
@@ -1,208 +0,0 @@
1use std::cell::UnsafeCell;
2use std::mem::MaybeUninit;
3use std::sync::{Condvar, Mutex, Once};
4use std::time::{Duration as StdDuration, Instant as StdInstant};
5use std::{mem, ptr, thread};
6
7use atomic_polyfill::{AtomicU8, Ordering};
8
9use crate::time::driver::{AlarmHandle, Driver};
10
11const ALARM_COUNT: usize = 4;
12
13struct AlarmState {
14 timestamp: u64,
15
16 // This is really a Option<(fn(*mut ()), *mut ())>
17 // but fn pointers aren't allowed in const yet
18 callback: *const (),
19 ctx: *mut (),
20}
21
22unsafe impl Send for AlarmState {}
23
24impl AlarmState {
25 const fn new() -> Self {
26 Self {
27 timestamp: u64::MAX,
28 callback: ptr::null(),
29 ctx: ptr::null_mut(),
30 }
31 }
32}
33
34struct TimeDriver {
35 alarm_count: AtomicU8,
36
37 once: Once,
38 alarms: UninitCell<Mutex<[AlarmState; ALARM_COUNT]>>,
39 zero_instant: UninitCell<StdInstant>,
40 signaler: UninitCell<Signaler>,
41}
42
43const ALARM_NEW: AlarmState = AlarmState::new();
44crate::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
45 alarm_count: AtomicU8::new(0),
46
47 once: Once::new(),
48 alarms: UninitCell::uninit(),
49 zero_instant: UninitCell::uninit(),
50 signaler: UninitCell::uninit(),
51});
52
53impl TimeDriver {
54 fn init(&self) {
55 self.once.call_once(|| unsafe {
56 self.alarms.write(Mutex::new([ALARM_NEW; ALARM_COUNT]));
57 self.zero_instant.write(StdInstant::now());
58 self.signaler.write(Signaler::new());
59
60 thread::spawn(Self::alarm_thread);
61 });
62 }
63
64 fn alarm_thread() {
65 let zero = unsafe { DRIVER.zero_instant.read() };
66 loop {
67 let now = DRIVER.now();
68
69 let mut next_alarm = u64::MAX;
70 {
71 let alarms = &mut *unsafe { DRIVER.alarms.as_ref() }.lock().unwrap();
72 for alarm in alarms {
73 if alarm.timestamp <= now {
74 alarm.timestamp = u64::MAX;
75
76 // Call after clearing alarm, so the callback can set another alarm.
77
78 // safety:
79 // - 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
81 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback) };
82 f(alarm.ctx);
83 } else {
84 next_alarm = next_alarm.min(alarm.timestamp);
85 }
86 }
87 }
88
89 // Ensure we don't overflow
90 let until = zero
91 .checked_add(StdDuration::from_micros(next_alarm))
92 .unwrap_or_else(|| StdInstant::now() + StdDuration::from_secs(1));
93
94 unsafe { DRIVER.signaler.as_ref() }.wait_until(until);
95 }
96 }
97}
98
99impl Driver for TimeDriver {
100 fn now(&self) -> u64 {
101 self.init();
102
103 let zero = unsafe { self.zero_instant.read() };
104 StdInstant::now().duration_since(zero).as_micros() as u64
105 }
106
107 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
108 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
109 if x < ALARM_COUNT as u8 {
110 Some(x + 1)
111 } else {
112 None
113 }
114 });
115
116 match id {
117 Ok(id) => Some(AlarmHandle::new(id)),
118 Err(_) => None,
119 }
120 }
121
122 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
123 self.init();
124 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
125 let alarm = &mut alarms[alarm.id() as usize];
126 alarm.callback = callback as *const ();
127 alarm.ctx = ctx;
128 }
129
130 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
131 self.init();
132 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
133 let alarm = &mut alarms[alarm.id() as usize];
134 alarm.timestamp = timestamp;
135 unsafe { self.signaler.as_ref() }.signal();
136 }
137}
138
139struct Signaler {
140 mutex: Mutex<bool>,
141 condvar: Condvar,
142}
143
144impl Signaler {
145 fn new() -> Self {
146 Self {
147 mutex: Mutex::new(false),
148 condvar: Condvar::new(),
149 }
150 }
151
152 fn wait_until(&self, until: StdInstant) {
153 let mut signaled = self.mutex.lock().unwrap();
154 while !*signaled {
155 let now = StdInstant::now();
156
157 if now >= until {
158 break;
159 }
160
161 let dur = until - now;
162 let (signaled2, timeout) = self.condvar.wait_timeout(signaled, dur).unwrap();
163 signaled = signaled2;
164 if timeout.timed_out() {
165 break;
166 }
167 }
168 *signaled = false;
169 }
170
171 fn signal(&self) {
172 let mut signaled = self.mutex.lock().unwrap();
173 *signaled = true;
174 self.condvar.notify_one();
175 }
176}
177
178pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>);
179unsafe impl<T> Send for UninitCell<T> {}
180unsafe impl<T> Sync for UninitCell<T> {}
181
182impl<T> UninitCell<T> {
183 pub const fn uninit() -> Self {
184 Self(MaybeUninit::uninit())
185 }
186
187 pub unsafe fn as_ptr(&self) -> *const T {
188 (*self.0.as_ptr()).get()
189 }
190
191 pub unsafe fn as_mut_ptr(&self) -> *mut T {
192 (*self.0.as_ptr()).get()
193 }
194
195 pub unsafe fn as_ref(&self) -> &T {
196 &*self.as_ptr()
197 }
198
199 pub unsafe fn write(&self, val: T) {
200 ptr::write(self.as_mut_ptr(), val)
201 }
202}
203
204impl<T: Copy> UninitCell<T> {
205 pub unsafe fn read(&self) -> T {
206 ptr::read(self.as_mut_ptr())
207 }
208}