timer/
timer.rs

1// Timer example taken from https://rust-lang.github.io/async-book/02_execution/03_wakeups.html.
2
3use microasync::sync;
4
5use std::{
6    future::Future,
7    pin::Pin,
8    sync::{Arc, Mutex},
9    task::{Context, Poll, Waker},
10    thread,
11    time::Duration,
12};
13
14pub struct TimerFuture {
15    shared_state: Arc<Mutex<SharedState>>,
16}
17
18/// Shared state between the future and the waiting thread
19struct SharedState {
20    /// Whether or not the sleep time has elapsed
21    completed: bool,
22
23    /// The waker for the task that `TimerFuture` is running on.
24    /// The thread can use this after setting `completed = true` to tell
25    /// `TimerFuture`'s task to wake up, see that `completed = true`, and
26    /// move forward.
27    waker: Option<Waker>,
28}
29
30impl Future for TimerFuture {
31    type Output = ();
32    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
33        // Look at the shared state to see if the timer has already completed.
34        let mut shared_state = self.shared_state.lock().unwrap();
35        if shared_state.completed {
36            Poll::Ready(())
37        } else {
38            // Set waker so that the thread can wake up the current task
39            // when the timer has completed, ensuring that the future is polled
40            // again and sees that `completed = true`.
41            //
42            // It's tempting to do this once rather than repeatedly cloning
43            // the waker each time. However, the `TimerFuture` can move between
44            // tasks on the executor, which could cause a stale waker pointing
45            // to the wrong task, preventing `TimerFuture` from waking up
46            // correctly.
47            //
48            // N.B. it's possible to check for this using the `Waker::will_wake`
49            // function, but we omit that here to keep things simple.
50            shared_state.waker = Some(cx.waker().clone());
51            Poll::Pending
52        }
53    }
54}
55
56impl TimerFuture {
57    /// Create a new `TimerFuture` which will complete after the provided
58    /// timeout.
59    pub fn new(duration: Duration) -> Self {
60        let shared_state = Arc::new(Mutex::new(SharedState {
61            completed: false,
62            waker: None,
63        }));
64
65        // Spawn the new thread
66        let thread_shared_state = shared_state.clone();
67        thread::spawn(move || {
68            thread::sleep(duration);
69            let mut shared_state = thread_shared_state.lock().unwrap();
70            // Signal that the timer has completed and wake up the last
71            // task on which the future was polled, if one exists.
72            shared_state.completed = true;
73            if let Some(waker) = shared_state.waker.take() {
74                waker.wake()
75            }
76        });
77
78        TimerFuture { shared_state }
79    }
80}
81
82fn main() {
83    println!("{}", sync(do_sth_async(1000)));
84}
85
86async fn subtract_async(a: i32, b: i32) -> i32 {
87    a - b
88}
89
90async fn add_async(a: i32, b: i32) -> i32 {
91    subtract_async(a, -b).await
92}
93
94async fn do_sth_async(i: i32) -> i32 {
95    TimerFuture::new(Duration::from_millis(2000)).await;
96    add_async(i, i * 4).await
97}