scrappy_utils/task.rs
1use std::cell::UnsafeCell;
2use std::marker::PhantomData;
3use std::task::Waker;
4use std::{fmt, rc};
5
6/// A synchronization primitive for task wakeup.
7///
8/// Sometimes the task interested in a given event will change over time.
9/// An `LocalWaker` can coordinate concurrent notifications with the consumer
10/// potentially "updating" the underlying task to wake up. This is useful in
11/// scenarios where a computation completes in another task and wants to
12/// notify the consumer, but the consumer is in the process of being migrated to
13/// a new logical task.
14///
15/// Consumers should call `register` before checking the result of a computation
16/// and producers should call `wake` after producing the computation (this
17/// differs from the usual `thread::park` pattern). It is also permitted for
18/// `wake` to be called **before** `register`. This results in a no-op.
19///
20/// A single `AtomicWaker` may be reused for any number of calls to `register` or
21/// `wake`.
22#[derive(Default)]
23pub struct LocalWaker {
24 pub(crate) waker: UnsafeCell<Option<Waker>>,
25 _t: PhantomData<rc::Rc<()>>,
26}
27
28impl LocalWaker {
29 /// Create an `LocalWaker`.
30 pub fn new() -> Self {
31 LocalWaker {
32 waker: UnsafeCell::new(None),
33 _t: PhantomData,
34 }
35 }
36
37 #[inline]
38 /// Check if waker has been registered.
39 pub fn is_registed(&self) -> bool {
40 unsafe { (*self.waker.get()).is_some() }
41 }
42
43 #[inline]
44 /// Registers the waker to be notified on calls to `wake`.
45 ///
46 /// Returns `true` if waker was registered before.
47 pub fn register(&self, waker: &Waker) -> bool {
48 unsafe {
49 let w = self.waker.get();
50 let is_registered = (*w).is_some();
51 *w = Some(waker.clone());
52 is_registered
53 }
54 }
55
56 #[inline]
57 /// Calls `wake` on the last `Waker` passed to `register`.
58 ///
59 /// If `register` has not been called yet, then this does nothing.
60 pub fn wake(&self) {
61 if let Some(waker) = self.take() {
62 waker.wake();
63 }
64 }
65
66 /// Returns the last `Waker` passed to `register`, so that the user can wake it.
67 ///
68 /// If a waker has not been registered, this returns `None`.
69 pub fn take(&self) -> Option<Waker> {
70 unsafe { (*self.waker.get()).take() }
71 }
72}
73
74impl fmt::Debug for LocalWaker {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 write!(f, "LocalWaker")
77 }
78}