1 | use core::mem; |
2 | use core::task::Waker; |
3 | |
4 | /// Utility struct to register and wake a waker. |
5 | #[derive (Debug, Default)] |
6 | pub struct WakerRegistration { |
7 | waker: Option<Waker>, |
8 | } |
9 | |
10 | impl WakerRegistration { |
11 | /// Create a new `WakerRegistration`. |
12 | pub const fn new() -> Self { |
13 | Self { waker: None } |
14 | } |
15 | |
16 | /// Register a waker. Overwrites the previous waker, if any. |
17 | pub fn register(&mut self, w: &Waker) { |
18 | match self.waker { |
19 | // Optimization: If both the old and new Wakers wake the same task, we can simply |
20 | // keep the old waker, skipping the clone. (In most executor implementations, |
21 | // cloning a waker is somewhat expensive, comparable to cloning an Arc). |
22 | Some(ref w2) if (w2.will_wake(w)) => {} |
23 | _ => { |
24 | // clone the new waker and store it |
25 | if let Some(old_waker) = mem::replace(&mut self.waker, Some(w.clone())) { |
26 | // We had a waker registered for another task. Wake it, so the other task can |
27 | // reregister itself if it's still interested. |
28 | // |
29 | // If two tasks are waiting on the same thing concurrently, this will cause them |
30 | // to wake each other in a loop fighting over this WakerRegistration. This wastes |
31 | // CPU but things will still work. |
32 | // |
33 | // If the user wants to have two tasks waiting on the same thing they should use |
34 | // a more appropriate primitive that can store multiple wakers. |
35 | old_waker.wake() |
36 | } |
37 | } |
38 | } |
39 | } |
40 | |
41 | /// Wake the registered waker, if any. |
42 | pub fn wake(&mut self) { |
43 | if let Some(w) = self.waker.take() { |
44 | w.wake() |
45 | } |
46 | } |
47 | |
48 | /// Returns true if a waker is currently registered |
49 | pub fn occupied(&self) -> bool { |
50 | self.waker.is_some() |
51 | } |
52 | } |
53 | |