aboutsummaryrefslogtreecommitdiff
path: root/embassy-time/src/driver_std.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-12-08 23:27:32 +0100
committerDániel Buga <[email protected]>2024-12-13 21:20:59 +0100
commitb268b1795fed58544c166c41842ce0d66328aa3e (patch)
tree55b6fb09f6694b5e3355d344770b36bfe1550415 /embassy-time/src/driver_std.rs
parentec96395d084d5edc8be25ddaea8547e2ebd447a6 (diff)
Merge time-driver and time-queue-driver traits, make HALs own and handle the queue.
Diffstat (limited to 'embassy-time/src/driver_std.rs')
-rw-r--r--embassy-time/src/driver_std.rs155
1 files changed, 44 insertions, 111 deletions
diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs
index 45467f09b..35888fddd 100644
--- a/embassy-time/src/driver_std.rs
+++ b/embassy-time/src/driver_std.rs
@@ -1,96 +1,66 @@
1use std::cell::{RefCell, UnsafeCell}; 1use std::sync::{Condvar, Mutex};
2use std::mem::MaybeUninit; 2use std::thread;
3use std::sync::{Condvar, Mutex, Once};
4use std::time::{Duration as StdDuration, Instant as StdInstant}; 3use std::time::{Duration as StdDuration, Instant as StdInstant};
5use std::{ptr, thread};
6 4
7use critical_section::Mutex as CsMutex;
8use embassy_time_driver::Driver; 5use embassy_time_driver::Driver;
9use embassy_time_queue_driver::GlobalTimerQueue; 6use embassy_time_queue_driver::Queue;
10 7
11struct AlarmState { 8struct TimeDriver {
12 timestamp: u64, 9 signaler: Signaler,
13} 10 inner: Mutex<Inner>,
14
15unsafe impl Send for AlarmState {}
16
17impl AlarmState {
18 const fn new() -> Self {
19 Self { timestamp: u64::MAX }
20 }
21} 11}
22 12
23struct TimeDriver { 13struct Inner {
24 once: Once, 14 zero_instant: Option<StdInstant>,
25 // The STD Driver implementation requires the alarm's mutex to be reentrant, which the STD Mutex isn't 15 queue: Queue,
26 // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections
27 // themselves are reentrant
28 alarm: UninitCell<CsMutex<RefCell<AlarmState>>>,
29 zero_instant: UninitCell<StdInstant>,
30 signaler: UninitCell<Signaler>,
31} 16}
32 17
33embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { 18embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
34 once: Once::new(), 19 inner: Mutex::new(Inner{
35 alarm: UninitCell::uninit(), 20 zero_instant: None,
36 zero_instant: UninitCell::uninit(), 21 queue: Queue::new(),
37 signaler: UninitCell::uninit(), 22 }),
23 signaler: Signaler::new(),
38}); 24});
39 25
40impl TimeDriver { 26impl Inner {
41 fn init(&self) { 27 fn init(&mut self) -> StdInstant {
42 self.once.call_once(|| unsafe { 28 *self.zero_instant.get_or_insert_with(|| {
43 self.alarm 29 thread::spawn(alarm_thread);
44 .write(CsMutex::new(RefCell::new(const { AlarmState::new() }))); 30 StdInstant::now()
45 self.zero_instant.write(StdInstant::now()); 31 })
46 self.signaler.write(Signaler::new());
47
48 thread::spawn(Self::alarm_thread);
49 });
50 } 32 }
33}
51 34
52 fn alarm_thread() { 35impl Driver for TimeDriver {
53 let zero = unsafe { DRIVER.zero_instant.read() }; 36 fn now(&self) -> u64 {
54 loop { 37 let mut inner = self.inner.lock().unwrap();
55 let now = DRIVER.now(); 38 let zero = inner.init();
56 39 StdInstant::now().duration_since(zero).as_micros() as u64
57 let next_alarm = critical_section::with(|cs| { 40 }
58 let mut alarm = unsafe { DRIVER.alarm.as_ref() }.borrow_ref_mut(cs);
59 if alarm.timestamp <= now {
60 alarm.timestamp = u64::MAX;
61
62 TIMER_QUEUE_DRIVER.dispatch();
63 }
64 alarm.timestamp
65 });
66
67 // Ensure we don't overflow
68 let until = zero
69 .checked_add(StdDuration::from_micros(next_alarm))
70 .unwrap_or_else(|| StdInstant::now() + StdDuration::from_secs(1));
71 41
72 unsafe { DRIVER.signaler.as_ref() }.wait_until(until); 42 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
43 let mut inner = self.inner.lock().unwrap();
44 inner.init();
45 if inner.queue.schedule_wake(at, waker) {
46 self.signaler.signal();
73 } 47 }
74 } 48 }
49}
75 50
76 fn set_alarm(&self, timestamp: u64) -> bool { 51fn alarm_thread() {
77 self.init(); 52 let zero = DRIVER.inner.lock().unwrap().zero_instant.unwrap();
78 critical_section::with(|cs| { 53 loop {
79 let mut alarm = unsafe { self.alarm.as_ref() }.borrow_ref_mut(cs); 54 let now = DRIVER.now();
80 alarm.timestamp = timestamp;
81 unsafe { self.signaler.as_ref() }.signal();
82 });
83 55
84 true 56 let next_alarm = DRIVER.inner.lock().unwrap().queue.next_expiration(now);
85 }
86}
87 57
88impl Driver for TimeDriver { 58 // Ensure we don't overflow
89 fn now(&self) -> u64 { 59 let until = zero
90 self.init(); 60 .checked_add(StdDuration::from_micros(next_alarm))
61 .unwrap_or_else(|| StdInstant::now() + StdDuration::from_secs(1));
91 62
92 let zero = unsafe { self.zero_instant.read() }; 63 DRIVER.signaler.wait_until(until);
93 StdInstant::now().duration_since(zero).as_micros() as u64
94 } 64 }
95} 65}
96 66
@@ -100,7 +70,7 @@ struct Signaler {
100} 70}
101 71
102impl Signaler { 72impl Signaler {
103 fn new() -> Self { 73 const fn new() -> Self {
104 Self { 74 Self {
105 mutex: Mutex::new(false), 75 mutex: Mutex::new(false),
106 condvar: Condvar::new(), 76 condvar: Condvar::new(),
@@ -132,40 +102,3 @@ impl Signaler {
132 self.condvar.notify_one(); 102 self.condvar.notify_one();
133 } 103 }
134} 104}
135
136pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>);
137unsafe impl<T> Send for UninitCell<T> {}
138unsafe impl<T> Sync for UninitCell<T> {}
139
140impl<T> UninitCell<T> {
141 pub const fn uninit() -> Self {
142 Self(MaybeUninit::uninit())
143 }
144
145 pub unsafe fn as_ptr(&self) -> *const T {
146 (*self.0.as_ptr()).get()
147 }
148
149 pub unsafe fn as_mut_ptr(&self) -> *mut T {
150 (*self.0.as_ptr()).get()
151 }
152
153 pub unsafe fn as_ref(&self) -> &T {
154 &*self.as_ptr()
155 }
156
157 pub unsafe fn write(&self, val: T) {
158 ptr::write(self.as_mut_ptr(), val)
159 }
160}
161
162impl<T: Copy> UninitCell<T> {
163 pub unsafe fn read(&self) -> T {
164 ptr::read(self.as_mut_ptr())
165 }
166}
167
168embassy_time_queue_driver::timer_queue_impl!(
169 static TIMER_QUEUE_DRIVER: GlobalTimerQueue
170 = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration))
171);