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}