runtime: consolidate errors for context missing (#3441)

This commit is contained in:
Arve Knudsen 2021-01-20 14:29:13 +01:00 committed by GitHub
parent 36cf95ab62
commit fdde5583f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 77 additions and 24 deletions

View File

@ -259,8 +259,7 @@ cfg_rt! {
/// This function panics if there is no current reactor set and `rt` feature /// This function panics if there is no current reactor set and `rt` feature
/// flag is not enabled. /// flag is not enabled.
pub(super) fn current() -> Self { pub(super) fn current() -> Self {
crate::runtime::context::io_handle() crate::runtime::context::io_handle().expect("A Tokio 1.x context was found, but IO is disabled. Call `enable_io` on the runtime builder to enable IO.")
.expect("there is no reactor running, must be called from the context of Tokio runtime")
} }
} }
} }
@ -274,7 +273,7 @@ cfg_not_rt! {
/// This function panics if there is no current reactor set, or if the `rt` /// This function panics if there is no current reactor set, or if the `rt`
/// feature flag is not enabled. /// feature flag is not enabled.
pub(super) fn current() -> Self { pub(super) fn current() -> Self {
panic!("there is no reactor running, must be called from the context of Tokio runtime with `rt` enabled.") panic!(crate::util::error::CONTEXT_MISSING_ERROR)
} }
} }
} }

View File

@ -9,6 +9,7 @@ use crate::runtime::builder::ThreadNameFn;
use crate::runtime::context; use crate::runtime::context;
use crate::runtime::task::{self, JoinHandle}; use crate::runtime::task::{self, JoinHandle};
use crate::runtime::{Builder, Callback, Handle}; use crate::runtime::{Builder, Callback, Handle};
use crate::util::error::CONTEXT_MISSING_ERROR;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::fmt; use std::fmt;
@ -81,7 +82,7 @@ where
F: FnOnce() -> R + Send + 'static, F: FnOnce() -> R + Send + 'static,
R: Send + 'static, R: Send + 'static,
{ {
let rt = context::current().expect("not currently running on the Tokio runtime."); let rt = context::current().expect(CONTEXT_MISSING_ERROR);
rt.spawn_blocking(func) rt.spawn_blocking(func)
} }
@ -91,7 +92,7 @@ where
F: FnOnce() -> R + Send + 'static, F: FnOnce() -> R + Send + 'static,
R: Send + 'static, R: Send + 'static,
{ {
let rt = context::current().expect("not currently running on the Tokio runtime."); let rt = context::current().expect(CONTEXT_MISSING_ERROR);
let (task, _handle) = task::joinable(BlockingTask::new(func)); let (task, _handle) = task::joinable(BlockingTask::new(func));
rt.blocking_spawner.spawn(task, &rt) rt.blocking_spawner.spawn(task, &rt)

View File

@ -13,9 +13,9 @@ pub(crate) fn current() -> Option<Handle> {
cfg_io_driver! { cfg_io_driver! {
pub(crate) fn io_handle() -> crate::runtime::driver::IoHandle { pub(crate) fn io_handle() -> crate::runtime::driver::IoHandle {
CONTEXT.with(|ctx| match *ctx.borrow() { CONTEXT.with(|ctx| {
Some(ref ctx) => ctx.io_handle.clone(), let ctx = ctx.borrow();
None => Default::default(), ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).io_handle.clone()
}) })
} }
} }
@ -23,18 +23,18 @@ cfg_io_driver! {
cfg_signal_internal! { cfg_signal_internal! {
#[cfg(unix)] #[cfg(unix)]
pub(crate) fn signal_handle() -> crate::runtime::driver::SignalHandle { pub(crate) fn signal_handle() -> crate::runtime::driver::SignalHandle {
CONTEXT.with(|ctx| match *ctx.borrow() { CONTEXT.with(|ctx| {
Some(ref ctx) => ctx.signal_handle.clone(), let ctx = ctx.borrow();
None => Default::default(), ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).signal_handle.clone()
}) })
} }
} }
cfg_time! { cfg_time! {
pub(crate) fn time_handle() -> crate::runtime::driver::TimeHandle { pub(crate) fn time_handle() -> crate::runtime::driver::TimeHandle {
CONTEXT.with(|ctx| match *ctx.borrow() { CONTEXT.with(|ctx| {
Some(ref ctx) => ctx.time_handle.clone(), let ctx = ctx.borrow();
None => Default::default(), ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).time_handle.clone()
}) })
} }

View File

@ -1,6 +1,7 @@
use crate::runtime::blocking::task::BlockingTask; use crate::runtime::blocking::task::BlockingTask;
use crate::runtime::task::{self, JoinHandle}; use crate::runtime::task::{self, JoinHandle};
use crate::runtime::{blocking, context, driver, Spawner}; use crate::runtime::{blocking, context, driver, Spawner};
use crate::util::error::CONTEXT_MISSING_ERROR;
use std::future::Future; use std::future::Future;
use std::{error, fmt}; use std::{error, fmt};
@ -97,7 +98,7 @@ impl Handle {
/// # } /// # }
/// ``` /// ```
pub fn current() -> Self { pub fn current() -> Self {
context::current().expect("not currently running on the Tokio runtime.") context::current().expect(CONTEXT_MISSING_ERROR)
} }
/// Returns a Handle view over the currently running Runtime /// Returns a Handle view over the currently running Runtime
@ -213,7 +214,7 @@ impl fmt::Debug for TryCurrentError {
impl fmt::Display for TryCurrentError { impl fmt::Display for TryCurrentError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("no tokio Runtime has been initialized") f.write_str(CONTEXT_MISSING_ERROR)
} }
} }

View File

@ -1,5 +1,6 @@
use crate::runtime; use crate::runtime;
use crate::task::JoinHandle; use crate::task::JoinHandle;
use crate::util::error::CONTEXT_MISSING_ERROR;
use std::future::Future; use std::future::Future;
@ -129,7 +130,7 @@ cfg_rt! {
T::Output: Send + 'static, T::Output: Send + 'static,
{ {
let spawn_handle = runtime::context::spawn_handle() let spawn_handle = runtime::context::spawn_handle()
.expect("must be called from the context of Tokio runtime configured with either `basic_scheduler` or `threaded_scheduler`"); .expect(CONTEXT_MISSING_ERROR);
let task = crate::util::trace::task(task, "task"); let task = crate::util::trace::task(task, "task");
spawn_handle.spawn(task) spawn_handle.spawn(task)
} }

View File

@ -47,7 +47,7 @@ cfg_rt! {
/// panicking. /// panicking.
pub(crate) fn current() -> Self { pub(crate) fn current() -> Self {
crate::runtime::context::time_handle() crate::runtime::context::time_handle()
.expect("there is no timer running, must be called from the context of Tokio runtime") .expect("A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers.")
} }
} }
} }
@ -71,8 +71,7 @@ cfg_not_rt! {
/// lazy, and so outside executed inside the runtime successfuly without /// lazy, and so outside executed inside the runtime successfuly without
/// panicking. /// panicking.
pub(crate) fn current() -> Self { pub(crate) fn current() -> Self {
panic!("there is no timer running, must be called from the context of Tokio runtime or \ panic!(crate::util::error::CONTEXT_MISSING_ERROR)
`rt` is not enabled")
} }
} }
} }

3
tokio/src/util/error.rs Normal file
View File

@ -0,0 +1,3 @@
/// Error string explaining that the Tokio context hasn't been instantiated.
pub(crate) const CONTEXT_MISSING_ERROR: &str =
"there is no reactor running, must be called from the context of a Tokio 1.x runtime";

View File

@ -35,3 +35,12 @@ pub(crate) mod trace;
#[cfg(any(feature = "macros"))] #[cfg(any(feature = "macros"))]
#[cfg_attr(not(feature = "macros"), allow(unreachable_pub))] #[cfg_attr(not(feature = "macros"), allow(unreachable_pub))]
pub use rand::thread_rng_n; pub use rand::thread_rng_n;
#[cfg(any(
feature = "rt",
feature = "time",
feature = "net",
feature = "process",
all(unix, feature = "signal")
))]
pub(crate) mod error;

View File

@ -84,3 +84,16 @@ fn test_drop_on_notify() {
// Force the reactor to turn // Force the reactor to turn
rt.block_on(async {}); rt.block_on(async {});
} }
#[test]
#[should_panic(
expected = "A Tokio 1.x context was found, but IO is disabled. Call `enable_io` on the runtime builder to enable IO."
)]
fn panics_when_io_disabled() {
let rt = runtime::Builder::new_current_thread().build().unwrap();
rt.block_on(async {
let _ =
tokio::net::TcpListener::from_std(std::net::TcpListener::bind("127.0.0.1:0").unwrap());
});
}

View File

@ -7,13 +7,17 @@ use futures::executor::block_on;
use std::net::TcpListener; use std::net::TcpListener;
#[test] #[test]
#[should_panic(expected = "no timer running")] #[should_panic(
fn panics_when_no_timer() { expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime"
)]
fn timeout_panics_when_no_tokio_context() {
block_on(timeout_value()); block_on(timeout_value());
} }
#[test] #[test]
#[should_panic(expected = "no reactor running")] #[should_panic(
expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime"
)]
fn panics_when_no_reactor() { fn panics_when_no_reactor() {
let srv = TcpListener::bind("127.0.0.1:0").unwrap(); let srv = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = srv.local_addr().unwrap(); let addr = srv.local_addr().unwrap();
@ -25,3 +29,11 @@ async fn timeout_value() {
let dur = Duration::from_millis(20); let dur = Duration::from_millis(20);
let _ = timeout(dur, rx).await; let _ = timeout(dur, rx).await;
} }
#[test]
#[should_panic(
expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime"
)]
fn io_panics_when_no_tokio_context() {
let _ = tokio::net::TcpListener::from_std(std::net::TcpListener::bind("127.0.0.1:0").unwrap());
}

View File

@ -6,7 +6,7 @@ use tokio::sync::oneshot;
use tokio_test::{assert_err, assert_ok}; use tokio_test::{assert_err, assert_ok};
use std::thread; use std::thread;
use std::time::Duration; use tokio::time::{timeout, Duration};
mod support { mod support {
pub(crate) mod mpsc_stream; pub(crate) mod mpsc_stream;
@ -135,6 +135,21 @@ fn acquire_mutex_in_drop() {
drop(rt); drop(rt);
} }
#[test]
#[should_panic(
expected = "A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers."
)]
fn timeout_panics_when_no_time_handle() {
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
rt.block_on(async {
let (_tx, rx) = oneshot::channel::<()>();
let dur = Duration::from_millis(20);
let _ = timeout(dur, rx).await;
});
}
fn rt() -> Runtime { fn rt() -> Runtime {
tokio::runtime::Builder::new_current_thread() tokio::runtime::Builder::new_current_thread()
.enable_all() .enable_all()