From eefa4f6f871d1fbcc97d58afdea50c3830261955 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 12:26:55 +0100 Subject: [PATCH 01/35] Use function to produce error string for context missing Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 7 ++-- tokio/src/runtime/blocking/pool.rs | 4 +-- tokio/src/runtime/context.rs | 54 ++++++++++++++++++++++++++++++ tokio/src/runtime/handle.rs | 4 +-- tokio/src/task/spawn.rs | 2 +- 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index a1784dff414..80d9570e5ce 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -17,6 +17,7 @@ use scheduled_io::ScheduledIo; use crate::park::{Park, Unpark}; use crate::util::slab::{self, Slab}; use crate::{loom::sync::Mutex, util::bit}; +use crate::runtime::context; use std::fmt; use std::io; @@ -259,8 +260,8 @@ cfg_rt! { /// This function panics if there is no current reactor set and `rt` feature /// flag is not enabled. pub(super) fn current() -> Self { - crate::runtime::context::io_handle() - .expect("there is no reactor running, must be called from the context of Tokio runtime") + context::io_handle() + .expect(&context::missing_error(&[])) } } } @@ -274,7 +275,7 @@ cfg_not_rt! { /// This function panics if there is no current reactor set, or if the `rt` /// feature flag is not enabled. pub(super) fn current() -> Self { - panic!("there is no reactor running, must be called from the context of Tokio runtime with `rt` enabled.") + panic!(&context::missing_error(Some(&[&"rt"]))) } } } diff --git a/tokio/src/runtime/blocking/pool.rs b/tokio/src/runtime/blocking/pool.rs index 9f98d898c4e..6c0fb367711 100644 --- a/tokio/src/runtime/blocking/pool.rs +++ b/tokio/src/runtime/blocking/pool.rs @@ -81,7 +81,7 @@ where F: FnOnce() -> 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) } @@ -91,7 +91,7 @@ where F: FnOnce() -> 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)); rt.blocking_spawner.spawn(task, &rt) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index 0817019db48..3046cb4f87e 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -1,5 +1,6 @@ //! Thread local runtime context use crate::runtime::Handle; +use std::fmt::Write; use std::cell::RefCell; @@ -77,3 +78,56 @@ impl Drop for EnterGuard { }); } } + +/// Returns an error string explaining that the Tokio context hasn't been instantiated. +pub(crate) fn missing_error(features: &[&str]) -> String { + // TODO: Include Tokio version + let sfx = if features.len() > 0 { + let mut sfx = String::from(" with "); + for (i, feat) in features.iter().enumerate() { + if i == 0 { + if features.len() > 1 { + write!(&mut sfx, "either ").expect("failed to write to string"); + } + } else { + if i == features.len() - 1 { + write!(&mut sfx, " or ").expect("failed to write to string"); + } else { + write!(&mut sfx, ", ").expect("failed to write to string"); + } + } + write!(&mut sfx, "{}", feat).expect("failed to write to string"); + } + write!(&mut sfx, " enabled").expect("failed to write to string"); + sfx + } else { + String::new() + }; + format!("there is no reactor running, must be called from the context of Tokio runtime{}", sfx) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_missing_error_no_features() { + assert_eq!(&missing_error(&[]), "there is no reactor running, must be called from the context of Tokio runtime"); + } + + #[test] + fn test_missing_error_one_feature() { + assert_eq!(&missing_error(&["rt"]), "there is no reactor running, must be called from the context of Tokio runtime with rt enabled"); + } + + #[test] + fn test_missing_error_two_features() { + assert_eq!(&missing_error(&["rt", "signal"]), "there is no reactor running, must be called from the context of Tokio runtime with either rt or signal enabled"); + } + + #[test] + fn test_missing_error_three_features() { + assert_eq!(&missing_error(&["rt", "signal", "sync"]), + "there is no reactor running, must be called from the context of Tokio runtime with either rt, signal or sync enabled"); + } +} diff --git a/tokio/src/runtime/handle.rs b/tokio/src/runtime/handle.rs index 6ff3c393020..6845839bbca 100644 --- a/tokio/src/runtime/handle.rs +++ b/tokio/src/runtime/handle.rs @@ -97,7 +97,7 @@ impl Handle { /// # } /// ``` 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 @@ -213,7 +213,7 @@ impl fmt::Debug for TryCurrentError { impl fmt::Display for TryCurrentError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("no tokio Runtime has been initialized") + f.write_str(&context::missing_error(&[])) } } diff --git a/tokio/src/task/spawn.rs b/tokio/src/task/spawn.rs index a060852dc23..08b9ff66cd0 100644 --- a/tokio/src/task/spawn.rs +++ b/tokio/src/task/spawn.rs @@ -129,7 +129,7 @@ cfg_rt! { T::Output: Send + 'static, { 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(&runtime::context::missing_error(&[&"basic_scheduler", &"threaded_scheduler"])); let task = crate::util::trace::task(task, "task"); spawn_handle.spawn(task) } From a7b29ee6148fd2ce6c1a4d64bf49ce271d1778aa Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 12:43:30 +0100 Subject: [PATCH 02/35] context::missing_error: Include Tokio version Signed-off-by: Arve Knudsen --- tokio/src/runtime/context.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index 3046cb4f87e..49cb3bf6629 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -103,7 +103,7 @@ pub(crate) fn missing_error(features: &[&str]) -> String { } else { String::new() }; - format!("there is no reactor running, must be called from the context of Tokio runtime{}", sfx) + format!("there is no reactor running, must be called from the context of Tokio {} runtime{}", env!("CARGO_PKG_VERSION"), sfx) } #[cfg(test)] @@ -112,22 +112,33 @@ mod tests { #[test] fn test_missing_error_no_features() { - assert_eq!(&missing_error(&[]), "there is no reactor running, must be called from the context of Tokio runtime"); + assert_eq!(missing_error(&[]), format!( + "there is no reactor running, must be called from the context of Tokio {} runtime", + env!("CARGO_PKG_VERSION") + )); } #[test] fn test_missing_error_one_feature() { - assert_eq!(&missing_error(&["rt"]), "there is no reactor running, must be called from the context of Tokio runtime with rt enabled"); + assert_eq!(missing_error(&["rt"]), format!( + "there is no reactor running, must be called from the context of Tokio {} runtime with rt enabled", + env!("CARGO_PKG_VERSION") + )); } #[test] fn test_missing_error_two_features() { - assert_eq!(&missing_error(&["rt", "signal"]), "there is no reactor running, must be called from the context of Tokio runtime with either rt or signal enabled"); + assert_eq!(missing_error(&["rt", "signal"]), format!( + "there is no reactor running, must be called from the context of Tokio {} runtime with either rt or signal enabled", + env!("CARGO_PKG_VERSION") + )); } #[test] fn test_missing_error_three_features() { - assert_eq!(&missing_error(&["rt", "signal", "sync"]), - "there is no reactor running, must be called from the context of Tokio runtime with either rt, signal or sync enabled"); + assert_eq!(missing_error(&["rt", "signal", "sync"]), format!( + "there is no reactor running, must be called from the context of Tokio {} runtime with either rt, signal or sync enabled", + env!("CARGO_PKG_VERSION") + )); } } From 5a45db88952e279e05fb198d0702eb28bc87d37d Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 12:52:06 +0100 Subject: [PATCH 03/35] context::missing_error: Hardcode Tokio version Signed-off-by: Arve Knudsen --- tokio/src/runtime/context.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index 49cb3bf6629..6226c372b07 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -103,7 +103,7 @@ pub(crate) fn missing_error(features: &[&str]) -> String { } else { String::new() }; - format!("there is no reactor running, must be called from the context of Tokio {} runtime{}", env!("CARGO_PKG_VERSION"), sfx) + format!("there is no reactor running, must be called from the context of Tokio 1.x runtime{}", sfx) } #[cfg(test)] @@ -112,33 +112,25 @@ mod tests { #[test] fn test_missing_error_no_features() { - assert_eq!(missing_error(&[]), format!( - "there is no reactor running, must be called from the context of Tokio {} runtime", - env!("CARGO_PKG_VERSION") - )); + assert_eq!(&missing_error(&[]), "there is no reactor running, must be called from the context of Tokio 1.x runtime"); } #[test] fn test_missing_error_one_feature() { - assert_eq!(missing_error(&["rt"]), format!( - "there is no reactor running, must be called from the context of Tokio {} runtime with rt enabled", - env!("CARGO_PKG_VERSION") - )); + assert_eq!(&missing_error(&["rt"]), + "there is no reactor running, must be called from the context of Tokio 1.x runtime with rt enabled"); } #[test] fn test_missing_error_two_features() { - assert_eq!(missing_error(&["rt", "signal"]), format!( - "there is no reactor running, must be called from the context of Tokio {} runtime with either rt or signal enabled", - env!("CARGO_PKG_VERSION") - )); + assert_eq!(&missing_error(&["rt", "signal"]), + "there is no reactor running, must be called from the context of Tokio 1.x runtime with either rt or signal enabled"); } #[test] fn test_missing_error_three_features() { - assert_eq!(missing_error(&["rt", "signal", "sync"]), format!( - "there is no reactor running, must be called from the context of Tokio {} runtime with either rt, signal or sync enabled", - env!("CARGO_PKG_VERSION") - )); + assert_eq!(&missing_error(&["rt", "signal", "sync"]), + "there is no reactor running, must be called from the context of Tokio 1.x runtime with either rt, signal or sync enabled" + ); } } From 68ce4af361fca5320d8dd408d96d63bca5753b97 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 13:11:19 +0100 Subject: [PATCH 04/35] Formatting Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 2 +- tokio/src/runtime/context.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index 80d9570e5ce..ddd49a1bdb4 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -15,9 +15,9 @@ mod scheduled_io; use scheduled_io::ScheduledIo; use crate::park::{Park, Unpark}; +use crate::runtime::context; use crate::util::slab::{self, Slab}; use crate::{loom::sync::Mutex, util::bit}; -use crate::runtime::context; use std::fmt; use std::io; diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index 6226c372b07..927b81771e6 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -103,7 +103,10 @@ pub(crate) fn missing_error(features: &[&str]) -> String { } else { String::new() }; - format!("there is no reactor running, must be called from the context of Tokio 1.x runtime{}", sfx) + format!( + "there is no reactor running, must be called from the context of Tokio 1.x runtime{}", + sfx + ) } #[cfg(test)] @@ -112,7 +115,10 @@ mod tests { #[test] fn test_missing_error_no_features() { - assert_eq!(&missing_error(&[]), "there is no reactor running, must be called from the context of Tokio 1.x runtime"); + assert_eq!( + &missing_error(&[]), + "there is no reactor running, must be called from the context of Tokio 1.x runtime" + ); } #[test] From ed42e6e537eee9887796ca3321611f5dae3e0686 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 13:16:05 +0100 Subject: [PATCH 05/35] Simplify Signed-off-by: Arve Knudsen --- tokio/src/runtime/context.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index 927b81771e6..effb36e60d2 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -89,12 +89,10 @@ pub(crate) fn missing_error(features: &[&str]) -> String { if features.len() > 1 { write!(&mut sfx, "either ").expect("failed to write to string"); } + } else if i == features.len() - 1 { + write!(&mut sfx, " or ").expect("failed to write to string"); } else { - if i == features.len() - 1 { - write!(&mut sfx, " or ").expect("failed to write to string"); - } else { - write!(&mut sfx, ", ").expect("failed to write to string"); - } + write!(&mut sfx, ", ").expect("failed to write to string"); } write!(&mut sfx, "{}", feat).expect("failed to write to string"); } From 6f90e124bf54fb7a4e24be64d29e9b5e7c5251c8 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 13:19:33 +0100 Subject: [PATCH 06/35] Simplify Signed-off-by: Arve Knudsen --- tokio/src/runtime/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index effb36e60d2..dc4d576cfd8 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -82,7 +82,7 @@ impl Drop for EnterGuard { /// Returns an error string explaining that the Tokio context hasn't been instantiated. pub(crate) fn missing_error(features: &[&str]) -> String { // TODO: Include Tokio version - let sfx = if features.len() > 0 { + let sfx = if !features.is_empty() { let mut sfx = String::from(" with "); for (i, feat) in features.iter().enumerate() { if i == 0 { From 8b26582ff917221e4a98023ab511cc2490209da5 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 13:51:16 +0100 Subject: [PATCH 07/35] Appease clippy Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 2 +- tokio/src/runtime/blocking/pool.rs | 4 ++-- tokio/src/runtime/handle.rs | 2 +- tokio/src/task/spawn.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index ddd49a1bdb4..cde5d4b1b2e 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -261,7 +261,7 @@ cfg_rt! { /// flag is not enabled. pub(super) fn current() -> Self { context::io_handle() - .expect(&context::missing_error(&[])) + .unwrap_or_else(|| panic!(context::missing_error(&[]))) } } } diff --git a/tokio/src/runtime/blocking/pool.rs b/tokio/src/runtime/blocking/pool.rs index 6c0fb367711..ea80d7dcd99 100644 --- a/tokio/src/runtime/blocking/pool.rs +++ b/tokio/src/runtime/blocking/pool.rs @@ -81,7 +81,7 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - let rt = context::current().expect(&context::missing_error(&[])); + let rt = context::current().unwrap_or_else(|| panic!(context::missing_error(&[]))); rt.spawn_blocking(func) } @@ -91,7 +91,7 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - let rt = context::current().expect(&context::missing_error(&[])); + let rt = context::current().unwrap_or_else(|| panic!(context::missing_error(&[]))); let (task, _handle) = task::joinable(BlockingTask::new(func)); rt.blocking_spawner.spawn(task, &rt) diff --git a/tokio/src/runtime/handle.rs b/tokio/src/runtime/handle.rs index 6845839bbca..375008da839 100644 --- a/tokio/src/runtime/handle.rs +++ b/tokio/src/runtime/handle.rs @@ -97,7 +97,7 @@ impl Handle { /// # } /// ``` pub fn current() -> Self { - context::current().expect(&context::missing_error(&[])) + context::current().unwrap_or_else(|| panic!(context::missing_error(&[]))) } /// Returns a Handle view over the currently running Runtime diff --git a/tokio/src/task/spawn.rs b/tokio/src/task/spawn.rs index 08b9ff66cd0..d4a615e0573 100644 --- a/tokio/src/task/spawn.rs +++ b/tokio/src/task/spawn.rs @@ -129,7 +129,7 @@ cfg_rt! { T::Output: Send + 'static, { let spawn_handle = runtime::context::spawn_handle() - .expect(&runtime::context::missing_error(&[&"basic_scheduler", &"threaded_scheduler"])); + .unwrap_or_else(|| panic!(runtime::context::missing_error(&[&"basic_scheduler", &"threaded_scheduler"]))); let task = crate::util::trace::task(task, "task"); spawn_handle.spawn(task) } From bf2d2fc1a82841a471852e68c6bccf5b8fedbdb0 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 14:12:08 +0100 Subject: [PATCH 08/35] Fix test errors Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 8 ++-- tokio/src/runtime/blocking/pool.rs | 5 ++- tokio/src/runtime/context.rs | 61 ------------------------------ tokio/src/runtime/handle.rs | 5 ++- tokio/src/task/spawn.rs | 3 +- tokio/src/util/error.rs | 61 ++++++++++++++++++++++++++++++ tokio/src/util/mod.rs | 2 + 7 files changed, 75 insertions(+), 70 deletions(-) create mode 100644 tokio/src/util/error.rs diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index cde5d4b1b2e..9df1f19959c 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -15,7 +15,7 @@ mod scheduled_io; use scheduled_io::ScheduledIo; use crate::park::{Park, Unpark}; -use crate::runtime::context; +use crate::util::error::context_missing_error; use crate::util::slab::{self, Slab}; use crate::{loom::sync::Mutex, util::bit}; @@ -260,8 +260,8 @@ cfg_rt! { /// This function panics if there is no current reactor set and `rt` feature /// flag is not enabled. pub(super) fn current() -> Self { - context::io_handle() - .unwrap_or_else(|| panic!(context::missing_error(&[]))) + crate::runtime::context::io_handle() + .unwrap_or_else(|| panic!(context_missing_error(&[]))) } } } @@ -275,7 +275,7 @@ cfg_not_rt! { /// This function panics if there is no current reactor set, or if the `rt` /// feature flag is not enabled. pub(super) fn current() -> Self { - panic!(&context::missing_error(Some(&[&"rt"]))) + panic!(context_missing_error(&[&"rt"])) } } } diff --git a/tokio/src/runtime/blocking/pool.rs b/tokio/src/runtime/blocking/pool.rs index ea80d7dcd99..198e8e5a577 100644 --- a/tokio/src/runtime/blocking/pool.rs +++ b/tokio/src/runtime/blocking/pool.rs @@ -9,6 +9,7 @@ use crate::runtime::builder::ThreadNameFn; use crate::runtime::context; use crate::runtime::task::{self, JoinHandle}; use crate::runtime::{Builder, Callback, Handle}; +use crate::util::error::context_missing_error; use std::collections::{HashMap, VecDeque}; use std::fmt; @@ -81,7 +82,7 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - let rt = context::current().unwrap_or_else(|| panic!(context::missing_error(&[]))); + let rt = context::current().unwrap_or_else(|| panic!(context_missing_error(&[]))); rt.spawn_blocking(func) } @@ -91,7 +92,7 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - let rt = context::current().unwrap_or_else(|| panic!(context::missing_error(&[]))); + let rt = context::current().unwrap_or_else(|| panic!(context_missing_error(&[]))); let (task, _handle) = task::joinable(BlockingTask::new(func)); rt.blocking_spawner.spawn(task, &rt) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index dc4d576cfd8..0817019db48 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -1,6 +1,5 @@ //! Thread local runtime context use crate::runtime::Handle; -use std::fmt::Write; use std::cell::RefCell; @@ -78,63 +77,3 @@ impl Drop for EnterGuard { }); } } - -/// Returns an error string explaining that the Tokio context hasn't been instantiated. -pub(crate) fn missing_error(features: &[&str]) -> String { - // TODO: Include Tokio version - let sfx = if !features.is_empty() { - let mut sfx = String::from(" with "); - for (i, feat) in features.iter().enumerate() { - if i == 0 { - if features.len() > 1 { - write!(&mut sfx, "either ").expect("failed to write to string"); - } - } else if i == features.len() - 1 { - write!(&mut sfx, " or ").expect("failed to write to string"); - } else { - write!(&mut sfx, ", ").expect("failed to write to string"); - } - write!(&mut sfx, "{}", feat).expect("failed to write to string"); - } - write!(&mut sfx, " enabled").expect("failed to write to string"); - sfx - } else { - String::new() - }; - format!( - "there is no reactor running, must be called from the context of Tokio 1.x runtime{}", - sfx - ) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_missing_error_no_features() { - assert_eq!( - &missing_error(&[]), - "there is no reactor running, must be called from the context of Tokio 1.x runtime" - ); - } - - #[test] - fn test_missing_error_one_feature() { - assert_eq!(&missing_error(&["rt"]), - "there is no reactor running, must be called from the context of Tokio 1.x runtime with rt enabled"); - } - - #[test] - fn test_missing_error_two_features() { - assert_eq!(&missing_error(&["rt", "signal"]), - "there is no reactor running, must be called from the context of Tokio 1.x runtime with either rt or signal enabled"); - } - - #[test] - fn test_missing_error_three_features() { - assert_eq!(&missing_error(&["rt", "signal", "sync"]), - "there is no reactor running, must be called from the context of Tokio 1.x runtime with either rt, signal or sync enabled" - ); - } -} diff --git a/tokio/src/runtime/handle.rs b/tokio/src/runtime/handle.rs index 375008da839..56678636f4d 100644 --- a/tokio/src/runtime/handle.rs +++ b/tokio/src/runtime/handle.rs @@ -1,6 +1,7 @@ use crate::runtime::blocking::task::BlockingTask; use crate::runtime::task::{self, JoinHandle}; use crate::runtime::{blocking, context, driver, Spawner}; +use crate::util::error::context_missing_error; use std::future::Future; use std::{error, fmt}; @@ -97,7 +98,7 @@ impl Handle { /// # } /// ``` pub fn current() -> Self { - context::current().unwrap_or_else(|| panic!(context::missing_error(&[]))) + context::current().unwrap_or_else(|| panic!(context_missing_error(&[]))) } /// Returns a Handle view over the currently running Runtime @@ -213,7 +214,7 @@ impl fmt::Debug for TryCurrentError { impl fmt::Display for TryCurrentError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&context::missing_error(&[])) + f.write_str(&context_missing_error(&[])) } } diff --git a/tokio/src/task/spawn.rs b/tokio/src/task/spawn.rs index d4a615e0573..603aa0477e1 100644 --- a/tokio/src/task/spawn.rs +++ b/tokio/src/task/spawn.rs @@ -1,5 +1,6 @@ use crate::runtime; use crate::task::JoinHandle; +use crate::util::error::context_missing_error; use std::future::Future; @@ -129,7 +130,7 @@ cfg_rt! { T::Output: Send + 'static, { let spawn_handle = runtime::context::spawn_handle() - .unwrap_or_else(|| panic!(runtime::context::missing_error(&[&"basic_scheduler", &"threaded_scheduler"]))); + .unwrap_or_else(|| panic!(context_missing_error(&[&"basic_scheduler", &"threaded_scheduler"]))); let task = crate::util::trace::task(task, "task"); spawn_handle.spawn(task) } diff --git a/tokio/src/util/error.rs b/tokio/src/util/error.rs new file mode 100644 index 00000000000..a49660e5293 --- /dev/null +++ b/tokio/src/util/error.rs @@ -0,0 +1,61 @@ +use std::fmt::Write; + +/// Returns an error string explaining that the Tokio context hasn't been instantiated. +pub(crate) fn context_missing_error(features: &[&str]) -> String { + // TODO: Include Tokio version + let sfx = if !features.is_empty() { + let mut sfx = String::from(" with "); + for (i, feat) in features.iter().enumerate() { + if i == 0 { + if features.len() > 1 { + write!(&mut sfx, "either ").expect("failed to write to string"); + } + } else if i == features.len() - 1 { + write!(&mut sfx, " or ").expect("failed to write to string"); + } else { + write!(&mut sfx, ", ").expect("failed to write to string"); + } + write!(&mut sfx, "{}", feat).expect("failed to write to string"); + } + write!(&mut sfx, " enabled").expect("failed to write to string"); + sfx + } else { + String::new() + }; + format!( + "there is no reactor running, must be called from the context of Tokio 1.x runtime{}", + sfx + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_context_missing_error_no_features() { + assert_eq!( + &context_missing_error(&[]), + "there is no reactor running, must be called from the context of Tokio 1.x runtime" + ); + } + + #[test] + fn test_context_missing_error_one_feature() { + assert_eq!(&context_missing_error(&["rt"]), + "there is no reactor running, must be called from the context of Tokio 1.x runtime with rt enabled"); + } + + #[test] + fn test_context_missing_error_two_features() { + assert_eq!(&context_missing_error(&["rt", "signal"]), + "there is no reactor running, must be called from the context of Tokio 1.x runtime with either rt or signal enabled"); + } + + #[test] + fn test_context_missing_error_three_features() { + assert_eq!(&context_missing_error(&["rt", "signal", "sync"]), + "there is no reactor running, must be called from the context of Tokio 1.x runtime with either rt, signal or sync enabled" + ); + } +} diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index 382bbb91a78..5f58dc20353 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -35,3 +35,5 @@ pub(crate) mod trace; #[cfg(any(feature = "macros"))] #[cfg_attr(not(feature = "macros"), allow(unreachable_pub))] pub use rand::thread_rng_n; + +pub(crate) mod error; From 61616add22bd979044ea8616569a7a01dea187bc Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 14:30:16 +0100 Subject: [PATCH 09/35] Fix test errors Signed-off-by: Arve Knudsen --- tokio/src/util/error.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tokio/src/util/error.rs b/tokio/src/util/error.rs index a49660e5293..ff7bd321dde 100644 --- a/tokio/src/util/error.rs +++ b/tokio/src/util/error.rs @@ -1,5 +1,7 @@ +#[cfg(any(feature = "rt", feature = "net"))] use std::fmt::Write; +#[cfg(any(feature = "rt", feature = "net"))] /// Returns an error string explaining that the Tokio context hasn't been instantiated. pub(crate) fn context_missing_error(features: &[&str]) -> String { // TODO: Include Tokio version From 1f90f0e10eef39b5446067a6735a52d193c9883f Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 14:34:48 +0100 Subject: [PATCH 10/35] Update tokio/src/util/error.rs Co-authored-by: Alice Ryhl --- tokio/src/util/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/src/util/error.rs b/tokio/src/util/error.rs index ff7bd321dde..dafa597e5a3 100644 --- a/tokio/src/util/error.rs +++ b/tokio/src/util/error.rs @@ -25,7 +25,7 @@ pub(crate) fn context_missing_error(features: &[&str]) -> String { String::new() }; format!( - "there is no reactor running, must be called from the context of Tokio 1.x runtime{}", + "there is no reactor running, must be called from the context of a Tokio 1.x runtime{}", sfx ) } From 9cf7fbe6388b7e1751db0256d7df6f816e70a267 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 16:45:36 +0100 Subject: [PATCH 11/35] Apply feedback from review Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 6 ++---- tokio/src/runtime/context.rs | 7 ++++--- tokio/src/task/spawn.rs | 2 +- tokio/src/util/error.rs | 10 ++++------ tokio/src/util/mod.rs | 1 + 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index 9df1f19959c..417439e814c 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -15,7 +15,6 @@ mod scheduled_io; use scheduled_io::ScheduledIo; use crate::park::{Park, Unpark}; -use crate::util::error::context_missing_error; use crate::util::slab::{self, Slab}; use crate::{loom::sync::Mutex, util::bit}; @@ -260,8 +259,7 @@ cfg_rt! { /// This function panics if there is no current reactor set and `rt` feature /// flag is not enabled. pub(super) fn current() -> Self { - crate::runtime::context::io_handle() - .unwrap_or_else(|| panic!(context_missing_error(&[]))) + crate::runtime::context::io_handle().expect("io not enabled on Tokio context") } } } @@ -275,7 +273,7 @@ cfg_not_rt! { /// This function panics if there is no current reactor set, or if the `rt` /// feature flag is not enabled. pub(super) fn current() -> Self { - panic!(context_missing_error(&[&"rt"])) + panic!(crate::util::error::context_missing_error(&[&"rt"])) } } } diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index 0817019db48..f0279221e9c 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -1,5 +1,6 @@ //! Thread local runtime context use crate::runtime::Handle; +use crate::util::error::context_missing_error; use std::cell::RefCell; @@ -13,9 +14,9 @@ pub(crate) fn current() -> Option { cfg_io_driver! { pub(crate) fn io_handle() -> crate::runtime::driver::IoHandle { - CONTEXT.with(|ctx| match *ctx.borrow() { - Some(ref ctx) => ctx.io_handle.clone(), - None => Default::default(), + CONTEXT.with(|ctx| { + let ctx = ctx.borrow(); + ctx.as_ref().unwrap_or_else(|| panic!(context_missing_error(&[]))).io_handle.clone() }) } } diff --git a/tokio/src/task/spawn.rs b/tokio/src/task/spawn.rs index 603aa0477e1..d37c121f46c 100644 --- a/tokio/src/task/spawn.rs +++ b/tokio/src/task/spawn.rs @@ -130,7 +130,7 @@ cfg_rt! { T::Output: Send + 'static, { let spawn_handle = runtime::context::spawn_handle() - .unwrap_or_else(|| panic!(context_missing_error(&[&"basic_scheduler", &"threaded_scheduler"]))); + .unwrap_or_else(|| panic!(context_missing_error(&[]))); let task = crate::util::trace::task(task, "task"); spawn_handle.spawn(task) } diff --git a/tokio/src/util/error.rs b/tokio/src/util/error.rs index dafa597e5a3..da3e4a9b87a 100644 --- a/tokio/src/util/error.rs +++ b/tokio/src/util/error.rs @@ -1,7 +1,5 @@ -#[cfg(any(feature = "rt", feature = "net"))] use std::fmt::Write; -#[cfg(any(feature = "rt", feature = "net"))] /// Returns an error string explaining that the Tokio context hasn't been instantiated. pub(crate) fn context_missing_error(features: &[&str]) -> String { // TODO: Include Tokio version @@ -38,26 +36,26 @@ mod tests { fn test_context_missing_error_no_features() { assert_eq!( &context_missing_error(&[]), - "there is no reactor running, must be called from the context of Tokio 1.x runtime" + "there is no reactor running, must be called from the context of a Tokio 1.x runtime" ); } #[test] fn test_context_missing_error_one_feature() { assert_eq!(&context_missing_error(&["rt"]), - "there is no reactor running, must be called from the context of Tokio 1.x runtime with rt enabled"); + "there is no reactor running, must be called from the context of a Tokio 1.x runtime with rt enabled"); } #[test] fn test_context_missing_error_two_features() { assert_eq!(&context_missing_error(&["rt", "signal"]), - "there is no reactor running, must be called from the context of Tokio 1.x runtime with either rt or signal enabled"); + "there is no reactor running, must be called from the context of a Tokio 1.x runtime with either rt or signal enabled"); } #[test] fn test_context_missing_error_three_features() { assert_eq!(&context_missing_error(&["rt", "signal", "sync"]), - "there is no reactor running, must be called from the context of Tokio 1.x runtime with either rt, signal or sync enabled" + "there is no reactor running, must be called from the context of a Tokio 1.x runtime with either rt, signal or sync enabled" ); } } diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index 5f58dc20353..651003b49f6 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -36,4 +36,5 @@ pub(crate) mod trace; #[cfg_attr(not(feature = "macros"), allow(unreachable_pub))] pub use rand::thread_rng_n; +#[cfg(any(feature = "rt", feature = "net"))] pub(crate) mod error; From 98b50b19b38e75a9155b0e24dd3c1406c0b5026b Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 17:12:26 +0100 Subject: [PATCH 12/35] Improve error messages Signed-off-by: Arve Knudsen --- tokio/src/runtime/context.rs | 12 ++++++------ tokio/src/time/driver/handle.rs | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index f0279221e9c..79f957e618f 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -24,18 +24,18 @@ cfg_io_driver! { cfg_signal_internal! { #[cfg(unix)] pub(crate) fn signal_handle() -> crate::runtime::driver::SignalHandle { - CONTEXT.with(|ctx| match *ctx.borrow() { - Some(ref ctx) => ctx.signal_handle.clone(), - None => Default::default(), + CONTEXT.with(|ctx| { + let ctx = ctx.borrow(); + ctx.as_ref().unwrap_or_else(|| panic!(context_missing_error(&[]))).signal_handle.clone() }) } } cfg_time! { pub(crate) fn time_handle() -> crate::runtime::driver::TimeHandle { - CONTEXT.with(|ctx| match *ctx.borrow() { - Some(ref ctx) => ctx.time_handle.clone(), - None => Default::default(), + CONTEXT.with(|ctx| { + let ctx = ctx.borrow(); + ctx.as_ref().unwrap_or_else(|| panic!(context_missing_error(&[]))).time_handle.clone() }) } diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index bfc49fbe451..1ee8535f948 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -47,7 +47,7 @@ cfg_rt! { /// panicking. pub(crate) fn current() -> Self { crate::runtime::context::time_handle() - .expect("there is no timer running, must be called from the context of Tokio runtime") + .expect("time must be enabled on the Tokio 1.x context") } } } @@ -71,8 +71,7 @@ cfg_not_rt! { /// lazy, and so outside executed inside the runtime successfuly without /// panicking. pub(crate) fn current() -> Self { - panic!("there is no timer running, must be called from the context of Tokio runtime or \ - `rt` is not enabled") + panic!("`rt` must be enabled") } } } From 3126cfd796ce014a772da06d1e5aaba108e8327c Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 17:24:03 +0100 Subject: [PATCH 13/35] Fix tests Signed-off-by: Arve Knudsen --- tokio/src/runtime/context.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index 79f957e618f..6e1aede602b 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -1,6 +1,5 @@ //! Thread local runtime context use crate::runtime::Handle; -use crate::util::error::context_missing_error; use std::cell::RefCell; @@ -16,7 +15,7 @@ cfg_io_driver! { pub(crate) fn io_handle() -> crate::runtime::driver::IoHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(context_missing_error(&[]))).io_handle.clone() + ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error(&[]))).io_handle.clone() }) } } @@ -26,7 +25,7 @@ cfg_signal_internal! { pub(crate) fn signal_handle() -> crate::runtime::driver::SignalHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(context_missing_error(&[]))).signal_handle.clone() + ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error(&[]))).signal_handle.clone() }) } } @@ -35,7 +34,7 @@ cfg_time! { pub(crate) fn time_handle() -> crate::runtime::driver::TimeHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(context_missing_error(&[]))).time_handle.clone() + ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error(&[]))).time_handle.clone() }) } From b2d8eb6da50005884b307224bb4a9012080a74bb Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 17:38:15 +0100 Subject: [PATCH 14/35] Fix test Signed-off-by: Arve Knudsen --- tokio/tests/no_rt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio/tests/no_rt.rs b/tokio/tests/no_rt.rs index 962eed7952d..a7f996a362b 100644 --- a/tokio/tests/no_rt.rs +++ b/tokio/tests/no_rt.rs @@ -7,8 +7,8 @@ use futures::executor::block_on; use std::net::TcpListener; #[test] -#[should_panic(expected = "no timer running")] -fn panics_when_no_timer() { +#[should_panic(expected = "no reactor running")] +fn timeout_panics_when_no_tokio_context() { block_on(timeout_value()); } From 18a6c13ae213e5d4be54f0d1c264afe84d6f3fff Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 17:51:02 +0100 Subject: [PATCH 15/35] Add integration test Signed-off-by: Arve Knudsen --- tokio/tests/rt_basic.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tokio/tests/rt_basic.rs b/tokio/tests/rt_basic.rs index 977a838c208..27d796d47b3 100644 --- a/tokio/tests/rt_basic.rs +++ b/tokio/tests/rt_basic.rs @@ -6,7 +6,7 @@ use tokio::sync::oneshot; use tokio_test::{assert_err, assert_ok}; use std::thread; -use std::time::Duration; +use tokio::time::{timeout, Duration}; mod support { pub(crate) mod mpsc_stream; @@ -135,6 +135,19 @@ fn acquire_mutex_in_drop() { drop(rt); } +#[test] +#[should_panic(expected = "time must be enabled on the Tokio 1.x context")] +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 { tokio::runtime::Builder::new_current_thread() .enable_all() From 5d6703948025082e9f62e5bb65bfa1a85b506c3d Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 18:05:49 +0100 Subject: [PATCH 16/35] Update tokio/tests/no_rt.rs Co-authored-by: Alice Ryhl --- tokio/tests/no_rt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/tests/no_rt.rs b/tokio/tests/no_rt.rs index a7f996a362b..241871acc28 100644 --- a/tokio/tests/no_rt.rs +++ b/tokio/tests/no_rt.rs @@ -7,7 +7,7 @@ use futures::executor::block_on; use std::net::TcpListener; #[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 timeout_panics_when_no_tokio_context() { block_on(timeout_value()); } From b1f45582707a111a78c53689ca758ad34e684374 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 18:06:13 +0100 Subject: [PATCH 17/35] Update tokio/src/time/driver/handle.rs Co-authored-by: Alice Ryhl --- tokio/src/time/driver/handle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index 1ee8535f948..4e0679f95ae 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -47,7 +47,7 @@ cfg_rt! { /// panicking. pub(crate) fn current() -> Self { crate::runtime::context::time_handle() - .expect("time must be enabled on the Tokio 1.x context") + .expect("A Tokio 1.x context was found, but timers are disabled on the runtime.") } } } From e62d4dd1e1960f4f314bf31f01f771a71ecb7c12 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 18:11:37 +0100 Subject: [PATCH 18/35] Fix test Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index 417439e814c..614f8426c69 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -273,7 +273,7 @@ cfg_not_rt! { /// This function panics if there is no current reactor set, or if the `rt` /// feature flag is not enabled. pub(super) fn current() -> Self { - panic!(crate::util::error::context_missing_error(&[&"rt"])) + panic!("`rt` must be enabled") } } } From c707db0d8d12c0620d65e97215629970c49e500b Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 18:17:17 +0100 Subject: [PATCH 19/35] Fix test Signed-off-by: Arve Knudsen --- tokio/src/time/driver/handle.rs | 2 +- tokio/src/util/mod.rs | 2 +- tokio/tests/rt_basic.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index 4e0679f95ae..3d66a5ed5d1 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -47,7 +47,7 @@ cfg_rt! { /// panicking. pub(crate) fn current() -> Self { crate::runtime::context::time_handle() - .expect("A Tokio 1.x context was found, but timers are disabled on the runtime.") + .expect("a Tokio 1.x context was found, but timers are disabled on the runtime") } } } diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index 651003b49f6..9150a03aebb 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -36,5 +36,5 @@ pub(crate) mod trace; #[cfg_attr(not(feature = "macros"), allow(unreachable_pub))] pub use rand::thread_rng_n; -#[cfg(any(feature = "rt", feature = "net"))] +#[cfg(feature = "rt")] pub(crate) mod error; diff --git a/tokio/tests/rt_basic.rs b/tokio/tests/rt_basic.rs index 27d796d47b3..8360ad51bc0 100644 --- a/tokio/tests/rt_basic.rs +++ b/tokio/tests/rt_basic.rs @@ -136,7 +136,7 @@ fn acquire_mutex_in_drop() { } #[test] -#[should_panic(expected = "time must be enabled on the Tokio 1.x context")] +#[should_panic(expected = "a Tokio 1.x context was found, but timers are disabled on the runtime")] fn timeout_panics_when_no_time_handle() { let rt = tokio::runtime::Builder::new_current_thread() .build() From a1bbf254efe8a8a48d3bfb6e5ceee1abbf8cecaa Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 18:17:45 +0100 Subject: [PATCH 20/35] Formatting Signed-off-by: Arve Knudsen --- tokio/tests/no_rt.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tokio/tests/no_rt.rs b/tokio/tests/no_rt.rs index 241871acc28..b58cdfd11a3 100644 --- a/tokio/tests/no_rt.rs +++ b/tokio/tests/no_rt.rs @@ -7,7 +7,9 @@ use futures::executor::block_on; use std::net::TcpListener; #[test] -#[should_panic(expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime")] +#[should_panic( + 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()); } From bb9530b60a137734b86adc244ed5767dffede051 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 18:48:34 +0100 Subject: [PATCH 21/35] Add integration test Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 4 ++-- tokio/src/time/driver/handle.rs | 4 ++-- tokio/tests/io_driver.rs | 13 +++++++++++++ tokio/tests/rt_basic.rs | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index 614f8426c69..fe0a80e8c21 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -259,7 +259,7 @@ cfg_rt! { /// This function panics if there is no current reactor set and `rt` feature /// flag is not enabled. pub(super) fn current() -> Self { - crate::runtime::context::io_handle().expect("io not enabled on Tokio context") + crate::runtime::context::io_handle().expect("a Tokio 1.x context was found, but io is disabled") } } } @@ -273,7 +273,7 @@ cfg_not_rt! { /// This function panics if there is no current reactor set, or if the `rt` /// feature flag is not enabled. pub(super) fn current() -> Self { - panic!("`rt` must be enabled") + panic!("feature `rt` must be enabled on Tokio 1.x") } } } diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index 3d66a5ed5d1..488db1885a5 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -47,7 +47,7 @@ cfg_rt! { /// panicking. pub(crate) fn current() -> Self { crate::runtime::context::time_handle() - .expect("a Tokio 1.x context was found, but timers are disabled on the runtime") + .expect("a Tokio 1.x context was found, but timers are disabled") } } } @@ -71,7 +71,7 @@ cfg_not_rt! { /// lazy, and so outside executed inside the runtime successfuly without /// panicking. pub(crate) fn current() -> Self { - panic!("`rt` must be enabled") + panic!("feature `rt` must be enabled on Tokio 1.x") } } } diff --git a/tokio/tests/io_driver.rs b/tokio/tests/io_driver.rs index 9a40247ea98..3041df7f8d4 100644 --- a/tokio/tests/io_driver.rs +++ b/tokio/tests/io_driver.rs @@ -84,3 +84,16 @@ fn test_drop_on_notify() { // Force the reactor to turn rt.block_on(async {}); } + +#[test] +#[should_panic(expected = "a Tokio 1.x context was found, but io is disabled")] +fn panics_when_io_disabled() { + let rt = runtime::Builder::new_current_thread() + .build() + .unwrap(); + + // Force the reactor to turn + rt.block_on(async { + let _ = tokio::net::TcpListener::from_std(std::net::TcpListener::bind("127.0.0.1:0").unwrap()); + }); +} diff --git a/tokio/tests/rt_basic.rs b/tokio/tests/rt_basic.rs index 8360ad51bc0..5d50d388079 100644 --- a/tokio/tests/rt_basic.rs +++ b/tokio/tests/rt_basic.rs @@ -136,7 +136,7 @@ fn acquire_mutex_in_drop() { } #[test] -#[should_panic(expected = "a Tokio 1.x context was found, but timers are disabled on the runtime")] +#[should_panic(expected = "a Tokio 1.x context was found, but timers are disabled")] fn timeout_panics_when_no_time_handle() { let rt = tokio::runtime::Builder::new_current_thread() .build() From a10b38634f441bd44475455ca0d20bb3333982ad Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 18:53:12 +0100 Subject: [PATCH 22/35] Add integration test Signed-off-by: Arve Knudsen --- tokio/tests/io_driver.rs | 7 +++---- tokio/tests/no_rt.rs | 8 ++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tokio/tests/io_driver.rs b/tokio/tests/io_driver.rs index 3041df7f8d4..590bb9ecb0f 100644 --- a/tokio/tests/io_driver.rs +++ b/tokio/tests/io_driver.rs @@ -88,12 +88,11 @@ fn test_drop_on_notify() { #[test] #[should_panic(expected = "a Tokio 1.x context was found, but io is disabled")] fn panics_when_io_disabled() { - let rt = runtime::Builder::new_current_thread() - .build() - .unwrap(); + let rt = runtime::Builder::new_current_thread().build().unwrap(); // Force the reactor to turn rt.block_on(async { - let _ = tokio::net::TcpListener::from_std(std::net::TcpListener::bind("127.0.0.1:0").unwrap()); + let _ = + tokio::net::TcpListener::from_std(std::net::TcpListener::bind("127.0.0.1:0").unwrap()); }); } diff --git a/tokio/tests/no_rt.rs b/tokio/tests/no_rt.rs index b58cdfd11a3..f1d5b4e9322 100644 --- a/tokio/tests/no_rt.rs +++ b/tokio/tests/no_rt.rs @@ -27,3 +27,11 @@ async fn timeout_value() { let dur = Duration::from_millis(20); 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()); +} From d6af014a61e5d46325c4b1c7d10a4c5dcbdc8f1a Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 18:58:09 +0100 Subject: [PATCH 23/35] Remove argument from context_missing_error Signed-off-by: Arve Knudsen --- tokio/src/runtime/blocking/pool.rs | 4 +-- tokio/src/runtime/context.rs | 6 ++-- tokio/src/runtime/handle.rs | 4 +-- tokio/src/task/spawn.rs | 2 +- tokio/src/util/error.rs | 51 +++--------------------------- 5 files changed, 13 insertions(+), 54 deletions(-) diff --git a/tokio/src/runtime/blocking/pool.rs b/tokio/src/runtime/blocking/pool.rs index 198e8e5a577..897ddb4cb08 100644 --- a/tokio/src/runtime/blocking/pool.rs +++ b/tokio/src/runtime/blocking/pool.rs @@ -82,7 +82,7 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - let rt = context::current().unwrap_or_else(|| panic!(context_missing_error(&[]))); + let rt = context::current().unwrap_or_else(|| panic!(context_missing_error())); rt.spawn_blocking(func) } @@ -92,7 +92,7 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - let rt = context::current().unwrap_or_else(|| panic!(context_missing_error(&[]))); + let rt = context::current().unwrap_or_else(|| panic!(context_missing_error())); let (task, _handle) = task::joinable(BlockingTask::new(func)); rt.blocking_spawner.spawn(task, &rt) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index 6e1aede602b..e39ac7680e3 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -15,7 +15,7 @@ cfg_io_driver! { pub(crate) fn io_handle() -> crate::runtime::driver::IoHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error(&[]))).io_handle.clone() + ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error())).io_handle.clone() }) } } @@ -25,7 +25,7 @@ cfg_signal_internal! { pub(crate) fn signal_handle() -> crate::runtime::driver::SignalHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error(&[]))).signal_handle.clone() + ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error())).signal_handle.clone() }) } } @@ -34,7 +34,7 @@ cfg_time! { pub(crate) fn time_handle() -> crate::runtime::driver::TimeHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error(&[]))).time_handle.clone() + ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error())).time_handle.clone() }) } diff --git a/tokio/src/runtime/handle.rs b/tokio/src/runtime/handle.rs index 56678636f4d..95239f6149e 100644 --- a/tokio/src/runtime/handle.rs +++ b/tokio/src/runtime/handle.rs @@ -98,7 +98,7 @@ impl Handle { /// # } /// ``` pub fn current() -> Self { - context::current().unwrap_or_else(|| panic!(context_missing_error(&[]))) + context::current().unwrap_or_else(|| panic!(context_missing_error())) } /// Returns a Handle view over the currently running Runtime @@ -214,7 +214,7 @@ impl fmt::Debug for TryCurrentError { impl fmt::Display for TryCurrentError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&context_missing_error(&[])) + f.write_str(&context_missing_error()) } } diff --git a/tokio/src/task/spawn.rs b/tokio/src/task/spawn.rs index d37c121f46c..072ea85d25e 100644 --- a/tokio/src/task/spawn.rs +++ b/tokio/src/task/spawn.rs @@ -130,7 +130,7 @@ cfg_rt! { T::Output: Send + 'static, { let spawn_handle = runtime::context::spawn_handle() - .unwrap_or_else(|| panic!(context_missing_error(&[]))); + .unwrap_or_else(|| panic!(context_missing_error())); let task = crate::util::trace::task(task, "task"); spawn_handle.spawn(task) } diff --git a/tokio/src/util/error.rs b/tokio/src/util/error.rs index da3e4a9b87a..bc703a6840d 100644 --- a/tokio/src/util/error.rs +++ b/tokio/src/util/error.rs @@ -1,30 +1,8 @@ -use std::fmt::Write; - /// Returns an error string explaining that the Tokio context hasn't been instantiated. -pub(crate) fn context_missing_error(features: &[&str]) -> String { +pub(crate) fn context_missing_error() -> String { // TODO: Include Tokio version - let sfx = if !features.is_empty() { - let mut sfx = String::from(" with "); - for (i, feat) in features.iter().enumerate() { - if i == 0 { - if features.len() > 1 { - write!(&mut sfx, "either ").expect("failed to write to string"); - } - } else if i == features.len() - 1 { - write!(&mut sfx, " or ").expect("failed to write to string"); - } else { - write!(&mut sfx, ", ").expect("failed to write to string"); - } - write!(&mut sfx, "{}", feat).expect("failed to write to string"); - } - write!(&mut sfx, " enabled").expect("failed to write to string"); - sfx - } else { - String::new() - }; - format!( - "there is no reactor running, must be called from the context of a Tokio 1.x runtime{}", - sfx + String::from( + "there is no reactor running, must be called from the context of a Tokio 1.x runtime", ) } @@ -33,29 +11,10 @@ mod tests { use super::*; #[test] - fn test_context_missing_error_no_features() { + fn test_context_missing_error() { assert_eq!( - &context_missing_error(&[]), + &context_missing_error(), "there is no reactor running, must be called from the context of a Tokio 1.x runtime" ); } - - #[test] - fn test_context_missing_error_one_feature() { - assert_eq!(&context_missing_error(&["rt"]), - "there is no reactor running, must be called from the context of a Tokio 1.x runtime with rt enabled"); - } - - #[test] - fn test_context_missing_error_two_features() { - assert_eq!(&context_missing_error(&["rt", "signal"]), - "there is no reactor running, must be called from the context of a Tokio 1.x runtime with either rt or signal enabled"); - } - - #[test] - fn test_context_missing_error_three_features() { - assert_eq!(&context_missing_error(&["rt", "signal", "sync"]), - "there is no reactor running, must be called from the context of a Tokio 1.x runtime with either rt, signal or sync enabled" - ); - } } From 37f613a03819e44e07b91779062b71c2c432618a Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 19:00:21 +0100 Subject: [PATCH 24/35] Remove TODO Signed-off-by: Arve Knudsen --- tokio/src/util/error.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tokio/src/util/error.rs b/tokio/src/util/error.rs index bc703a6840d..12caaca09d6 100644 --- a/tokio/src/util/error.rs +++ b/tokio/src/util/error.rs @@ -1,6 +1,5 @@ /// Returns an error string explaining that the Tokio context hasn't been instantiated. pub(crate) fn context_missing_error() -> String { - // TODO: Include Tokio version String::from( "there is no reactor running, must be called from the context of a Tokio 1.x runtime", ) From 25a589447d78e0abf2eabc512cda3c148b198aa3 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Sun, 17 Jan 2021 19:06:17 +0100 Subject: [PATCH 25/35] Clean up Signed-off-by: Arve Knudsen --- tokio/tests/io_driver.rs | 1 - tokio/tests/no_rt.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tokio/tests/io_driver.rs b/tokio/tests/io_driver.rs index 590bb9ecb0f..1a9b20b752f 100644 --- a/tokio/tests/io_driver.rs +++ b/tokio/tests/io_driver.rs @@ -90,7 +90,6 @@ fn test_drop_on_notify() { fn panics_when_io_disabled() { let rt = runtime::Builder::new_current_thread().build().unwrap(); - // Force the reactor to turn rt.block_on(async { let _ = tokio::net::TcpListener::from_std(std::net::TcpListener::bind("127.0.0.1:0").unwrap()); diff --git a/tokio/tests/no_rt.rs b/tokio/tests/no_rt.rs index f1d5b4e9322..2ee2582cbab 100644 --- a/tokio/tests/no_rt.rs +++ b/tokio/tests/no_rt.rs @@ -15,7 +15,7 @@ fn timeout_panics_when_no_tokio_context() { } #[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() { let srv = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = srv.local_addr().unwrap(); From 37d8d8a571e6f95d51c00e1f5ee1632874f9ab17 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Mon, 18 Jan 2021 09:03:41 +0100 Subject: [PATCH 26/35] Use const string for context_missing_error Signed-off-by: Arve Knudsen --- tokio/src/runtime/blocking/pool.rs | 6 +++--- tokio/src/runtime/context.rs | 6 +++--- tokio/src/runtime/handle.rs | 6 +++--- tokio/src/task/spawn.rs | 4 ++-- tokio/src/util/error.rs | 21 ++------------------- tokio/tests/no_rt.rs | 4 +++- 6 files changed, 16 insertions(+), 31 deletions(-) diff --git a/tokio/src/runtime/blocking/pool.rs b/tokio/src/runtime/blocking/pool.rs index 897ddb4cb08..791e4050d82 100644 --- a/tokio/src/runtime/blocking/pool.rs +++ b/tokio/src/runtime/blocking/pool.rs @@ -9,7 +9,7 @@ use crate::runtime::builder::ThreadNameFn; use crate::runtime::context; use crate::runtime::task::{self, JoinHandle}; use crate::runtime::{Builder, Callback, Handle}; -use crate::util::error::context_missing_error; +use crate::util::error::CONTEXT_MISSING_ERROR; use std::collections::{HashMap, VecDeque}; use std::fmt; @@ -82,7 +82,7 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - let rt = context::current().unwrap_or_else(|| panic!(context_missing_error())); + let rt = context::current().expect(CONTEXT_MISSING_ERROR); rt.spawn_blocking(func) } @@ -92,7 +92,7 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - let rt = context::current().unwrap_or_else(|| panic!(context_missing_error())); + let rt = context::current().expect(CONTEXT_MISSING_ERROR); let (task, _handle) = task::joinable(BlockingTask::new(func)); rt.blocking_spawner.spawn(task, &rt) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index e39ac7680e3..6e4a01696b4 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -15,7 +15,7 @@ cfg_io_driver! { pub(crate) fn io_handle() -> crate::runtime::driver::IoHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error())).io_handle.clone() + ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).io_handle.clone() }) } } @@ -25,7 +25,7 @@ cfg_signal_internal! { pub(crate) fn signal_handle() -> crate::runtime::driver::SignalHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error())).signal_handle.clone() + ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).signal_handle.clone() }) } } @@ -34,7 +34,7 @@ cfg_time! { pub(crate) fn time_handle() -> crate::runtime::driver::TimeHandle { CONTEXT.with(|ctx| { let ctx = ctx.borrow(); - ctx.as_ref().unwrap_or_else(|| panic!(crate::util::error::context_missing_error())).time_handle.clone() + ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).time_handle.clone() }) } diff --git a/tokio/src/runtime/handle.rs b/tokio/src/runtime/handle.rs index 95239f6149e..76b28f24e36 100644 --- a/tokio/src/runtime/handle.rs +++ b/tokio/src/runtime/handle.rs @@ -1,7 +1,7 @@ use crate::runtime::blocking::task::BlockingTask; use crate::runtime::task::{self, JoinHandle}; use crate::runtime::{blocking, context, driver, Spawner}; -use crate::util::error::context_missing_error; +use crate::util::error::CONTEXT_MISSING_ERROR; use std::future::Future; use std::{error, fmt}; @@ -98,7 +98,7 @@ impl Handle { /// # } /// ``` pub fn current() -> Self { - context::current().unwrap_or_else(|| panic!(context_missing_error())) + context::current().expect(CONTEXT_MISSING_ERROR) } /// Returns a Handle view over the currently running Runtime @@ -214,7 +214,7 @@ impl fmt::Debug for TryCurrentError { impl fmt::Display for TryCurrentError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&context_missing_error()) + f.write_str(CONTEXT_MISSING_ERROR) } } diff --git a/tokio/src/task/spawn.rs b/tokio/src/task/spawn.rs index 072ea85d25e..d846fb4a816 100644 --- a/tokio/src/task/spawn.rs +++ b/tokio/src/task/spawn.rs @@ -1,6 +1,6 @@ use crate::runtime; use crate::task::JoinHandle; -use crate::util::error::context_missing_error; +use crate::util::error::CONTEXT_MISSING_ERROR; use std::future::Future; @@ -130,7 +130,7 @@ cfg_rt! { T::Output: Send + 'static, { let spawn_handle = runtime::context::spawn_handle() - .unwrap_or_else(|| panic!(context_missing_error())); + .expect(CONTEXT_MISSING_ERROR); let task = crate::util::trace::task(task, "task"); spawn_handle.spawn(task) } diff --git a/tokio/src/util/error.rs b/tokio/src/util/error.rs index 12caaca09d6..6a310bdfa43 100644 --- a/tokio/src/util/error.rs +++ b/tokio/src/util/error.rs @@ -1,19 +1,2 @@ -/// Returns an error string explaining that the Tokio context hasn't been instantiated. -pub(crate) fn context_missing_error() -> String { - String::from( - "there is no reactor running, must be called from the context of a Tokio 1.x runtime", - ) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_context_missing_error() { - assert_eq!( - &context_missing_error(), - "there is no reactor running, must be called from the context of a Tokio 1.x runtime" - ); - } -} +/// 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"; diff --git a/tokio/tests/no_rt.rs b/tokio/tests/no_rt.rs index 2ee2582cbab..8437b80468b 100644 --- a/tokio/tests/no_rt.rs +++ b/tokio/tests/no_rt.rs @@ -15,7 +15,9 @@ fn timeout_panics_when_no_tokio_context() { } #[test] -#[should_panic(expected = "there is no reactor running, must be called from the context of a Tokio 1.x runtime")] +#[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() { let srv = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = srv.local_addr().unwrap(); From 47ff6ef8d53629624740625fc0612e5ed7c82cf0 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Mon, 18 Jan 2021 09:04:08 +0100 Subject: [PATCH 27/35] Formatting Signed-off-by: Arve Knudsen --- tokio/src/util/error.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tokio/src/util/error.rs b/tokio/src/util/error.rs index 6a310bdfa43..518cb2c0aed 100644 --- a/tokio/src/util/error.rs +++ b/tokio/src/util/error.rs @@ -1,2 +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"; +pub(crate) const CONTEXT_MISSING_ERROR: &str = + "there is no reactor running, must be called from the context of a Tokio 1.x runtime"; From 0e6f64473bdeaaadb2d0f45e0cb119a38b2d63d7 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Tue, 19 Jan 2021 19:54:55 +0100 Subject: [PATCH 28/35] Fixup error messages Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 2 +- tokio/src/time/driver/handle.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index fe0a80e8c21..a0d7f6e2edf 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -273,7 +273,7 @@ cfg_not_rt! { /// This function panics if there is no current reactor set, or if the `rt` /// feature flag is not enabled. pub(super) fn current() -> Self { - panic!("feature `rt` must be enabled on Tokio 1.x") + panic!(&format!("{} with feature `rt` enabled", crate::util::error::CONTEXT_MISSING_ERROR)) } } } diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index 488db1885a5..7a59b00dc1d 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -71,7 +71,7 @@ cfg_not_rt! { /// lazy, and so outside executed inside the runtime successfuly without /// panicking. pub(crate) fn current() -> Self { - panic!("feature `rt` must be enabled on Tokio 1.x") + panic!(&format!("{} with feature `rt` enabled", crate::util::error::CONTEXT_MISSING_ERROR)) } } } From d0d77513f67d0a8adf07e8801978ca8bde440091 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Tue, 19 Jan 2021 20:46:09 +0100 Subject: [PATCH 29/35] Tweak error message Signed-off-by: Arve Knudsen --- tokio/src/io/driver/mod.rs | 2 +- tokio/src/time/driver/handle.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index a0d7f6e2edf..f990ed3165b 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -273,7 +273,7 @@ cfg_not_rt! { /// This function panics if there is no current reactor set, or if the `rt` /// feature flag is not enabled. pub(super) fn current() -> Self { - panic!(&format!("{} with feature `rt` enabled", crate::util::error::CONTEXT_MISSING_ERROR)) + panic!(crate::util::error::CONTEXT_MISSING_ERROR) } } } diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index 7a59b00dc1d..a8e2fc68168 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -71,7 +71,7 @@ cfg_not_rt! { /// lazy, and so outside executed inside the runtime successfuly without /// panicking. pub(crate) fn current() -> Self { - panic!(&format!("{} with feature `rt` enabled", crate::util::error::CONTEXT_MISSING_ERROR)) + panic!(crate::util::error::CONTEXT_MISSING_ERROR) } } } From 7abf22c32f758146e6bc059013d3e9c16ec29547 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Tue, 19 Jan 2021 20:53:25 +0100 Subject: [PATCH 30/35] Enable usage of util::error without rt feature Signed-off-by: Arve Knudsen --- tokio/src/util/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index 9150a03aebb..5f58dc20353 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -36,5 +36,4 @@ pub(crate) mod trace; #[cfg_attr(not(feature = "macros"), allow(unreachable_pub))] pub use rand::thread_rng_n; -#[cfg(feature = "rt")] pub(crate) mod error; From 3c34b952abc90982d52f8177b7fe35015fdc54a5 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Tue, 19 Jan 2021 21:03:54 +0100 Subject: [PATCH 31/35] Fix tests Signed-off-by: Arve Knudsen --- tokio/src/util/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index 5f58dc20353..92f67af2f25 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -36,4 +36,11 @@ pub(crate) mod trace; #[cfg_attr(not(feature = "macros"), allow(unreachable_pub))] pub use rand::thread_rng_n; +#[cfg(any( + feature = "rt", + feature = "time", + feature = "net", + feature = "process", + all(unix, feature = "signal") +))] pub(crate) mod error; From 8adddb18d28181d488a3ddb27e4f0e20ca9c96c0 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Wed, 20 Jan 2021 12:51:29 +0100 Subject: [PATCH 32/35] Apply suggestions from code review Co-authored-by: Alice Ryhl --- tokio/src/io/driver/mod.rs | 2 +- tokio/src/time/driver/handle.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index f990ed3165b..fa2d4208c72 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -259,7 +259,7 @@ cfg_rt! { /// This function panics if there is no current reactor set and `rt` feature /// flag is not enabled. pub(super) fn current() -> Self { - crate::runtime::context::io_handle().expect("a Tokio 1.x context was found, but io is disabled") + 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.") } } } diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index a8e2fc68168..e934b562be4 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -47,7 +47,7 @@ cfg_rt! { /// panicking. pub(crate) fn current() -> Self { crate::runtime::context::time_handle() - .expect("a Tokio 1.x context was found, but timers are disabled") + .expect("A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers.") } } } From c0a7f6352646b48b96200e285b499268a7b4c0db Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 20 Jan 2021 09:49:24 +0100 Subject: [PATCH 33/35] io: keep track of initialized bytes in read_to_end (#3426) --- tokio/src/io/util/mod.rs | 2 + tokio/src/io/util/read_to_end.rs | 68 ++++++------ tokio/src/io/util/read_to_string.rs | 20 ++-- tokio/src/io/util/vec_with_initialized.rs | 120 ++++++++++++++++++++++ tokio/tests/io_read_to_end.rs | 65 +++++++++++- 5 files changed, 227 insertions(+), 48 deletions(-) create mode 100644 tokio/src/io/util/vec_with_initialized.rs diff --git a/tokio/src/io/util/mod.rs b/tokio/src/io/util/mod.rs index e75ea03424c..e06e7e25e47 100644 --- a/tokio/src/io/util/mod.rs +++ b/tokio/src/io/util/mod.rs @@ -48,6 +48,7 @@ cfg_io_util! { mod read_line; mod read_to_end; + mod vec_with_initialized; cfg_process! { pub(crate) use read_to_end::read_to_end; } @@ -82,6 +83,7 @@ cfg_io_util! { cfg_not_io_util! { cfg_process! { + mod vec_with_initialized; mod read_to_end; // Used by process pub(crate) use read_to_end::read_to_end; diff --git a/tokio/src/io/util/read_to_end.rs b/tokio/src/io/util/read_to_end.rs index 1aee6810ee4..dff7d66d0c6 100644 --- a/tokio/src/io/util/read_to_end.rs +++ b/tokio/src/io/util/read_to_end.rs @@ -1,10 +1,11 @@ -use crate::io::{AsyncRead, ReadBuf}; +use crate::io::util::vec_with_initialized::{into_read_buf_parts, VecWithInitialized}; +use crate::io::AsyncRead; use pin_project_lite::pin_project; use std::future::Future; use std::io; use std::marker::PhantomPinned; -use std::mem::{self, MaybeUninit}; +use std::mem; use std::pin::Pin; use std::task::{Context, Poll}; @@ -13,7 +14,7 @@ pin_project! { #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct ReadToEnd<'a, R: ?Sized> { reader: &'a mut R, - buf: &'a mut Vec, + buf: VecWithInitialized<&'a mut Vec>, // The number of bytes appended to buf. This can be less than buf.len() if // the buffer was not empty when the operation was started. read: usize, @@ -27,22 +28,22 @@ pub(crate) fn read_to_end<'a, R>(reader: &'a mut R, buffer: &'a mut Vec) -> where R: AsyncRead + Unpin + ?Sized, { + // SAFETY: The generic type on VecWithInitialized is &mut Vec. ReadToEnd { reader, - buf: buffer, + buf: unsafe { VecWithInitialized::new(buffer) }, read: 0, _pin: PhantomPinned, } } -pub(super) fn read_to_end_internal( - buf: &mut Vec, +pub(super) fn read_to_end_internal>, R: AsyncRead + ?Sized>( + buf: &mut VecWithInitialized, mut reader: Pin<&mut R>, num_read: &mut usize, cx: &mut Context<'_>, ) -> Poll> { loop { - // safety: The caller promised to prepare the buffer. let ret = ready!(poll_read_to_end(buf, reader.as_mut(), cx)); match ret { Err(err) => return Poll::Ready(Err(err)), @@ -57,8 +58,8 @@ pub(super) fn read_to_end_internal( /// Tries to read from the provided AsyncRead. /// /// The length of the buffer is increased by the number of bytes read. -fn poll_read_to_end( - buf: &mut Vec, +fn poll_read_to_end>, R: AsyncRead + ?Sized>( + buf: &mut VecWithInitialized, read: Pin<&mut R>, cx: &mut Context<'_>, ) -> Poll> { @@ -68,37 +69,34 @@ fn poll_read_to_end( // of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every // time is 4,500 times (!) slower than this if the reader has a very small // amount of data to return. - reserve(buf, 32); + buf.reserve(32); - let mut unused_capacity = ReadBuf::uninit(get_unused_capacity(buf)); + // Get a ReadBuf into the vector. + let mut read_buf = buf.get_read_buf(); - let ptr = unused_capacity.filled().as_ptr(); - ready!(read.poll_read(cx, &mut unused_capacity))?; - assert_eq!(ptr, unused_capacity.filled().as_ptr()); + let filled_before = read_buf.filled().len(); + let poll_result = read.poll_read(cx, &mut read_buf); + let filled_after = read_buf.filled().len(); + let n = filled_after - filled_before; - let n = unused_capacity.filled().len(); - let new_len = buf.len() + n; + // Update the length of the vector using the result of poll_read. + let read_buf_parts = into_read_buf_parts(read_buf); + buf.apply_read_buf(read_buf_parts); - assert!(new_len <= buf.capacity()); - unsafe { - buf.set_len(new_len); - } - Poll::Ready(Ok(n)) -} - -/// Allocates more memory and ensures that the unused capacity is prepared for use -/// with the `AsyncRead`. -fn reserve(buf: &mut Vec, bytes: usize) { - if buf.capacity() - buf.len() >= bytes { - return; + match poll_result { + Poll::Pending => { + // In this case, nothing should have been read. However we still + // update the vector in case the poll_read call initialized parts of + // the vector's unused capacity. + debug_assert_eq!(filled_before, filled_after); + Poll::Pending + } + Poll::Ready(Err(err)) => { + debug_assert_eq!(filled_before, filled_after); + Poll::Ready(Err(err)) + } + Poll::Ready(Ok(())) => Poll::Ready(Ok(n)), } - buf.reserve(bytes); -} - -/// Returns the unused capacity of the provided vector. -fn get_unused_capacity(buf: &mut Vec) -> &mut [MaybeUninit] { - let uninit = bytes::BufMut::chunk_mut(buf); - unsafe { &mut *(uninit as *mut _ as *mut [MaybeUninit]) } } impl Future for ReadToEnd<'_, A> diff --git a/tokio/src/io/util/read_to_string.rs b/tokio/src/io/util/read_to_string.rs index e463203c0ae..215ead370d8 100644 --- a/tokio/src/io/util/read_to_string.rs +++ b/tokio/src/io/util/read_to_string.rs @@ -1,5 +1,6 @@ use crate::io::util::read_line::finish_string_read; use crate::io::util::read_to_end::read_to_end_internal; +use crate::io::util::vec_with_initialized::VecWithInitialized; use crate::io::AsyncRead; use pin_project_lite::pin_project; @@ -19,7 +20,7 @@ pin_project! { // while reading to postpone utf-8 handling until after reading. output: &'a mut String, // The actual allocation of the string is moved into this vector instead. - buf: Vec, + buf: VecWithInitialized>, // The number of bytes appended to buf. This can be less than buf.len() if // the buffer was not empty when the operation was started. read: usize, @@ -37,29 +38,25 @@ where R: AsyncRead + ?Sized + Unpin, { let buf = mem::replace(string, String::new()).into_bytes(); + // SAFETY: The generic type of the VecWithInitialized is Vec. ReadToString { reader, - buf, + buf: unsafe { VecWithInitialized::new(buf) }, output: string, read: 0, _pin: PhantomPinned, } } -/// # Safety -/// -/// Before first calling this method, the unused capacity must have been -/// prepared for use with the provided AsyncRead. This can be done using the -/// `prepare_buffer` function in `read_to_end.rs`. -unsafe fn read_to_string_internal( +fn read_to_string_internal( reader: Pin<&mut R>, output: &mut String, - buf: &mut Vec, + buf: &mut VecWithInitialized>, read: &mut usize, cx: &mut Context<'_>, ) -> Poll> { let io_res = ready!(read_to_end_internal(buf, reader, read, cx)); - let utf8_res = String::from_utf8(mem::replace(buf, Vec::new())); + let utf8_res = String::from_utf8(buf.take()); // At this point both buf and output are empty. The allocation is in utf8_res. @@ -77,7 +74,6 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let me = self.project(); - // safety: The constructor of ReadToString called `prepare_buffer`. - unsafe { read_to_string_internal(Pin::new(*me.reader), me.output, me.buf, me.read, cx) } + read_to_string_internal(Pin::new(*me.reader), me.output, me.buf, me.read, cx) } } diff --git a/tokio/src/io/util/vec_with_initialized.rs b/tokio/src/io/util/vec_with_initialized.rs new file mode 100644 index 00000000000..ca24719dbf6 --- /dev/null +++ b/tokio/src/io/util/vec_with_initialized.rs @@ -0,0 +1,120 @@ +use crate::io::ReadBuf; +use std::mem::MaybeUninit; + +/// This struct wraps a `Vec` or `&mut Vec`, combining it with a +/// `num_initialized`, which keeps track of the number of initialized bytes +/// in the unused capacity. +/// +/// The purpose of this struct is to remember how many bytes were initialized +/// through a `ReadBuf` from call to call. +/// +/// This struct has the safety invariant that the first `num_initialized` of the +/// vector's allocation must be initialized at any time. +#[derive(Debug)] +pub(crate) struct VecWithInitialized { + vec: V, + // The number of initialized bytes in the vector. + // Always between `vec.len()` and `vec.capacity()`. + num_initialized: usize, +} + +impl VecWithInitialized> { + #[cfg(feature = "io-util")] + pub(crate) fn take(&mut self) -> Vec { + self.num_initialized = 0; + std::mem::take(&mut self.vec) + } +} + +impl VecWithInitialized +where + V: AsMut>, +{ + /// Safety: The generic parameter `V` must be either `Vec` or `&mut Vec`. + pub(crate) unsafe fn new(mut vec: V) -> Self { + // SAFETY: The safety invariants of vector guarantee that the bytes up + // to its length are initialized. + Self { + num_initialized: vec.as_mut().len(), + vec, + } + } + + pub(crate) fn reserve(&mut self, num_bytes: usize) { + let vec = self.vec.as_mut(); + if vec.capacity() - vec.len() >= num_bytes { + return; + } + // SAFETY: Setting num_initialized to `vec.len()` is correct as + // `reserve` does not change the length of the vector. + self.num_initialized = vec.len(); + vec.reserve(num_bytes); + } + + #[cfg(feature = "io-util")] + pub(crate) fn is_empty(&mut self) -> bool { + self.vec.as_mut().is_empty() + } + + pub(crate) fn get_read_buf<'a>(&'a mut self) -> ReadBuf<'a> { + let num_initialized = self.num_initialized; + + // SAFETY: Creating the slice is safe because of the safety invariants + // on Vec. The safety invariants of `ReadBuf` will further guarantee + // that no bytes in the slice are de-initialized. + let vec = self.vec.as_mut(); + let len = vec.len(); + let cap = vec.capacity(); + let ptr = vec.as_mut_ptr().cast::>(); + let slice = unsafe { std::slice::from_raw_parts_mut::<'a, MaybeUninit>(ptr, cap) }; + + // SAFETY: This is safe because the safety invariants of + // VecWithInitialized say that the first num_initialized bytes must be + // initialized. + let mut read_buf = ReadBuf::uninit(slice); + unsafe { + read_buf.assume_init(num_initialized); + } + read_buf.set_filled(len); + + read_buf + } + + pub(crate) fn apply_read_buf(&mut self, parts: ReadBufParts) { + let vec = self.vec.as_mut(); + assert_eq!(vec.as_ptr(), parts.ptr); + + // SAFETY: + // The ReadBufParts really does point inside `self.vec` due to the above + // check, and the safety invariants of `ReadBuf` guarantee that the + // first `parts.initialized` bytes of `self.vec` really have been + // initialized. Additionally, `ReadBuf` guarantees that `parts.len` is + // at most `parts.initialized`, so the first `parts.len` bytes are also + // initialized. + // + // Note that this relies on the fact that `V` is either `Vec` or + // `&mut Vec`, so the vector returned by `self.vec.as_mut()` cannot + // change from call to call. + unsafe { + self.num_initialized = parts.initialized; + vec.set_len(parts.len); + } + } +} + +pub(crate) struct ReadBufParts { + // Pointer is only used to check that the ReadBuf actually came from the + // right VecWithInitialized. + ptr: *const u8, + len: usize, + initialized: usize, +} + +// This is needed to release the borrow on `VecWithInitialized`. +pub(crate) fn into_read_buf_parts(rb: ReadBuf<'_>) -> ReadBufParts { + ReadBufParts { + ptr: rb.filled().as_ptr(), + len: rb.filled().len(), + initialized: rb.initialized().len(), + } +} diff --git a/tokio/tests/io_read_to_end.rs b/tokio/tests/io_read_to_end.rs index ee636ba5963..171e6d6480e 100644 --- a/tokio/tests/io_read_to_end.rs +++ b/tokio/tests/io_read_to_end.rs @@ -1,7 +1,9 @@ #![warn(rust_2018_idioms)] #![cfg(feature = "full")] -use tokio::io::AsyncReadExt; +use std::pin::Pin; +use std::task::{Context, Poll}; +use tokio::io::{AsyncRead, AsyncReadExt, ReadBuf}; use tokio_test::assert_ok; #[tokio::test] @@ -13,3 +15,64 @@ async fn read_to_end() { assert_eq!(n, 11); assert_eq!(buf[..], b"hello world"[..]); } + +#[derive(Copy, Clone, Debug)] +enum State { + Initializing, + JustFilling, + Done, +} + +struct UninitTest { + num_init: usize, + state: State, +} + +impl AsyncRead for UninitTest { + fn poll_read( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + let me = Pin::into_inner(self); + let real_num_init = buf.initialized().len() - buf.filled().len(); + assert_eq!(real_num_init, me.num_init, "{:?}", me.state); + + match me.state { + State::Initializing => { + buf.initialize_unfilled_to(me.num_init + 2); + buf.advance(1); + me.num_init += 1; + + if me.num_init == 24 { + me.state = State::JustFilling; + } + } + State::JustFilling => { + buf.advance(1); + me.num_init -= 1; + + if me.num_init == 15 { + // The buffer is resized on next call. + me.num_init = 0; + me.state = State::Done; + } + } + State::Done => { /* .. do nothing .. */ } + } + + Poll::Ready(Ok(())) + } +} + +#[tokio::test] +async fn read_to_end_uninit() { + let mut buf = Vec::with_capacity(64); + let mut test = UninitTest { + num_init: 0, + state: State::Initializing, + }; + + test.read_to_end(&mut buf).await.unwrap(); + assert_eq!(buf.len(), 33); +} From d88b63de9782a6502b2c5a32c0cfa5bdb1437a8d Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 20 Jan 2021 09:53:31 +0100 Subject: [PATCH 34/35] util: add pollable Semaphore (#3444) --- tokio-util/Cargo.toml | 3 +- tokio-util/src/sync/mod.rs | 3 + tokio-util/src/sync/poll_semaphore.rs | 85 +++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 tokio-util/src/sync/poll_semaphore.rs diff --git a/tokio-util/Cargo.toml b/tokio-util/Cargo.toml index d48ac8083a9..0104bcc4cb7 100644 --- a/tokio-util/Cargo.toml +++ b/tokio-util/Cargo.toml @@ -47,6 +47,7 @@ futures-util = { version = "0.3.0", optional = true } log = "0.4" pin-project-lite = "0.2.0" slab = { version = "0.4.1", optional = true } # Backs `DelayQueue` +async-stream = "0.3.0" [dev-dependencies] tokio = { version = "1.0.0", features = ["full"] } @@ -55,8 +56,6 @@ tokio-test = { version = "0.4.0" } futures = "0.3.0" futures-test = "0.3.5" -async-stream = "0.3.0" - [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] diff --git a/tokio-util/src/sync/mod.rs b/tokio-util/src/sync/mod.rs index 159f12dbe39..7a0637d32a6 100644 --- a/tokio-util/src/sync/mod.rs +++ b/tokio-util/src/sync/mod.rs @@ -4,3 +4,6 @@ mod cancellation_token; pub use cancellation_token::{CancellationToken, WaitForCancellationFuture}; mod intrusive_double_linked_list; + +mod poll_semaphore; +pub use poll_semaphore::PollSemaphore; diff --git a/tokio-util/src/sync/poll_semaphore.rs b/tokio-util/src/sync/poll_semaphore.rs new file mode 100644 index 00000000000..6519bc6635d --- /dev/null +++ b/tokio-util/src/sync/poll_semaphore.rs @@ -0,0 +1,85 @@ +use futures_core::Stream; +use std::fmt; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; +use tokio::sync::{OwnedSemaphorePermit, Semaphore}; + +/// A wrapper around [`Semaphore`] that provides a `poll_acquire` method. +/// +/// [`Semaphore`]: tokio::sync::Semaphore +pub struct PollSemaphore { + semaphore: Arc, + inner: Pin + Send + Sync>>, +} + +impl PollSemaphore { + /// Create a new `PollSemaphore`. + pub fn new(semaphore: Arc) -> Self { + Self { + semaphore: semaphore.clone(), + inner: Box::pin(async_stream::stream! { + loop { + match semaphore.clone().acquire_owned().await { + Ok(permit) => yield permit, + Err(_closed) => break, + } + } + }), + } + } + + /// Closes the semaphore. + pub fn close(&self) { + self.semaphore.close() + } + + /// Obtain a clone of the inner semaphore. + pub fn clone_inner(&self) -> Arc { + self.semaphore.clone() + } + + /// Get back the inner semaphore. + pub fn into_inner(self) -> Arc { + self.semaphore + } + + /// Poll to acquire a permit from the semaphore. + /// + /// This can return the following values: + /// + /// - `Poll::Pending` if a permit is not currently available. + /// - `Poll::Ready(Some(permit))` if a permit was acquired. + /// - `Poll::Ready(None)` if the semaphore has been closed. + /// + /// When this method returns `Poll::Pending`, the current task is scheduled + /// to receive a wakeup when a permit becomes available, or when the + /// semaphore is closed. Note that on multiple calls to `poll_acquire`, only + /// the `Waker` from the `Context` passed to the most recent call is + /// scheduled to receive a wakeup. + pub fn poll_acquire(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.as_mut().poll_next(cx) + } +} + +impl Stream for PollSemaphore { + type Item = OwnedSemaphorePermit; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::into_inner(self).poll_acquire(cx) + } +} + +impl Clone for PollSemaphore { + fn clone(&self) -> PollSemaphore { + PollSemaphore::new(self.clone_inner()) + } +} + +impl fmt::Debug for PollSemaphore { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PollSemaphore") + .field("semaphore", &self.semaphore) + .finish() + } +} From f4598e8fac9262b2a4ea80ae615297f6c22e07c2 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Wed, 20 Jan 2021 13:36:16 +0100 Subject: [PATCH 35/35] Fix tests Signed-off-by: Arve Knudsen --- tokio/tests/io_driver.rs | 4 +++- tokio/tests/rt_basic.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tokio/tests/io_driver.rs b/tokio/tests/io_driver.rs index 1a9b20b752f..6fb566de582 100644 --- a/tokio/tests/io_driver.rs +++ b/tokio/tests/io_driver.rs @@ -86,7 +86,9 @@ fn test_drop_on_notify() { } #[test] -#[should_panic(expected = "a Tokio 1.x context was found, but io is disabled")] +#[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(); diff --git a/tokio/tests/rt_basic.rs b/tokio/tests/rt_basic.rs index 5d50d388079..4b1bdadc1ab 100644 --- a/tokio/tests/rt_basic.rs +++ b/tokio/tests/rt_basic.rs @@ -136,7 +136,9 @@ fn acquire_mutex_in_drop() { } #[test] -#[should_panic(expected = "a Tokio 1.x context was found, but timers are disabled")] +#[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()