Add executortest
This commit is contained in:
85
executortest/src/main.rs
Normal file
85
executortest/src/main.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
sync::{Arc, Mutex},
|
||||
task::{Context, Poll, Waker},
|
||||
thread,
|
||||
time::Duration,
|
||||
sync::mpsc::{sync_channel, Receiver, SyncSender},
|
||||
};
|
||||
use futures::{
|
||||
future::{BoxFuture, FutureExt},
|
||||
task::{waker_ref, ArcWake},
|
||||
};
|
||||
|
||||
pub struct TimerFuture {
|
||||
shared_state: Arc<Mutex<SharedState>>,
|
||||
}
|
||||
|
||||
/// Shared state between the future and the waiting thread
|
||||
struct SharedState {
|
||||
/// If the sleep time has elapsed
|
||||
completed: bool,
|
||||
|
||||
/// The waker for the task that `TimerFuture` is running on.
|
||||
/// The thread can use this after setting `completed = true` to tell
|
||||
/// `TimerFuture`'s task to wake up, see that `completed = true`, and
|
||||
/// move forward.
|
||||
waker: Option<Waker>,
|
||||
}
|
||||
|
||||
impl Future for TimerFuture {
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
// Look at the shared state to see if the timer has already completed.
|
||||
let mut shared_state = self.shared_state.lock().unwrap();
|
||||
if shared_state.completed {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
// Set waker so that the thread can wake up the current task
|
||||
// when the timer has completed, ensuring that the future is polled
|
||||
// again and sees that `completed = true`.
|
||||
//
|
||||
// It's tempting to do this once rather than repeatedly cloning
|
||||
// the waker each time. However, the `TimerFuture` can move between
|
||||
// tasks on the executor, which could cause a stale waker pointing
|
||||
// to the wrong task, preventing `TimerFuture` from waking up
|
||||
// correctly.
|
||||
//
|
||||
// N.B. it's possible to check for this using the `Waker::will_wake`
|
||||
// function, but we omit that here to keep things simple.
|
||||
shared_state.waker = Some(cx.waker().clone());
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TimerFuture {
|
||||
/// Create a new `TimerFuture` which will complete after the provided
|
||||
/// timeout.
|
||||
pub fn new(duration: Duration) -> Self {
|
||||
let shared_state = Arc::new(Mutex::new(SharedState {
|
||||
completed: false,
|
||||
waker: None,
|
||||
}));
|
||||
|
||||
// Spawn the new thread
|
||||
let thread_shared_state = shared_state.clone();
|
||||
thread::spawn(move || {
|
||||
thread::sleep(duration);
|
||||
let mut shared_state = thread_shared_state.lock().unwrap();
|
||||
// Signal that the timer has completed and wake up the last
|
||||
// task on which the future was polled, if one exists.
|
||||
shared_state.completed = true;
|
||||
if let Some(waker) = shared_state.waker.take() {
|
||||
waker.wake()
|
||||
}
|
||||
});
|
||||
|
||||
TimerFuture { shared_state }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
Reference in New Issue
Block a user