Skip to content

Instantly share code, notes, and snippets.

@alexcrichton
Created January 26, 2017 00:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save alexcrichton/871b5bf058a2ce77ac4fedccf3fda9c9 to your computer and use it in GitHub Desktop.
Save alexcrichton/871b5bf058a2ce77ac4fedccf3fda9c9 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;
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()
}
}
}
@46bit
Copy link

46bit commented Jun 10, 2017

This was really helpful and thanks for posting it. One patch needed - WaitResult needs pub to be exported by wait_timeout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment