aboutsummaryrefslogtreecommitdiff
path: root/embassy-time/src/driver_std.rs
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2024-11-26 23:54:21 +0100
committerDániel Buga <[email protected]>2024-12-10 21:31:42 +0100
commit5a5495aac43d75610735f2ca80fb6c8e8f31ed71 (patch)
tree7a4336917894730692589359e9d1a285ec5a0a05 /embassy-time/src/driver_std.rs
parent406d377b7564d16e12b7fae4f42c0c709bf4f243 (diff)
Refactor integrated-timers
Diffstat (limited to 'embassy-time/src/driver_std.rs')
-rw-r--r--embassy-time/src/driver_std.rs121
1 files changed, 31 insertions, 90 deletions
diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs
index cbef7aae1..45467f09b 100644
--- a/embassy-time/src/driver_std.rs
+++ b/embassy-time/src/driver_std.rs
@@ -1,53 +1,38 @@
1use core::sync::atomic::{AtomicU8, Ordering};
2use std::cell::{RefCell, UnsafeCell}; 1use std::cell::{RefCell, UnsafeCell};
3use std::mem::MaybeUninit; 2use std::mem::MaybeUninit;
4use std::sync::{Condvar, Mutex, Once}; 3use std::sync::{Condvar, Mutex, Once};
5use std::time::{Duration as StdDuration, Instant as StdInstant}; 4use std::time::{Duration as StdDuration, Instant as StdInstant};
6use std::{mem, ptr, thread}; 5use std::{ptr, thread};
7 6
8use critical_section::Mutex as CsMutex; 7use critical_section::Mutex as CsMutex;
9use embassy_time_driver::{AlarmHandle, Driver}; 8use embassy_time_driver::Driver;
10 9use embassy_time_queue_driver::GlobalTimerQueue;
11const ALARM_COUNT: usize = 4;
12 10
13struct AlarmState { 11struct AlarmState {
14 timestamp: u64, 12 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} 13}
21 14
22unsafe impl Send for AlarmState {} 15unsafe impl Send for AlarmState {}
23 16
24impl AlarmState { 17impl AlarmState {
25 const fn new() -> Self { 18 const fn new() -> Self {
26 Self { 19 Self { timestamp: u64::MAX }
27 timestamp: u64::MAX,
28 callback: ptr::null(),
29 ctx: ptr::null_mut(),
30 }
31 } 20 }
32} 21}
33 22
34struct TimeDriver { 23struct TimeDriver {
35 alarm_count: AtomicU8,
36
37 once: Once, 24 once: Once,
38 // The STD Driver implementation requires the alarms' mutex to be reentrant, which the STD Mutex isn't 25 // The STD Driver implementation requires the alarm's mutex to be reentrant, which the STD Mutex isn't
39 // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections 26 // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections
40 // themselves are reentrant 27 // themselves are reentrant
41 alarms: UninitCell<CsMutex<RefCell<[AlarmState; ALARM_COUNT]>>>, 28 alarm: UninitCell<CsMutex<RefCell<AlarmState>>>,
42 zero_instant: UninitCell<StdInstant>, 29 zero_instant: UninitCell<StdInstant>,
43 signaler: UninitCell<Signaler>, 30 signaler: UninitCell<Signaler>,
44} 31}
45 32
46embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { 33embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
47 alarm_count: AtomicU8::new(0),
48
49 once: Once::new(), 34 once: Once::new(),
50 alarms: UninitCell::uninit(), 35 alarm: UninitCell::uninit(),
51 zero_instant: UninitCell::uninit(), 36 zero_instant: UninitCell::uninit(),
52 signaler: UninitCell::uninit(), 37 signaler: UninitCell::uninit(),
53}); 38});
@@ -55,8 +40,8 @@ embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
55impl TimeDriver { 40impl TimeDriver {
56 fn init(&self) { 41 fn init(&self) {
57 self.once.call_once(|| unsafe { 42 self.once.call_once(|| unsafe {
58 self.alarms 43 self.alarm
59 .write(CsMutex::new(RefCell::new([const { AlarmState::new() }; ALARM_COUNT]))); 44 .write(CsMutex::new(RefCell::new(const { AlarmState::new() })));
60 self.zero_instant.write(StdInstant::now()); 45 self.zero_instant.write(StdInstant::now());
61 self.signaler.write(Signaler::new()); 46 self.signaler.write(Signaler::new());
62 47
@@ -70,36 +55,13 @@ impl TimeDriver {
70 let now = DRIVER.now(); 55 let now = DRIVER.now();
71 56
72 let next_alarm = critical_section::with(|cs| { 57 let next_alarm = critical_section::with(|cs| {
73 let alarms = unsafe { DRIVER.alarms.as_ref() }.borrow(cs); 58 let mut alarm = unsafe { DRIVER.alarm.as_ref() }.borrow_ref_mut(cs);
74 loop { 59 if alarm.timestamp <= now {
75 let pending = alarms 60 alarm.timestamp = u64::MAX;
76 .borrow_mut()
77 .iter_mut()
78 .find(|alarm| alarm.timestamp <= now)
79 .map(|alarm| {
80 alarm.timestamp = u64::MAX;
81
82 (alarm.callback, alarm.ctx)
83 });
84
85 if let Some((callback, ctx)) = pending {
86 // safety:
87 // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
88 // - other than that we only store valid function pointers into alarm.callback
89 let f: fn(*mut ()) = unsafe { mem::transmute(callback) };
90 f(ctx);
91 } else {
92 // No alarm due
93 break;
94 }
95 }
96 61
97 alarms 62 TIMER_QUEUE_DRIVER.dispatch();
98 .borrow() 63 }
99 .iter() 64 alarm.timestamp
100 .map(|alarm| alarm.timestamp)
101 .min()
102 .unwrap_or(u64::MAX)
103 }); 65 });
104 66
105 // Ensure we don't overflow 67 // Ensure we don't overflow
@@ -110,46 +72,11 @@ impl TimeDriver {
110 unsafe { DRIVER.signaler.as_ref() }.wait_until(until); 72 unsafe { DRIVER.signaler.as_ref() }.wait_until(until);
111 } 73 }
112 } 74 }
113}
114
115impl Driver for TimeDriver {
116 fn now(&self) -> u64 {
117 self.init();
118
119 let zero = unsafe { self.zero_instant.read() };
120 StdInstant::now().duration_since(zero).as_micros() as u64
121 }
122
123 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
124 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
125 if x < ALARM_COUNT as u8 {
126 Some(x + 1)
127 } else {
128 None
129 }
130 });
131
132 match id {
133 Ok(id) => Some(AlarmHandle::new(id)),
134 Err(_) => None,
135 }
136 }
137
138 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
139 self.init();
140 critical_section::with(|cs| {
141 let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs);
142 let alarm = &mut alarms[alarm.id() as usize];
143 alarm.callback = callback as *const ();
144 alarm.ctx = ctx;
145 });
146 }
147 75
148 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 76 fn set_alarm(&self, timestamp: u64) -> bool {
149 self.init(); 77 self.init();
150 critical_section::with(|cs| { 78 critical_section::with(|cs| {
151 let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs); 79 let mut alarm = unsafe { self.alarm.as_ref() }.borrow_ref_mut(cs);
152 let alarm = &mut alarms[alarm.id() as usize];
153 alarm.timestamp = timestamp; 80 alarm.timestamp = timestamp;
154 unsafe { self.signaler.as_ref() }.signal(); 81 unsafe { self.signaler.as_ref() }.signal();
155 }); 82 });
@@ -158,6 +85,15 @@ impl Driver for TimeDriver {
158 } 85 }
159} 86}
160 87
88impl Driver for TimeDriver {
89 fn now(&self) -> u64 {
90 self.init();
91
92 let zero = unsafe { self.zero_instant.read() };
93 StdInstant::now().duration_since(zero).as_micros() as u64
94 }
95}
96
161struct Signaler { 97struct Signaler {
162 mutex: Mutex<bool>, 98 mutex: Mutex<bool>,
163 condvar: Condvar, 99 condvar: Condvar,
@@ -228,3 +164,8 @@ impl<T: Copy> UninitCell<T> {
228 ptr::read(self.as_mut_ptr()) 164 ptr::read(self.as_mut_ptr())
229 } 165 }
230} 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);