mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-01 16:04:33 +01:00
waker registration somehow lost, back again
This commit is contained in:
parent
f62d0d17b2
commit
3f60522d63
1 changed files with 64 additions and 0 deletions
64
rtic-channel/src/waker_registration.rs
Normal file
64
rtic-channel/src/waker_registration.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
|
use core::task::Waker;
|
||||||
|
|
||||||
|
/// A critical section based waker handler.
|
||||||
|
pub struct CriticalSectionWakerRegistration {
|
||||||
|
waker: UnsafeCell<Option<Waker>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for CriticalSectionWakerRegistration {}
|
||||||
|
unsafe impl Sync for CriticalSectionWakerRegistration {}
|
||||||
|
|
||||||
|
impl CriticalSectionWakerRegistration {
|
||||||
|
/// Create a new waker registration.
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
waker: UnsafeCell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker.
|
||||||
|
/// This will overwrite the previous waker if there was one.
|
||||||
|
pub fn register(&self, new_waker: &Waker) {
|
||||||
|
critical_section::with(|_| {
|
||||||
|
// SAFETY: This access is protected by the critical section.
|
||||||
|
let self_waker = unsafe { &mut *self.waker.get() };
|
||||||
|
|
||||||
|
// From embassy
|
||||||
|
// https://github.com/embassy-rs/embassy/blob/b99533607ceed225dd12ae73aaa9a0d969a7365e/embassy-sync/src/waitqueue/waker.rs#L59-L61
|
||||||
|
match self_waker {
|
||||||
|
// Optimization: If both the old and new Wakers wake the same task, we can simply
|
||||||
|
// keep the old waker, skipping the clone. (In most executor implementations,
|
||||||
|
// cloning a waker is somewhat expensive, comparable to cloning an Arc).
|
||||||
|
Some(ref w2) if (w2.will_wake(new_waker)) => {}
|
||||||
|
_ => {
|
||||||
|
// clone the new waker and store it
|
||||||
|
if let Some(old_waker) = core::mem::replace(self_waker, Some(new_waker.clone()))
|
||||||
|
{
|
||||||
|
// We had a waker registered for another task. Wake it, so the other task can
|
||||||
|
// reregister itself if it's still interested.
|
||||||
|
//
|
||||||
|
// If two tasks are waiting on the same thing concurrently, this will cause them
|
||||||
|
// to wake each other in a loop fighting over this WakerRegistration. This wastes
|
||||||
|
// CPU but things will still work.
|
||||||
|
//
|
||||||
|
// If the user wants to have two tasks waiting on the same thing they should use
|
||||||
|
// a more appropriate primitive that can store multiple wakers.
|
||||||
|
old_waker.wake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wake the waker.
|
||||||
|
pub fn wake(&self) {
|
||||||
|
critical_section::with(|_| {
|
||||||
|
// SAFETY: This access is protected by the critical section.
|
||||||
|
let self_waker = unsafe { &mut *self.waker.get() };
|
||||||
|
if let Some(waker) = self_waker.take() {
|
||||||
|
waker.wake()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue