From 98d23b8b29da90f174fc61c66a5b8cd9f91778e9 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 18 Sep 2018 21:57:21 -0700 Subject: [PATCH] Make `tokio::run` panic if called from inside `tokio::run` (#646) This is implemented by creating an `Enter` instance from within `run`. This patch also introduces `Enter::block_on`. Fixes #504 --- src/runtime/mod.rs | 5 ++++- tests/runtime.rs | 12 ++++++++++++ tokio-executor/src/enter.rs | 9 +++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index c23d8dd1b..9ff0cc4c2 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -125,6 +125,7 @@ use reactor::{Background, Handle}; use std::io; +use tokio_executor::enter; use tokio_threadpool as threadpool; use futures; @@ -210,7 +211,9 @@ where F: Future + Send + 'static, { let mut runtime = Runtime::new().unwrap(); runtime.spawn(future); - runtime.shutdown_on_idle().wait().unwrap(); + enter().expect("nested tokio::run") + .block_on(runtime.shutdown_on_idle()) + .unwrap(); } impl Runtime { diff --git a/tests/runtime.rs b/tests/runtime.rs index ac40a6e06..66d10b951 100644 --- a/tests/runtime.rs +++ b/tests/runtime.rs @@ -390,3 +390,15 @@ mod from_block_on_all { test(|f| { tokio::spawn(f); }) } } + +#[test] +fn run_in_run() { + use std::panic; + + tokio::run(lazy(|| { + panic::catch_unwind(|| { + tokio::run(lazy(|| { Ok::<(), ()>(()) })) + }).unwrap_err(); + Ok::<(), ()>(()) + })); +} diff --git a/tokio-executor/src/enter.rs b/tokio-executor/src/enter.rs index c33cf6492..4d9af8ccf 100644 --- a/tokio-executor/src/enter.rs +++ b/tokio-executor/src/enter.rs @@ -3,6 +3,8 @@ use std::cell::Cell; use std::error::Error; use std::fmt; +use futures::{self, Future}; + thread_local!(static ENTERED: Cell = Cell::new(false)); /// Represents an executor context. @@ -80,6 +82,13 @@ impl Enter { pub fn make_permanent(mut self) { self.permanent = true; } + + /// Blocks the thread on the specified future, returning the value with + /// which that future completes. + pub fn block_on(&mut self, f: F) -> Result { + futures::executor::spawn(f).wait_future() + } + } impl fmt::Debug for Enter {