Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace parking with std::thread::park #54

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions Cargo.toml
Expand Up @@ -21,15 +21,14 @@ exclude = ["/.*"]

[features]
default = ["std"]
std = ["alloc", "fastrand", "futures-io", "parking", "memchr", "waker-fn"]
std = ["alloc", "fastrand", "futures-io", "memchr", "waker-fn"]
alloc = []

[dependencies]
fastrand = { version = "1.3.4", optional = true }
futures-core = { version = "0.3.5", default-features = false }
futures-io = { version = "0.3.5", optional = true }
memchr = { version = "2.3.3", optional = true }
parking = { version = "2.0.0", optional = true }
pin-project-lite = "0.2.0"
waker-fn = { version = "1.0.0", optional = true }

Expand Down
55 changes: 14 additions & 41 deletions src/future.rs
Expand Up @@ -52,59 +52,32 @@ use core::task::{Context, Poll};
/// ```
#[cfg(feature = "std")]
pub fn block_on<T>(future: impl Future<Output = T>) -> T {
use std::cell::RefCell;
use std::task::Waker;

use parking::Parker;
use waker_fn::waker_fn;

// Pin the future on the stack.
crate::pin!(future);

// Creates a parker and an associated waker that unparks it.
fn parker_and_waker() -> (Parker, Waker) {
let parker = Parker::new();
let unparker = parker.unparker();
let waker = waker_fn(move || {
unparker.unpark();
});
(parker, waker)
}

thread_local! {
// Creates a cached waker that unparks the current thread it.
// Cached parker and waker for efficiency.
static CACHE: RefCell<(Parker, Waker)> = RefCell::new(parker_and_waker());
static CACHE: Waker = {
let thread = std::thread::current();
waker_fn(move || thread.unpark())
};
}

CACHE.with(|cache| {
// Try grabbing the cached parker and waker.
match cache.try_borrow_mut() {
Ok(cache) => {
// Use the cached parker and waker.
let (parker, waker) = &*cache;
let cx = &mut Context::from_waker(waker);

// Keep polling until the future is ready.
loop {
match future.as_mut().poll(cx) {
Poll::Ready(output) => return output,
Poll::Pending => parker.park(),
}
}
}
Err(_) => {
// Looks like this is a recursive `block_on()` call.
// Create a fresh parker and waker.
let (parker, waker) = parker_and_waker();
let cx = &mut Context::from_waker(&waker);

// Keep polling until the future is ready.
loop {
match future.as_mut().poll(cx) {
Poll::Ready(output) => return output,
Poll::Pending => parker.park(),
}
}
// Use the cached waker.
let waker = &*cache;
let cx = &mut Context::from_waker(waker);

// Keep polling until the future is ready.
loop {
match future.as_mut().poll(cx) {
Poll::Ready(output) => return output,
Poll::Pending => std::thread::park(),
}
}
})
Expand Down