WakerRegistration: Wake previous task if any

This commit is contained in:
Dario Nieuwenhuis 2021-01-11 10:38:25 +01:00
parent 60df9e0d38
commit 877fc0321a

View File

@ -1,3 +1,4 @@
use core::mem;
use core::task::Context; use core::task::Context;
use core::task::Waker; use core::task::Waker;
@ -19,11 +20,21 @@ impl WakerRegistration {
// keep the old waker, skipping the clone. (In most executor implementations, // keep the old waker, skipping the clone. (In most executor implementations,
// cloning a waker is somewhat expensive, comparable to cloning an Arc). // cloning a waker is somewhat expensive, comparable to cloning an Arc).
Some(ref w2) if (w2.will_wake(w)) => {} Some(ref w2) if (w2.will_wake(w)) => {}
// In all other cases _ => {
// - we have no waker registered // clone the new waker and store it
// - we have a waker registered but it's for a different task. if let Some(old_waker) = mem::replace(&mut self.waker, Some(w.clone())) {
// then clone the new waker and store it // We had a waker registered for another task. Wake it, so the other task can
_ => self.waker = Some(w.clone()), // 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()
}
}
} }
} }
@ -35,4 +46,4 @@ impl WakerRegistration {
pub fn context(&self) -> Option<Context<'_>> { pub fn context(&self) -> Option<Context<'_>> {
self.waker.as_ref().map(|w| Context::from_waker(w)) self.waker.as_ref().map(|w| Context::from_waker(w))
} }
} }