Add Handle::block_on method (#2437)

This commit is contained in:
Dan Burkert 2020-04-24 06:25:48 -06:00 committed by GitHub
parent 9bcb50660e
commit d8139fef7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 119 additions and 7 deletions

View File

@ -35,6 +35,22 @@ macro_rules! cfg_blocking_impl {
}
}
/// Enables enter::block_on
macro_rules! cfg_block_on {
($($item:item)*) => {
$(
#[cfg(any(
feature = "blocking",
feature = "fs",
feature = "dns",
feature = "io-std",
feature = "rt-core",
))]
$item
)*
}
}
/// Enables blocking API internals
macro_rules! cfg_not_blocking_impl {
($($item:item)*) => {

View File

@ -42,7 +42,7 @@ cfg_resource_drivers! {
mod thread;
pub(crate) use self::thread::ParkThread;
cfg_blocking_impl! {
cfg_block_on! {
pub(crate) use self::thread::{CachedParkThread, ParkError};
}

View File

@ -204,7 +204,7 @@ impl Unpark for UnparkThread {
}
}
cfg_blocking_impl! {
cfg_block_on! {
use std::marker::PhantomData;
use std::rc::Rc;

View File

@ -138,14 +138,11 @@ cfg_rt_threaded! {
}
}
cfg_blocking_impl! {
use crate::park::ParkError;
use std::time::Duration;
cfg_block_on! {
impl Enter {
/// Blocks the thread on the specified future, returning the value with
/// which that future completes.
pub(crate) fn block_on<F>(&mut self, mut f: F) -> Result<F::Output, ParkError>
pub(crate) fn block_on<F>(&mut self, mut f: F) -> Result<F::Output, crate::park::ParkError>
where
F: std::future::Future,
{
@ -170,7 +167,14 @@ cfg_blocking_impl! {
park.park()?;
}
}
}
}
cfg_blocking_impl! {
use crate::park::ParkError;
use std::time::Duration;
impl Enter {
/// Blocks the thread on the specified future for **at most** `timeout`
///
/// If the future completes before `timeout`, the result is returned. If

View File

@ -119,6 +119,47 @@ cfg_rt_core! {
{
self.spawner.spawn(future)
}
/// Run a future to completion on the Tokio runtime from a synchronous
/// context.
///
/// This runs the given future on the runtime, blocking until it is
/// complete, and yielding its resolved result. Any tasks or timers which
/// the future spawns internally will be executed on the runtime.
///
/// This method should not be called from an asynchronous context.
///
/// # Panics
///
/// This function panics if the executor is at capacity, if the provided
/// future panics, or if called within an asynchronous execution context.
///
/// # Examples
///
/// ```no_run
/// use tokio::runtime::Runtime;
/// use std::thread;
///
/// // Create the runtime
/// let rt = Runtime::new().unwrap();
/// let handle = rt.handle().clone();
///
/// // Use the runtime from another thread
/// let th = thread::spawn(move || {
/// // Execute the future, blocking the current thread until completion
/// handle.block_on(async {
/// println!("hello");
/// });
/// });
///
/// th.join().unwrap();
/// ```
pub fn block_on<F: Future>(&self, future: F) -> F::Output {
self.enter(|| {
let mut enter = crate::runtime::enter(true);
enter.block_on(future).expect("failed to park thread")
})
}
}
}

View File

@ -402,12 +402,33 @@ impl Runtime {
/// complete, and yielding its resolved result. Any tasks or timers which
/// the future spawns internally will be executed on the runtime.
///
/// `&mut` is required as calling `block_on` **may** result in advancing the
/// state of the runtime. The details depend on how the runtime is
/// configured. [`runtime::Handle::block_on`][handle] provides a version
/// that takes `&self`.
///
/// This method should not be called from an asynchronous context.
///
/// # Panics
///
/// This function panics if the executor is at capacity, if the provided
/// future panics, or if called within an asynchronous execution context.
///
/// # Examples
///
/// ```no_run
/// use tokio::runtime::Runtime;
///
/// // Create the runtime
/// let mut rt = Runtime::new().unwrap();
///
/// // Execute the future, blocking the current thread until completion
/// rt.block_on(async {
/// println!("hello");
/// });
/// ```
///
/// [handle]: fn@Handle::block_on
pub fn block_on<F: Future>(&mut self, future: F) -> F::Output {
let kind = &mut self.kind;

View File

@ -82,6 +82,18 @@ rt_test! {
assert!(win);
}
#[test]
fn block_on_handle_sync() {
let rt = rt();
let mut win = false;
rt.handle().block_on(async {
win = true;
});
assert!(win);
}
#[test]
fn block_on_async() {
let mut rt = rt();
@ -100,6 +112,24 @@ rt_test! {
assert_eq!(out, "ZOMG");
}
#[test]
fn block_on_handle_async() {
let rt = rt();
let out = rt.handle().block_on(async {
let (tx, rx) = oneshot::channel();
thread::spawn(move || {
thread::sleep(Duration::from_millis(50));
tx.send("ZOMG").unwrap();
});
assert_ok!(rx.await)
});
assert_eq!(out, "ZOMG");
}
#[test]
fn spawn_one_bg() {
let mut rt = rt();