Skip to content

Instantly share code, notes, and snippets.

@46bit
Forked from alexcrichton/main.rs
Last active June 10, 2017 19:42
Show Gist options
  • Save 46bit/2de0ca76baa6af50ad5cc640ff21b20c to your computer and use it in GitHub Desktop.
Save 46bit/2de0ca76baa6af50ad5cc640ff21b20c to your computer and use it in GitHub Desktop.
extern crate futures;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::sync::Arc;
use std::time::{Instant, Duration};
use futures::{Async, Future};
use futures::executor::{self, Spawn};
use futures::task::Unpark;
pub enum WaitResult<F: Future> {
Ok(F::Item),
Err(F::Error),
TimedOut(Spawn<F>),
}
pub fn wait_timeout<F: Future>(f: F, dur: Duration) -> WaitResult<F> {
let now = Instant::now();
let mut task = executor::spawn(f);
let thread = Arc::new(ThreadUnpark::new(thread::current()));
loop {
let cur = Instant::now();
if cur >= now + dur {
return WaitResult::TimedOut(task)
}
match task.poll_future(thread.clone()) {
Ok(Async::Ready(e)) => return WaitResult::Ok(e),
Ok(Async::NotReady) => {}
Err(e) => return WaitResult::Err(e),
}
thread.park(now + dur - cur);
}
struct ThreadUnpark {
thread: thread::Thread,
ready: AtomicBool,
}
impl ThreadUnpark {
fn new(thread: thread::Thread) -> ThreadUnpark {
ThreadUnpark {
thread: thread,
ready: AtomicBool::new(false),
}
}
fn park(&self, dur: Duration) {
if !self.ready.swap(false, Ordering::SeqCst) {
thread::park_timeout(dur);
}
}
}
impl Unpark for ThreadUnpark {
fn unpark(&self) {
self.ready.store(true, Ordering::SeqCst);
self.thread.unpark()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment