diff options
| author | ivmarkov <[email protected]> | 2022-10-24 09:17:43 +0300 |
|---|---|---|
| committer | ivmarkov <[email protected]> | 2022-10-24 09:17:43 +0300 |
| commit | 4d5550070fe5e80ff2296a71239c568c774b9ceb (patch) | |
| tree | 3248eb5c70b9dd5402c5edc049cafc31a5f66ed3 | |
| parent | 53608a87ac4b6c8c60b5508551d12f5ba76ca2f6 (diff) | |
Change time Driver contract to never fire the alarm synchronously
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 72 | ||||
| -rw-r--r-- | embassy-nrf/src/time_driver.rs | 17 | ||||
| -rw-r--r-- | embassy-rp/src/timer.rs | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/time_driver.rs | 18 | ||||
| -rw-r--r-- | embassy-time/src/driver.rs | 13 | ||||
| -rw-r--r-- | embassy-time/src/driver_std.rs | 4 | ||||
| -rw-r--r-- | embassy-time/src/driver_wasm.rs | 4 | ||||
| -rw-r--r-- | embassy-time/src/queue_generic.rs | 77 |
8 files changed, 109 insertions, 113 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index e1258ebb5..5bcb1e6e7 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -354,46 +354,54 @@ impl Executor { | |||
| 354 | /// somehow schedule for `poll()` to be called later, at a time you know for sure there's | 354 | /// somehow schedule for `poll()` to be called later, at a time you know for sure there's |
| 355 | /// no `poll()` already running. | 355 | /// no `poll()` already running. |
| 356 | pub unsafe fn poll(&'static self) { | 356 | pub unsafe fn poll(&'static self) { |
| 357 | #[cfg(feature = "integrated-timers")] | 357 | loop { |
| 358 | self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); | 358 | #[cfg(feature = "integrated-timers")] |
| 359 | self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); | ||
| 359 | 360 | ||
| 360 | self.run_queue.dequeue_all(|p| { | 361 | self.run_queue.dequeue_all(|p| { |
| 361 | let task = p.as_ref(); | 362 | let task = p.as_ref(); |
| 362 | 363 | ||
| 363 | #[cfg(feature = "integrated-timers")] | 364 | #[cfg(feature = "integrated-timers")] |
| 364 | task.expires_at.set(Instant::MAX); | 365 | task.expires_at.set(Instant::MAX); |
| 365 | 366 | ||
| 366 | let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); | 367 | let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); |
| 367 | if state & STATE_SPAWNED == 0 { | 368 | if state & STATE_SPAWNED == 0 { |
| 368 | // If task is not running, ignore it. This can happen in the following scenario: | 369 | // If task is not running, ignore it. This can happen in the following scenario: |
| 369 | // - Task gets dequeued, poll starts | 370 | // - Task gets dequeued, poll starts |
| 370 | // - While task is being polled, it gets woken. It gets placed in the queue. | 371 | // - While task is being polled, it gets woken. It gets placed in the queue. |
| 371 | // - Task poll finishes, returning done=true | 372 | // - Task poll finishes, returning done=true |
| 372 | // - RUNNING bit is cleared, but the task is already in the queue. | 373 | // - RUNNING bit is cleared, but the task is already in the queue. |
| 373 | return; | 374 | return; |
| 374 | } | 375 | } |
| 375 | 376 | ||
| 376 | #[cfg(feature = "rtos-trace")] | 377 | #[cfg(feature = "rtos-trace")] |
| 377 | trace::task_exec_begin(p.as_ptr() as u32); | 378 | trace::task_exec_begin(p.as_ptr() as u32); |
| 378 | 379 | ||
| 379 | // Run the task | 380 | // Run the task |
| 380 | task.poll_fn.read()(p as _); | 381 | task.poll_fn.read()(p as _); |
| 381 | 382 | ||
| 382 | #[cfg(feature = "rtos-trace")] | 383 | #[cfg(feature = "rtos-trace")] |
| 383 | trace::task_exec_end(); | 384 | trace::task_exec_end(); |
| 385 | |||
| 386 | // Enqueue or update into timer_queue | ||
| 387 | #[cfg(feature = "integrated-timers")] | ||
| 388 | self.timer_queue.update(p); | ||
| 389 | }); | ||
| 384 | 390 | ||
| 385 | // Enqueue or update into timer_queue | ||
| 386 | #[cfg(feature = "integrated-timers")] | 391 | #[cfg(feature = "integrated-timers")] |
| 387 | self.timer_queue.update(p); | 392 | { |
| 388 | }); | 393 | // If this is already in the past, set_alarm might return false |
| 394 | // In that case do another poll loop iteration. | ||
| 395 | let next_expiration = self.timer_queue.next_expiration(); | ||
| 396 | if driver::set_alarm(self.alarm, next_expiration.as_ticks()) { | ||
| 397 | break; | ||
| 398 | } | ||
| 399 | } | ||
| 389 | 400 | ||
| 390 | #[cfg(feature = "integrated-timers")] | 401 | #[cfg(not(feature = "integrated-timers"))] |
| 391 | { | 402 | { |
| 392 | // If this is already in the past, set_alarm will immediately trigger the alarm. | 403 | break; |
| 393 | // This will cause `signal_fn` to be called, which will cause `poll()` to be called again, | 404 | } |
| 394 | // so we immediately do another poll loop iteration. | ||
| 395 | let next_expiration = self.timer_queue.next_expiration(); | ||
| 396 | driver::set_alarm(self.alarm, next_expiration.as_ticks()); | ||
| 397 | } | 405 | } |
| 398 | 406 | ||
| 399 | #[cfg(feature = "rtos-trace")] | 407 | #[cfg(feature = "rtos-trace")] |
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index c32a44637..0d03ad529 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs | |||
| @@ -243,20 +243,19 @@ impl Driver for RtcDriver { | |||
| 243 | }) | 243 | }) |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 246 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 247 | critical_section::with(|cs| { | 247 | critical_section::with(|cs| { |
| 248 | let n = alarm.id() as _; | ||
| 249 | let alarm = self.get_alarm(cs, alarm); | ||
| 250 | alarm.timestamp.set(timestamp); | ||
| 251 | |||
| 252 | let t = self.now(); | 248 | let t = self.now(); |
| 253 | 249 | ||
| 254 | // If alarm timestamp has passed, trigger it instantly. | 250 | // If alarm timestamp has passed don't set the alarm and return `false` to indicate that. |
| 255 | if timestamp <= t { | 251 | if timestamp <= t { |
| 256 | self.trigger_alarm(n, cs); | 252 | return false; |
| 257 | return; | ||
| 258 | } | 253 | } |
| 259 | 254 | ||
| 255 | let n = alarm.id() as _; | ||
| 256 | let alarm = self.get_alarm(cs, alarm); | ||
| 257 | alarm.timestamp.set(timestamp); | ||
| 258 | |||
| 260 | let r = rtc(); | 259 | let r = rtc(); |
| 261 | 260 | ||
| 262 | // If it hasn't triggered yet, setup it in the compare channel. | 261 | // If it hasn't triggered yet, setup it in the compare channel. |
| @@ -287,6 +286,8 @@ impl Driver for RtcDriver { | |||
| 287 | // It will be setup later by `next_period`. | 286 | // It will be setup later by `next_period`. |
| 288 | r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); | 287 | r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); |
| 289 | } | 288 | } |
| 289 | |||
| 290 | true | ||
| 290 | }) | 291 | }) |
| 291 | } | 292 | } |
| 292 | } | 293 | } |
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs index 5215c0c0f..8f280f550 100644 --- a/embassy-rp/src/timer.rs +++ b/embassy-rp/src/timer.rs | |||
| @@ -68,9 +68,16 @@ impl Driver for TimerDriver { | |||
| 68 | }) | 68 | }) |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 71 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 72 | let n = alarm.id() as usize; | 72 | let n = alarm.id() as usize; |
| 73 | critical_section::with(|cs| { | 73 | critical_section::with(|cs| { |
| 74 | let now = self.now(); | ||
| 75 | |||
| 76 | // If alarm timestamp has passed don't set the alarm and return `false` to indicate that. | ||
| 77 | if timestamp <= now { | ||
| 78 | return false; | ||
| 79 | } | ||
| 80 | |||
| 74 | let alarm = &self.alarms.borrow(cs)[n]; | 81 | let alarm = &self.alarms.borrow(cs)[n]; |
| 75 | alarm.timestamp.set(timestamp); | 82 | alarm.timestamp.set(timestamp); |
| 76 | 83 | ||
| @@ -80,13 +87,7 @@ impl Driver for TimerDriver { | |||
| 80 | // it is checked if the alarm time has passed. | 87 | // it is checked if the alarm time has passed. |
| 81 | unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; | 88 | unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; |
| 82 | 89 | ||
| 83 | let now = self.now(); | 90 | true |
| 84 | |||
| 85 | // If alarm timestamp has passed, trigger it instantly. | ||
| 86 | // This disarms it. | ||
| 87 | if timestamp <= now { | ||
| 88 | self.trigger_alarm(n, cs); | ||
| 89 | } | ||
| 90 | }) | 91 | }) |
| 91 | } | 92 | } |
| 92 | } | 93 | } |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index ed3225c51..e4c266e7f 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -292,21 +292,21 @@ impl Driver for RtcDriver { | |||
| 292 | }) | 292 | }) |
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 295 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 296 | critical_section::with(|cs| { | 296 | critical_section::with(|cs| { |
| 297 | let t = self.now(); | ||
| 298 | |||
| 299 | // If alarm timestamp has passed don't set the alarm and return `false` to indicate that. | ||
| 300 | if timestamp <= t { | ||
| 301 | return false; | ||
| 302 | } | ||
| 303 | |||
| 297 | let r = T::regs_gp16(); | 304 | let r = T::regs_gp16(); |
| 298 | 305 | ||
| 299 | let n = alarm.id() as _; | 306 | let n = alarm.id() as _; |
| 300 | let alarm = self.get_alarm(cs, alarm); | 307 | let alarm = self.get_alarm(cs, alarm); |
| 301 | alarm.timestamp.set(timestamp); | 308 | alarm.timestamp.set(timestamp); |
| 302 | 309 | ||
| 303 | let t = self.now(); | ||
| 304 | if timestamp <= t { | ||
| 305 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) }; | ||
| 306 | self.trigger_alarm(n, cs); | ||
| 307 | return; | ||
| 308 | } | ||
| 309 | |||
| 310 | let safe_timestamp = timestamp.max(t + 3); | 310 | let safe_timestamp = timestamp.max(t + 3); |
| 311 | 311 | ||
| 312 | // Write the CCR value regardless of whether we're going to enable it now or not. | 312 | // Write the CCR value regardless of whether we're going to enable it now or not. |
| @@ -317,6 +317,8 @@ impl Driver for RtcDriver { | |||
| 317 | let diff = timestamp - t; | 317 | let diff = timestamp - t; |
| 318 | // NOTE(unsafe) We're in a critical section | 318 | // NOTE(unsafe) We're in a critical section |
| 319 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) }; | 319 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) }; |
| 320 | |||
| 321 | true | ||
| 320 | }) | 322 | }) |
| 321 | } | 323 | } |
| 322 | } | 324 | } |
diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs index 79ae14b91..5c2ad3b23 100644 --- a/embassy-time/src/driver.rs +++ b/embassy-time/src/driver.rs | |||
| @@ -105,20 +105,21 @@ pub trait Driver: Send + Sync + 'static { | |||
| 105 | /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm | 105 | /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm |
| 106 | /// timestamp, the provided callback function will be called. | 106 | /// timestamp, the provided callback function will be called. |
| 107 | /// | 107 | /// |
| 108 | /// If `timestamp` is already in the past, the alarm callback must be immediately fired. | 108 | /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. |
| 109 | /// In this case, it is allowed (but not mandatory) to call the alarm callback synchronously from `set_alarm`. | 109 | /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set, |
| 110 | /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously. | ||
| 110 | /// | 111 | /// |
| 111 | /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. | 112 | /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. |
| 112 | /// | 113 | /// |
| 113 | /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any. | 114 | /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any. |
| 114 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64); | 115 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool; |
| 115 | } | 116 | } |
| 116 | 117 | ||
| 117 | extern "Rust" { | 118 | extern "Rust" { |
| 118 | fn _embassy_time_now() -> u64; | 119 | fn _embassy_time_now() -> u64; |
| 119 | fn _embassy_time_allocate_alarm() -> Option<AlarmHandle>; | 120 | fn _embassy_time_allocate_alarm() -> Option<AlarmHandle>; |
| 120 | fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); | 121 | fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); |
| 121 | fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64); | 122 | fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool; |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | /// See [`Driver::now`] | 125 | /// See [`Driver::now`] |
| @@ -139,7 +140,7 @@ pub fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ( | |||
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | /// See [`Driver::set_alarm`] | 142 | /// See [`Driver::set_alarm`] |
| 142 | pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) { | 143 | pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool { |
| 143 | unsafe { _embassy_time_set_alarm(alarm, timestamp) } | 144 | unsafe { _embassy_time_set_alarm(alarm, timestamp) } |
| 144 | } | 145 | } |
| 145 | 146 | ||
| @@ -167,7 +168,7 @@ macro_rules! time_driver_impl { | |||
| 167 | } | 168 | } |
| 168 | 169 | ||
| 169 | #[no_mangle] | 170 | #[no_mangle] |
| 170 | fn _embassy_time_set_alarm(alarm: $crate::driver::AlarmHandle, timestamp: u64) { | 171 | fn _embassy_time_set_alarm(alarm: $crate::driver::AlarmHandle, timestamp: u64) -> bool { |
| 171 | <$t as $crate::driver::Driver>::set_alarm(&$name, alarm, timestamp) | 172 | <$t as $crate::driver::Driver>::set_alarm(&$name, alarm, timestamp) |
| 172 | } | 173 | } |
| 173 | }; | 174 | }; |
diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index 2ddb2e604..fc7fd1979 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs | |||
| @@ -127,12 +127,14 @@ impl Driver for TimeDriver { | |||
| 127 | alarm.ctx = ctx; | 127 | alarm.ctx = ctx; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 130 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 131 | self.init(); | 131 | self.init(); |
| 132 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); | 132 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); |
| 133 | let alarm = &mut alarms[alarm.id() as usize]; | 133 | let alarm = &mut alarms[alarm.id() as usize]; |
| 134 | alarm.timestamp = timestamp; | 134 | alarm.timestamp = timestamp; |
| 135 | unsafe { self.signaler.as_ref() }.signal(); | 135 | unsafe { self.signaler.as_ref() }.signal(); |
| 136 | |||
| 137 | true | ||
| 136 | } | 138 | } |
| 137 | } | 139 | } |
| 138 | 140 | ||
diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs index e4497e6a2..d7a6b0d8d 100644 --- a/embassy-time/src/driver_wasm.rs +++ b/embassy-time/src/driver_wasm.rs | |||
| @@ -81,13 +81,15 @@ impl Driver for TimeDriver { | |||
| 81 | } | 81 | } |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { | 84 | fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) -> bool { |
| 85 | self.init(); | 85 | self.init(); |
| 86 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); | 86 | let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); |
| 87 | let alarm = &mut alarms[alarm.id() as usize]; | 87 | let alarm = &mut alarms[alarm.id() as usize]; |
| 88 | alarm.closure.replace(Closure::new(move || { | 88 | alarm.closure.replace(Closure::new(move || { |
| 89 | callback(ctx); | 89 | callback(ctx); |
| 90 | })); | 90 | })); |
| 91 | |||
| 92 | true | ||
| 91 | } | 93 | } |
| 92 | 94 | ||
| 93 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 95 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { |
diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs index 1c4e5398b..83f734848 100644 --- a/embassy-time/src/queue_generic.rs +++ b/embassy-time/src/queue_generic.rs | |||
| @@ -2,7 +2,6 @@ use core::cell::RefCell; | |||
| 2 | use core::cmp::Ordering; | 2 | use core::cmp::Ordering; |
| 3 | use core::task::Waker; | 3 | use core::task::Waker; |
| 4 | 4 | ||
| 5 | use atomic_polyfill::{AtomicU64, Ordering as AtomicOrdering}; | ||
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 5 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 7 | use embassy_sync::blocking_mutex::Mutex; | 6 | use embassy_sync::blocking_mutex::Mutex; |
| 8 | use heapless::sorted_linked_list::{LinkedIndexU8, Min, SortedLinkedList}; | 7 | use heapless::sorted_linked_list::{LinkedIndexU8, Min, SortedLinkedList}; |
| @@ -71,7 +70,7 @@ impl InnerQueue { | |||
| 71 | } | 70 | } |
| 72 | } | 71 | } |
| 73 | 72 | ||
| 74 | fn schedule_wake(&mut self, at: Instant, waker: &Waker, alarm_schedule: &AtomicU64) { | 73 | fn schedule_wake(&mut self, at: Instant, waker: &Waker) { |
| 75 | self.queue | 74 | self.queue |
| 76 | .find_mut(|timer| timer.waker.will_wake(waker)) | 75 | .find_mut(|timer| timer.waker.will_wake(waker)) |
| 77 | .map(|mut timer| { | 76 | .map(|mut timer| { |
| @@ -98,50 +97,54 @@ impl InnerQueue { | |||
| 98 | // dispatch all timers that are already due | 97 | // dispatch all timers that are already due |
| 99 | // | 98 | // |
| 100 | // Then update the alarm if necessary | 99 | // Then update the alarm if necessary |
| 101 | self.dispatch(alarm_schedule); | 100 | self.dispatch(); |
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | fn dispatch(&mut self, alarm_schedule: &AtomicU64) { | 103 | fn dispatch(&mut self) { |
| 105 | let now = Instant::now(); | 104 | loop { |
| 105 | let now = Instant::now(); | ||
| 106 | 106 | ||
| 107 | while self.queue.peek().filter(|timer| timer.at <= now).is_some() { | 107 | while self.queue.peek().filter(|timer| timer.at <= now).is_some() { |
| 108 | self.queue.pop().unwrap().waker.wake(); | 108 | self.queue.pop().unwrap().waker.wake(); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | self.update_alarm(alarm_schedule); | 111 | if self.update_alarm() { |
| 112 | break; | ||
| 113 | } | ||
| 114 | } | ||
| 112 | } | 115 | } |
| 113 | 116 | ||
| 114 | fn update_alarm(&mut self, alarm_schedule: &AtomicU64) { | 117 | fn update_alarm(&mut self) -> bool { |
| 115 | if let Some(timer) = self.queue.peek() { | 118 | if let Some(timer) = self.queue.peek() { |
| 116 | let new_at = timer.at; | 119 | let new_at = timer.at; |
| 117 | 120 | ||
| 118 | if self.alarm_at != new_at { | 121 | if self.alarm_at != new_at { |
| 119 | self.alarm_at = new_at; | 122 | self.alarm_at = new_at; |
| 120 | alarm_schedule.store(new_at.as_ticks(), AtomicOrdering::SeqCst); | 123 | |
| 124 | return set_alarm(self.alarm.unwrap(), self.alarm_at.as_ticks()); | ||
| 121 | } | 125 | } |
| 122 | } else { | 126 | } else { |
| 123 | self.alarm_at = Instant::MAX; | 127 | self.alarm_at = Instant::MAX; |
| 124 | alarm_schedule.store(Instant::MAX.as_ticks(), AtomicOrdering::SeqCst); | ||
| 125 | } | 128 | } |
| 129 | |||
| 130 | true | ||
| 126 | } | 131 | } |
| 127 | 132 | ||
| 128 | fn handle_alarm(&mut self, alarm_schedule: &AtomicU64) { | 133 | fn handle_alarm(&mut self) { |
| 129 | self.alarm_at = Instant::MAX; | 134 | self.alarm_at = Instant::MAX; |
| 130 | 135 | ||
| 131 | self.dispatch(alarm_schedule); | 136 | self.dispatch(); |
| 132 | } | 137 | } |
| 133 | } | 138 | } |
| 134 | 139 | ||
| 135 | struct Queue { | 140 | struct Queue { |
| 136 | inner: Mutex<CriticalSectionRawMutex, RefCell<InnerQueue>>, | 141 | inner: Mutex<CriticalSectionRawMutex, RefCell<InnerQueue>>, |
| 137 | alarm_schedule: AtomicU64, | ||
| 138 | } | 142 | } |
| 139 | 143 | ||
| 140 | impl Queue { | 144 | impl Queue { |
| 141 | const fn new() -> Self { | 145 | const fn new() -> Self { |
| 142 | Self { | 146 | Self { |
| 143 | inner: Mutex::new(RefCell::new(InnerQueue::new())), | 147 | inner: Mutex::new(RefCell::new(InnerQueue::new())), |
| 144 | alarm_schedule: AtomicU64::new(u64::MAX), | ||
| 145 | } | 148 | } |
| 146 | } | 149 | } |
| 147 | 150 | ||
| @@ -156,28 +159,12 @@ impl Queue { | |||
| 156 | set_alarm_callback(handle, Self::handle_alarm_callback, self as *const _ as _); | 159 | set_alarm_callback(handle, Self::handle_alarm_callback, self as *const _ as _); |
| 157 | } | 160 | } |
| 158 | 161 | ||
| 159 | inner.schedule_wake(at, waker, &self.alarm_schedule) | 162 | inner.schedule_wake(at, waker) |
| 160 | }); | 163 | }); |
| 161 | |||
| 162 | self.update_alarm(); | ||
| 163 | } | ||
| 164 | |||
| 165 | fn update_alarm(&self) { | ||
| 166 | // Need to set the alarm when we are *not* holding the mutex on the inner queue | ||
| 167 | // because mutexes are not re-entrant, which is a problem because `set_alarm` might immediately | ||
| 168 | // call us back if the timestamp is in the past. | ||
| 169 | let alarm_at = self.alarm_schedule.swap(u64::MAX, AtomicOrdering::SeqCst); | ||
| 170 | |||
| 171 | if alarm_at < u64::MAX { | ||
| 172 | set_alarm(self.inner.lock(|inner| inner.borrow().alarm.unwrap()), alarm_at); | ||
| 173 | } | ||
| 174 | } | 164 | } |
| 175 | 165 | ||
| 176 | fn handle_alarm(&self) { | 166 | fn handle_alarm(&self) { |
| 177 | self.inner | 167 | self.inner.lock(|inner| inner.borrow_mut().handle_alarm()); |
| 178 | .lock(|inner| inner.borrow_mut().handle_alarm(&self.alarm_schedule)); | ||
| 179 | |||
| 180 | self.update_alarm(); | ||
| 181 | } | 168 | } |
| 182 | 169 | ||
| 183 | fn handle_alarm_callback(ctx: *mut ()) { | 170 | fn handle_alarm_callback(ctx: *mut ()) { |
| @@ -196,7 +183,6 @@ crate::timer_queue_impl!(static QUEUE: Queue = Queue::new()); | |||
| 196 | #[cfg(test)] | 183 | #[cfg(test)] |
| 197 | mod tests { | 184 | mod tests { |
| 198 | use core::cell::Cell; | 185 | use core::cell::Cell; |
| 199 | use core::sync::atomic::Ordering; | ||
| 200 | use core::task::{RawWaker, RawWakerVTable, Waker}; | 186 | use core::task::{RawWaker, RawWakerVTable, Waker}; |
| 201 | use std::rc::Rc; | 187 | use std::rc::Rc; |
| 202 | use std::sync::Mutex; | 188 | use std::sync::Mutex; |
| @@ -282,20 +268,14 @@ mod tests { | |||
| 282 | inner.ctx = ctx; | 268 | inner.ctx = ctx; |
| 283 | } | 269 | } |
| 284 | 270 | ||
| 285 | fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) { | 271 | fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool { |
| 286 | let notify = { | 272 | let mut inner = self.0.lock().unwrap(); |
| 287 | let mut inner = self.0.lock().unwrap(); | ||
| 288 | |||
| 289 | if timestamp <= inner.now { | ||
| 290 | Some((inner.callback, inner.ctx)) | ||
| 291 | } else { | ||
| 292 | inner.alarm = timestamp; | ||
| 293 | None | ||
| 294 | } | ||
| 295 | }; | ||
| 296 | 273 | ||
| 297 | if let Some((callback, ctx)) = notify { | 274 | if timestamp <= inner.now { |
| 298 | (callback)(ctx); | 275 | false |
| 276 | } else { | ||
| 277 | inner.alarm = timestamp; | ||
| 278 | true | ||
| 299 | } | 279 | } |
| 300 | } | 280 | } |
| 301 | } | 281 | } |
| @@ -344,7 +324,6 @@ mod tests { | |||
| 344 | fn setup() { | 324 | fn setup() { |
| 345 | DRIVER.reset(); | 325 | DRIVER.reset(); |
| 346 | 326 | ||
| 347 | QUEUE.alarm_schedule.store(u64::MAX, Ordering::SeqCst); | ||
| 348 | QUEUE.inner.lock(|inner| { | 327 | QUEUE.inner.lock(|inner| { |
| 349 | *inner.borrow_mut() = InnerQueue::new(); | 328 | *inner.borrow_mut() = InnerQueue::new(); |
| 350 | }); | 329 | }); |
