mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-09-25 12:00:35 +00:00
Add Handle::block_on method (#2437)
This commit is contained in:
parent
9bcb50660e
commit
d8139fef7a
@ -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)*) => {
|
||||
|
@ -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};
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ impl Unpark for UnparkThread {
|
||||
}
|
||||
}
|
||||
|
||||
cfg_blocking_impl! {
|
||||
cfg_block_on! {
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user