From f3b8d888ffcdd5198c083725debca4987fa75d43 Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Wed, 23 Sep 2020 17:39:01 +0000 Subject: [PATCH 01/39] rt: Remove `threaded_scheduler()` and `basic_scheduler()` This PR removes the ability to set the threaded_scheduler and basic_scheduler directly via the builder methods. Now to select the basic_scheduler you must use `core_threads`. --- benches/mpsc.rs | 5 - benches/scheduler.rs | 1 - benches/signal.rs | 2 +- benches/spawn.rs | 14 +-- benches/sync_rwlock.rs | 7 +- benches/sync_semaphore.rs | 7 +- tokio-macros/src/entry.rs | 36 ++++--- tokio-macros/src/lib.rs | 8 +- tokio-test/src/lib.rs | 2 +- tokio-util/src/context.rs | 8 +- tokio-util/tests/context.rs | 8 +- tokio/src/io/stdio_common.rs | 2 +- tokio/src/lib.rs | 29 +----- tokio/src/runtime/builder.rs | 124 ++++++++++------------- tokio/src/runtime/mod.rs | 20 ++-- tokio/src/runtime/tests/loom_blocking.rs | 1 - tokio/src/runtime/tests/loom_pool.rs | 1 - tokio/src/signal/registry.rs | 2 +- tokio/src/signal/windows.rs | 2 +- tokio/tests/io_driver.rs | 2 +- tokio/tests/io_driver_drop.rs | 2 +- tokio/tests/rt_basic.rs | 2 +- tokio/tests/rt_common.rs | 4 +- tokio/tests/rt_threaded.rs | 10 +- tokio/tests/signal_ctrl_c.rs | 50 ++++++--- tokio/tests/signal_drop_rt.rs | 2 +- tokio/tests/signal_multi_rt.rs | 2 +- tokio/tests/task_blocking.rs | 41 ++------ tokio/tests/task_local_set.rs | 13 +-- tokio/tests/time_rt.rs | 6 +- 30 files changed, 171 insertions(+), 242 deletions(-) diff --git a/benches/mpsc.rs b/benches/mpsc.rs index ec07ad8f8bf..a1fb1858d21 100644 --- a/benches/mpsc.rs +++ b/benches/mpsc.rs @@ -45,7 +45,6 @@ fn send_large(b: &mut Bencher) { fn contention_bounded(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -72,7 +71,6 @@ fn contention_bounded(b: &mut Bencher) { fn contention_bounded_full(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -99,7 +97,6 @@ fn contention_bounded_full(b: &mut Bencher) { fn contention_unbounded(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -126,7 +123,6 @@ fn contention_unbounded(b: &mut Bencher) { fn uncontented_bounded(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -148,7 +144,6 @@ fn uncontented_bounded(b: &mut Bencher) { fn uncontented_unbounded(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); diff --git a/benches/scheduler.rs b/benches/scheduler.rs index 801de72a553..906528064e0 100644 --- a/benches/scheduler.rs +++ b/benches/scheduler.rs @@ -140,7 +140,6 @@ fn chained_spawn(b: &mut Bencher) { fn rt() -> Runtime { runtime::Builder::new() - .threaded_scheduler() .core_threads(4) .enable_all() .build() diff --git a/benches/signal.rs b/benches/signal.rs index d891326de0d..e3ad714c718 100644 --- a/benches/signal.rs +++ b/benches/signal.rs @@ -47,7 +47,7 @@ fn many_signals(bench: &mut Bencher) { let rt = runtime::Builder::new() // Intentionally single threaded to measure delays in propagating wakes - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap(); diff --git a/benches/spawn.rs b/benches/spawn.rs index f76daf3fbaa..717aad73741 100644 --- a/benches/spawn.rs +++ b/benches/spawn.rs @@ -11,7 +11,7 @@ async fn work() -> usize { fn basic_scheduler_local_spawn(bench: &mut Bencher) { let runtime = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); runtime.block_on(async { @@ -23,10 +23,7 @@ fn basic_scheduler_local_spawn(bench: &mut Bencher) { } fn threaded_scheduler_local_spawn(bench: &mut Bencher) { - let runtime = tokio::runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let runtime = tokio::runtime::Builder::new().build().unwrap(); runtime.block_on(async { bench.iter(|| { let h = tokio::spawn(work()); @@ -37,7 +34,7 @@ fn threaded_scheduler_local_spawn(bench: &mut Bencher) { fn basic_scheduler_remote_spawn(bench: &mut Bencher) { let runtime = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); @@ -48,10 +45,7 @@ fn basic_scheduler_remote_spawn(bench: &mut Bencher) { } fn threaded_scheduler_remote_spawn(bench: &mut Bencher) { - let runtime = tokio::runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let runtime = tokio::runtime::Builder::new().build().unwrap(); bench.iter(|| { let h = runtime.spawn(work()); diff --git a/benches/sync_rwlock.rs b/benches/sync_rwlock.rs index 30c66e49394..18f68a70271 100644 --- a/benches/sync_rwlock.rs +++ b/benches/sync_rwlock.rs @@ -5,7 +5,6 @@ use tokio::{sync::RwLock, task}; fn read_uncontended(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -24,7 +23,6 @@ fn read_uncontended(b: &mut Bencher) { fn read_concurrent_uncontended_multi(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -52,7 +50,7 @@ fn read_concurrent_uncontended_multi(b: &mut Bencher) { fn read_concurrent_uncontended(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); @@ -80,7 +78,6 @@ fn read_concurrent_uncontended(b: &mut Bencher) { fn read_concurrent_contended_multi(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -109,7 +106,7 @@ fn read_concurrent_contended_multi(b: &mut Bencher) { fn read_concurrent_contended(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); diff --git a/benches/sync_semaphore.rs b/benches/sync_semaphore.rs index 32d4aa2b50e..91f497ee274 100644 --- a/benches/sync_semaphore.rs +++ b/benches/sync_semaphore.rs @@ -5,7 +5,6 @@ use tokio::{sync::Semaphore, task}; fn uncontended(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -29,7 +28,6 @@ async fn task(s: Arc) { fn uncontended_concurrent_multi(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -52,7 +50,7 @@ fn uncontended_concurrent_multi(b: &mut Bencher) { fn uncontended_concurrent_single(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); @@ -75,7 +73,6 @@ fn uncontended_concurrent_single(b: &mut Bencher) { fn contended_concurrent_multi(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() .core_threads(6) - .threaded_scheduler() .build() .unwrap(); @@ -98,7 +95,7 @@ fn contended_concurrent_multi(b: &mut Bencher) { fn contended_concurrent_single(b: &mut Bencher) { let rt = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 2681f50d9c0..dea839f4b54 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -1,6 +1,5 @@ use proc_macro::TokenStream; use quote::quote; -use std::num::NonZeroUsize; #[derive(Clone, Copy, PartialEq)] enum Runtime { @@ -43,8 +42,8 @@ fn parse_knobs( if rt_threaded { match &namevalue.lit { syn::Lit::Int(expr) => { - let num = expr.base10_parse::().unwrap(); - if num.get() > 1 { + let num = expr.base10_parse::().unwrap(); + if num > 1 { runtime = Some(Runtime::Threaded); } else { runtime = Some(Runtime::Basic); @@ -77,7 +76,7 @@ fn parse_knobs( } "max_threads" => match &namevalue.lit { syn::Lit::Int(expr) => { - let num = expr.base10_parse::().unwrap(); + let num = expr.base10_parse::().unwrap(); if let Some(v) = core_threads { if num < v { @@ -128,17 +127,28 @@ fn parse_knobs( } } - let mut rt = quote! { tokio::runtime::Builder::new().basic_scheduler() }; + let mut rt = quote! { tokio::runtime::Builder::new() }; + if rt_threaded && (runtime == Some(Runtime::Threaded) || (runtime.is_none() && !is_test)) { - rt = quote! { #rt.threaded_scheduler() }; - } - if let Some(v) = core_threads.map(|v| v.get()) { - rt = quote! { #rt.core_threads(#v) }; + rt = quote! { #rt }; } - if let Some(v) = max_threads.map(|v| v.get()) { - rt = quote! { #rt.max_threads(#v) }; + + // if let Some(v) = core_threads { + // rt = quote! { #rt.core_threads(#v) }; + // } + + // if let Some(v) = max_threads { + // rt = quote! { #rt.max_threads(#v) }; + // } + + if is_test { + rt = quote! { #rt.core_threads(0) }; } + // if is_test && core_threads.is_none() { + // rt = quote! { #rt.core_threads(0) }; + // } + let header = { if is_test { quote! { @@ -269,7 +279,7 @@ pub(crate) mod old { #(#attrs)* #vis #sig { tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap() @@ -345,7 +355,7 @@ pub(crate) mod old { #(#attrs)* #vis fn #name() #ret { tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap() diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 09733ba5d4c..77eaaf78a41 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -62,7 +62,6 @@ use proc_macro::TokenStream; /// ```rust /// fn main() { /// tokio::runtime::Builder::new() -/// .threaded_scheduler() /// .enable_all() /// .build() /// .unwrap() @@ -88,7 +87,7 @@ use proc_macro::TokenStream; /// ```rust /// fn main() { /// tokio::runtime::Builder::new() -/// .basic_scheduler() +/// .core_threads(0) /// .enable_all() /// .build() /// .unwrap() @@ -112,7 +111,6 @@ use proc_macro::TokenStream; /// ```rust /// fn main() { /// tokio::runtime::Builder::new() -/// .threaded_scheduler() /// .core_threads(2) /// .enable_all() /// .build() @@ -191,7 +189,7 @@ pub fn main_threaded(args: TokenStream, item: TokenStream) -> TokenStream { /// ```rust /// fn main() { /// tokio::runtime::Builder::new() -/// .basic_scheduler() +/// .core_threads(0) /// .enable_all() /// .build() /// .unwrap() @@ -242,7 +240,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { /// ```rust /// fn main() { /// tokio::runtime::Builder::new() -/// .basic_scheduler() +/// .core_threads(0) /// .enable_all() /// .build() /// .unwrap() diff --git a/tokio-test/src/lib.rs b/tokio-test/src/lib.rs index cfbf80cee60..7bcb4df4918 100644 --- a/tokio-test/src/lib.rs +++ b/tokio-test/src/lib.rs @@ -29,7 +29,7 @@ pub fn block_on(future: F) -> F::Output { use tokio::runtime; let rt = runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap(); diff --git a/tokio-util/src/context.rs b/tokio-util/src/context.rs index e07538d9917..75fa4a6ea47 100644 --- a/tokio-util/src/context.rs +++ b/tokio-util/src/context.rs @@ -49,13 +49,13 @@ pub trait RuntimeExt { /// use tokio::time::{delay_for, Duration}; /// /// let rt = tokio::runtime::Builder::new() - /// .threaded_scheduler() /// .enable_all() - /// .build().unwrap(); + /// .build() + /// .unwrap(); /// /// let rt2 = tokio::runtime::Builder::new() - /// .threaded_scheduler() - /// .build().unwrap(); + /// .build() + /// .unwrap(); /// /// let fut = delay_for(Duration::from_millis(2)); /// diff --git a/tokio-util/tests/context.rs b/tokio-util/tests/context.rs index 2e39b14432a..7b6d1989cb1 100644 --- a/tokio-util/tests/context.rs +++ b/tokio-util/tests/context.rs @@ -7,17 +7,11 @@ use tokio_util::context::RuntimeExt; #[test] fn tokio_context_with_another_runtime() { let rt1 = Builder::new() - .threaded_scheduler() .core_threads(1) // no timer! .build() .unwrap(); - let rt2 = Builder::new() - .threaded_scheduler() - .core_threads(1) - .enable_all() - .build() - .unwrap(); + let rt2 = Builder::new().core_threads(1).enable_all().build().unwrap(); // Without the `HandleExt.wrap()` there would be a panic because there is // no timer running, since it would be referencing runtime r1. diff --git a/tokio/src/io/stdio_common.rs b/tokio/src/io/stdio_common.rs index a86ca37573d..0e47ac1555a 100644 --- a/tokio/src/io/stdio_common.rs +++ b/tokio/src/io/stdio_common.rs @@ -124,7 +124,7 @@ mod tests { wr.write_all(data.as_bytes()).await.unwrap(); }; crate::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap() .block_on(fut); diff --git a/tokio/src/lib.rs b/tokio/src/lib.rs index 4fe82cf2289..2d01823987d 100644 --- a/tokio/src/lib.rs +++ b/tokio/src/lib.rs @@ -408,32 +408,9 @@ cfg_macros! { #[doc(hidden)] pub use tokio_macros::select_priv_declare_output_enum; - doc_rt_core! { - cfg_rt_threaded! { - // This is the docs.rs case (with all features) so make sure macros - // is included in doc(cfg). - - #[cfg(not(test))] // Work around for rust-lang/rust#62127 - #[cfg_attr(docsrs, doc(cfg(feature = "macros")))] - pub use tokio_macros::main_threaded as main; - - #[cfg_attr(docsrs, doc(cfg(feature = "macros")))] - pub use tokio_macros::test_threaded as test; - } - - cfg_not_rt_threaded! { - #[cfg(not(test))] // Work around for rust-lang/rust#62127 - pub use tokio_macros::main_basic as main; - pub use tokio_macros::test_basic as test; - } - } - - // Maintains old behavior - cfg_not_rt_core! { - #[cfg(not(test))] - pub use tokio_macros::main; - pub use tokio_macros::test; - } + #[cfg(not(test))] + pub use tokio_macros::main; + pub use tokio_macros::test; } // TODO: rm diff --git a/tokio/src/runtime/builder.rs b/tokio/src/runtime/builder.rs index 043371c7726..e50a349c52a 100644 --- a/tokio/src/runtime/builder.rs +++ b/tokio/src/runtime/builder.rs @@ -27,7 +27,6 @@ use std::time::Duration; /// fn main() { /// // build runtime /// let runtime = Builder::new() -/// .threaded_scheduler() /// .core_threads(4) /// .thread_name("my-custom-name") /// .thread_stack_size(3 * 1024 * 1024) @@ -38,9 +37,6 @@ use std::time::Duration; /// } /// ``` pub struct Builder { - /// The task execution model to use. - kind: Kind, - /// Whether or not to enable the I/O driver enable_io: bool, @@ -75,15 +71,6 @@ pub struct Builder { pub(crate) type ThreadNameFn = std::sync::Arc String + Send + Sync + 'static>; -#[derive(Debug, Clone, Copy)] -enum Kind { - Shell, - #[cfg(feature = "rt-core")] - Basic, - #[cfg(feature = "rt-threaded")] - ThreadPool, -} - impl Builder { /// Returns a new runtime builder initialized with default configuration /// values. @@ -91,9 +78,6 @@ impl Builder { /// Configuration methods can be chained on the return value. pub fn new() -> Builder { Builder { - // No task execution by default - kind: Kind::Shell, - // I/O defaults to "off" enable_io: false, @@ -132,7 +116,6 @@ impl Builder { /// use tokio::runtime; /// /// let rt = runtime::Builder::new() - /// .threaded_scheduler() /// .enable_all() /// .build() /// .unwrap(); @@ -146,40 +129,62 @@ impl Builder { self } - #[deprecated(note = "In future will be replaced by core_threads method")] - /// Sets the maximum number of worker threads for the `Runtime`'s thread pool. + /// Sets the number of threads the `Runtime` will use. When `val` is set to + /// `0` or `1` this will use a single-threaded runtime. When `val` is set to + /// some value `>1` it will create a work-stealing runtime. /// - /// This must be a number between 1 and 32,768 though it is advised to keep + /// This should be a number between 0 and 32,768 though it is advised to keep /// this value on the smaller side. /// /// The default value is the number of cores available to the system. - pub fn num_threads(&mut self, val: usize) -> &mut Self { - self.core_threads = Some(val); - self - } - - /// Sets the core number of worker threads for the `Runtime`'s thread pool. /// - /// This should be a number between 1 and 32,768 though it is advised to keep - /// this value on the smaller side. + /// # Examples /// - /// The default value is the number of cores available to the system. + /// ## Work stealing runtime with 4 threads + /// + /// ``` + /// use tokio::runtime; + /// + /// // This will spawn a work-stealing runtime with 4 worker threads. + /// let rt = runtime::Builder::new() + /// .core_threads(4) + /// .build() + /// .unwrap(); /// - /// These threads will be always active and running. + /// rt.spawn(async move {}); + /// ``` /// - /// # Examples + /// ## Single threaded runtime on the current thread /// /// ``` /// use tokio::runtime; /// + /// // Create a runtime that _must_ be driven from a call + /// // to `Runtime::block_on`. /// let rt = runtime::Builder::new() - /// .threaded_scheduler() - /// .core_threads(4) + /// .core_threads(0) + /// .build() + /// .unwrap(); + /// + /// // This will run the runtime and future on the current thread + /// rt.block_on(async move {}); + /// ``` + /// + /// ## Single threaded runtime with 1 worker thread + /// + /// ``` + /// use tokio::runtime; + /// + /// // Spawn a single threaded runtime on a background thread. + /// let rt = runtime::Builder::new() + /// .core_threads(1) /// .build() /// .unwrap(); + /// + /// // This will run the future on the single worker thread. + /// rt.spawn(async move {}); /// ``` pub fn core_threads(&mut self, val: usize) -> &mut Self { - assert_ne!(val, 0, "Core threads cannot be zero"); self.core_threads = Some(val); self } @@ -190,7 +195,7 @@ impl Builder { /// Having `max_threads` less than `core_threads` results in invalid configuration /// when building multi-threaded `Runtime`, which would cause a panic. /// - /// Similarly to the `core_threads`, this number should be between 1 and 32,768. + /// Similarly to the `core_threads`, this number should be between 0 and 32,768. /// /// The default value is 512. /// @@ -199,7 +204,6 @@ impl Builder { /// Otherwise as `core_threads` are always active, it limits additional threads (e.g. for /// blocking annotations) as `max_threads - core_threads`. pub fn max_threads(&mut self, val: usize) -> &mut Self { - assert_ne!(val, 0, "Thread limit cannot be zero"); self.max_threads = val; self } @@ -268,7 +272,6 @@ impl Builder { /// /// # pub fn main() { /// let rt = runtime::Builder::new() - /// .threaded_scheduler() /// .thread_stack_size(32 * 1024) /// .build(); /// # } @@ -290,7 +293,6 @@ impl Builder { /// /// # pub fn main() { /// let runtime = runtime::Builder::new() - /// .threaded_scheduler() /// .on_thread_start(|| { /// println!("thread started"); /// }) @@ -317,7 +319,6 @@ impl Builder { /// /// # pub fn main() { /// let runtime = runtime::Builder::new() - /// .threaded_scheduler() /// .on_thread_stop(|| { /// println!("thread stopping"); /// }) @@ -335,7 +336,7 @@ impl Builder { /// Creates the configured `Runtime`. /// - /// The returned `ThreadPool` instance is ready to spawn tasks. + /// The returned `Runtime` instance is ready to spawn tasks. /// /// # Examples /// @@ -349,12 +350,19 @@ impl Builder { /// }); /// ``` pub fn build(&mut self) -> io::Result { - match self.kind { - Kind::Shell => self.build_shell_runtime(), + match self.core_threads { #[cfg(feature = "rt-core")] - Kind::Basic => self.build_basic_runtime(), + Some(n) if n == 0 => self.build_basic_runtime(), + #[cfg(feature = "rt-threaded")] - Kind::ThreadPool => self.build_threaded_runtime(), + Some(_) | None => self.build_threaded_runtime(), + + #[cfg(not(feature = "rt-threaded"))] + #[cfg(feature = "rt-core")] + Some(_) | None => self.build_basic_runtime(), + + #[cfg(not(feature = "rt-core"))] + Some(_) | None => self.build_shell_runtime(), } } @@ -365,6 +373,7 @@ impl Builder { } } + #[cfg_attr(feature = "rt-core", allow(dead_code))] fn build_shell_runtime(&mut self) -> io::Result { use crate::runtime::Kind; @@ -463,21 +472,6 @@ cfg_time! { cfg_rt_core! { impl Builder { - /// Sets runtime to use a simpler scheduler that runs all tasks on the current-thread. - /// - /// The executor and all necessary drivers will all be run on the current - /// thread during [`block_on`] calls. - /// - /// See also [the module level documentation][1], which has a section on scheduler - /// types. - /// - /// [1]: index.html#runtime-configurations - /// [`block_on`]: Runtime::block_on - pub fn basic_scheduler(&mut self) -> &mut Self { - self.kind = Kind::Basic; - self - } - fn build_basic_runtime(&mut self) -> io::Result { use crate::runtime::{BasicScheduler, Kind}; @@ -512,17 +506,6 @@ cfg_rt_core! { cfg_rt_threaded! { impl Builder { - /// Sets runtime to use a multi-threaded scheduler for executing tasks. - /// - /// See also [the module level documentation][1], which has a section on scheduler - /// types. - /// - /// [1]: index.html#runtime-configurations - pub fn threaded_scheduler(&mut self) -> &mut Self { - self.kind = Kind::ThreadPool; - self - } - fn build_threaded_runtime(&mut self) -> io::Result { use crate::loom::sys::num_cpus; use crate::runtime::{Kind, ThreadPool}; @@ -572,7 +555,6 @@ impl Default for Builder { impl fmt::Debug for Builder { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Builder") - .field("kind", &self.kind) .field("core_threads", &self.core_threads) .field("max_threads", &self.max_threads) .field( diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index a6a739bec36..44bc97b8f7e 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -115,18 +115,22 @@ //! //! The basic scheduler provides a _single-threaded_ future executor. All tasks //! will be created and executed on the current thread. The basic scheduler -//! requires the `rt-core` feature flag, and can be selected using the -//! [`Builder::basic_scheduler`] method: +//! requires the `rt-core` feature flag, and can be selected by setting +//! [`Builder::core_threads`] to `0` or `1`. //! ``` //! use tokio::runtime; //! //! # fn main() -> Result<(), Box> { //! let basic_rt = runtime::Builder::new() -//! .basic_scheduler() +//! .core_threads(0) //! .build()?; //! # Ok(()) } //! ``` //! +//! Setting `core_threads(0)` will allow you to run the scheduler on the current +//! thread. When setting `core_threads(1)`, the runtime will spawn one background +//! thread that will run the runtime. +//! //! If the `rt-core` feature is enabled and `rt-threaded` is not, //! [`Runtime::new`] will return a basic scheduler runtime by default. //! @@ -136,14 +140,12 @@ //! work-stealing strategy. By default, it will start a worker thread for each //! CPU core available on the system. This tends to be the ideal configurations //! for most applications. The threaded scheduler requires the `rt-threaded` feature -//! flag, and can be selected using the [`Builder::threaded_scheduler`] method: +//! flag, and is selected by default: //! ``` //! use tokio::runtime; //! //! # fn main() -> Result<(), Box> { -//! let threaded_rt = runtime::Builder::new() -//! .threaded_scheduler() -//! .build()?; +//! let threaded_rt = runtime::Runtime::new()?; //! # Ok(()) } //! ``` //! @@ -343,10 +345,10 @@ impl Runtime { /// [runtime builder]: crate::runtime::Builder pub fn new() -> io::Result { #[cfg(feature = "rt-threaded")] - let ret = Builder::new().threaded_scheduler().enable_all().build(); + let ret = Builder::new().enable_all().build(); #[cfg(all(not(feature = "rt-threaded"), feature = "rt-core"))] - let ret = Builder::new().basic_scheduler().enable_all().build(); + let ret = Builder::new().core_threads(0).enable_all().build(); #[cfg(not(feature = "rt-core"))] let ret = Builder::new().enable_all().build(); diff --git a/tokio/src/runtime/tests/loom_blocking.rs b/tokio/src/runtime/tests/loom_blocking.rs index db7048e3f96..b8c3a10813f 100644 --- a/tokio/src/runtime/tests/loom_blocking.rs +++ b/tokio/src/runtime/tests/loom_blocking.rs @@ -24,7 +24,6 @@ fn blocking_shutdown() { fn mk_runtime(num_threads: usize) -> Runtime { runtime::Builder::new() - .threaded_scheduler() .core_threads(num_threads) .build() .unwrap() diff --git a/tokio/src/runtime/tests/loom_pool.rs b/tokio/src/runtime/tests/loom_pool.rs index 47ee1981086..55b61cd8ed8 100644 --- a/tokio/src/runtime/tests/loom_pool.rs +++ b/tokio/src/runtime/tests/loom_pool.rs @@ -297,7 +297,6 @@ mod group_d { fn mk_pool(num_threads: usize) -> Runtime { runtime::Builder::new() - .threaded_scheduler() .core_threads(num_threads) .build() .unwrap() diff --git a/tokio/src/signal/registry.rs b/tokio/src/signal/registry.rs index 9e55a5e60e0..94fd6955c20 100644 --- a/tokio/src/signal/registry.rs +++ b/tokio/src/signal/registry.rs @@ -306,7 +306,7 @@ mod tests { } fn rt() -> Runtime { - runtime::Builder::new().basic_scheduler().build().unwrap() + runtime::Builder::new().core_threads(0).build().unwrap() } async fn collect(mut rx: crate::sync::mpsc::Receiver<()>) -> Vec<()> { diff --git a/tokio/src/signal/windows.rs b/tokio/src/signal/windows.rs index f638eed8a75..51a07ba0475 100644 --- a/tokio/src/signal/windows.rs +++ b/tokio/src/signal/windows.rs @@ -290,7 +290,7 @@ mod tests { fn rt() -> Runtime { crate::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap() } diff --git a/tokio/tests/io_driver.rs b/tokio/tests/io_driver.rs index d4f4f8d48cf..e630d0e6d0c 100644 --- a/tokio/tests/io_driver.rs +++ b/tokio/tests/io_driver.rs @@ -46,7 +46,7 @@ fn test_drop_on_notify() { // dropped. let rt = runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap(); diff --git a/tokio/tests/io_driver_drop.rs b/tokio/tests/io_driver_drop.rs index 0a5ce62513b..8a6f5f8cd62 100644 --- a/tokio/tests/io_driver_drop.rs +++ b/tokio/tests/io_driver_drop.rs @@ -46,7 +46,7 @@ fn drop_wakes() { fn rt() -> runtime::Runtime { runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap() diff --git a/tokio/tests/rt_basic.rs b/tokio/tests/rt_basic.rs index 3813c48006c..e7364b96f51 100644 --- a/tokio/tests/rt_basic.rs +++ b/tokio/tests/rt_basic.rs @@ -130,7 +130,7 @@ fn acquire_mutex_in_drop() { fn rt() -> Runtime { tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap() diff --git a/tokio/tests/rt_common.rs b/tokio/tests/rt_common.rs index 7f0491c4872..7032e381cdc 100644 --- a/tokio/tests/rt_common.rs +++ b/tokio/tests/rt_common.rs @@ -11,7 +11,7 @@ macro_rules! rt_test { fn rt() -> Arc { tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap() @@ -24,7 +24,6 @@ macro_rules! rt_test { fn rt() -> Arc { tokio::runtime::Builder::new() - .threaded_scheduler() .core_threads(4) .enable_all() .build() @@ -38,7 +37,6 @@ macro_rules! rt_test { fn rt() -> Arc { tokio::runtime::Builder::new() - .threaded_scheduler() .core_threads(1) .enable_all() .build() diff --git a/tokio/tests/rt_threaded.rs b/tokio/tests/rt_threaded.rs index a67c090ebf4..3d5b7529f84 100644 --- a/tokio/tests/rt_threaded.rs +++ b/tokio/tests/rt_threaded.rs @@ -18,11 +18,7 @@ use std::task::{Context, Poll}; #[test] fn single_thread() { // No panic when starting a runtime w/ a single thread - let _ = runtime::Builder::new() - .threaded_scheduler() - .enable_all() - .core_threads(1) - .build(); + let _ = runtime::Builder::new().enable_all().core_threads(1).build(); } #[test] @@ -189,7 +185,6 @@ fn drop_threadpool_drops_futures() { let b = num_dec.clone(); let rt = runtime::Builder::new() - .threaded_scheduler() .enable_all() .on_thread_start(move || { a.fetch_add(1, Relaxed); @@ -229,7 +224,6 @@ fn start_stop_callbacks_called() { let after_inner = after_start.clone(); let before_inner = before_stop.clone(); let rt = tokio::runtime::Builder::new() - .threaded_scheduler() .enable_all() .on_thread_start(move || { after_inner.clone().fetch_add(1, Ordering::Relaxed); @@ -330,7 +324,6 @@ fn multi_threadpool() { #[test] fn coop_and_block_in_place() { let rt = tokio::runtime::Builder::new() - .threaded_scheduler() // Setting max threads to 1 prevents another thread from claiming the // runtime worker yielded as part of `block_in_place` and guarantees the // same thread will reclaim the worker at the end of the @@ -381,7 +374,6 @@ fn coop_and_block_in_place() { #[test] fn max_threads() { let _rt = tokio::runtime::Builder::new() - .threaded_scheduler() .max_threads(1) .build() .unwrap(); diff --git a/tokio/tests/signal_ctrl_c.rs b/tokio/tests/signal_ctrl_c.rs index 4b057ee7e14..37c03da8391 100644 --- a/tokio/tests/signal_ctrl_c.rs +++ b/tokio/tests/signal_ctrl_c.rs @@ -11,20 +11,46 @@ use tokio::signal; use tokio::sync::oneshot; use tokio_test::assert_ok; -#[tokio::test] -async fn ctrl_c() { - let ctrl_c = signal::ctrl_c(); +// #[tokio::test] +// async fn ctrl_c() { +// let ctrl_c = signal::ctrl_c(); - let (fire, wait) = oneshot::channel(); +// let (fire, wait) = oneshot::channel(); - // NB: simulate a signal coming in by exercising our signal handler - // to avoid complications with sending SIGINT to the test process - tokio::spawn(async { - wait.await.expect("wait failed"); - send_signal(libc::SIGINT); - }); +// // NB: simulate a signal coming in by exercising our signal handler +// // to avoid complications with sending SIGINT to the test process +// tokio::spawn(async { +// wait.await.expect("wait failed"); +// send_signal(libc::SIGINT); +// }); + +// let _ = fire.send(()); + +// assert_ok!(ctrl_c.await); +// } + +#[test] +fn ctrl_c() { + let rt = tokio::runtime::Builder::new() + .core_threads(0) + .enable_all() + .build() + .unwrap(); - let _ = fire.send(()); + rt.block_on(async move { + let ctrl_c = signal::ctrl_c(); - assert_ok!(ctrl_c.await); + let (fire, wait) = oneshot::channel(); + + // NB: simulate a signal coming in by exercising our signal handler + // to avoid complications with sending SIGINT to the test process + tokio::spawn(async { + wait.await.expect("wait failed"); + send_signal(libc::SIGINT); + }); + + let _ = fire.send(()); + + assert_ok!(ctrl_c.await); + }); } diff --git a/tokio/tests/signal_drop_rt.rs b/tokio/tests/signal_drop_rt.rs index 709e0d41834..1bf6dd6a0b9 100644 --- a/tokio/tests/signal_drop_rt.rs +++ b/tokio/tests/signal_drop_rt.rs @@ -38,7 +38,7 @@ fn dropping_loops_does_not_cause_starvation() { fn rt() -> Runtime { tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap() diff --git a/tokio/tests/signal_multi_rt.rs b/tokio/tests/signal_multi_rt.rs index 78319a75331..051c8b0da51 100644 --- a/tokio/tests/signal_multi_rt.rs +++ b/tokio/tests/signal_multi_rt.rs @@ -48,7 +48,7 @@ fn multi_loop() { fn rt() -> Runtime { tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap() diff --git a/tokio/tests/task_blocking.rs b/tokio/tests/task_blocking.rs index 6cb11584b4a..be1e2ce7095 100644 --- a/tokio/tests/task_blocking.rs +++ b/tokio/tests/task_blocking.rs @@ -79,10 +79,7 @@ async fn no_block_in_basic_scheduler() { #[test] fn yes_block_in_threaded_block_on() { - let rt = runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let rt = runtime::Runtime::new().unwrap(); rt.block_on(async { task::block_in_place(|| {}); }); @@ -91,7 +88,7 @@ fn yes_block_in_threaded_block_on() { #[test] #[should_panic] fn no_block_in_basic_block_on() { - let rt = runtime::Builder::new().basic_scheduler().build().unwrap(); + let rt = runtime::Builder::new().core_threads(0).build().unwrap(); rt.block_on(async { task::block_in_place(|| {}); }); @@ -99,15 +96,12 @@ fn no_block_in_basic_block_on() { #[test] fn can_enter_basic_rt_from_within_block_in_place() { - let outer = tokio::runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); outer.block_on(async { tokio::task::block_in_place(|| { let inner = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); @@ -120,15 +114,12 @@ fn can_enter_basic_rt_from_within_block_in_place() { fn useful_panic_message_when_dropping_rt_in_rt() { use std::panic::{catch_unwind, AssertUnwindSafe}; - let outer = tokio::runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); let result = catch_unwind(AssertUnwindSafe(|| { outer.block_on(async { let _ = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); }); @@ -147,14 +138,11 @@ fn useful_panic_message_when_dropping_rt_in_rt() { #[test] fn can_shutdown_with_zero_timeout_in_runtime() { - let outer = tokio::runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); outer.block_on(async { let rt = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); rt.shutdown_timeout(Duration::from_nanos(0)); @@ -163,14 +151,11 @@ fn can_shutdown_with_zero_timeout_in_runtime() { #[test] fn can_shutdown_now_in_runtime() { - let outer = tokio::runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); outer.block_on(async { let rt = tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .build() .unwrap(); rt.shutdown_background(); @@ -180,7 +165,6 @@ fn can_shutdown_now_in_runtime() { #[test] fn coop_disabled_in_block_in_place() { let outer = tokio::runtime::Builder::new() - .threaded_scheduler() .enable_time() .build() .unwrap(); @@ -213,10 +197,7 @@ fn coop_disabled_in_block_in_place_in_block_on() { let (done_tx, done_rx) = std::sync::mpsc::channel(); let done = done_tx.clone(); thread::spawn(move || { - let outer = tokio::runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); for i in 0..200 { diff --git a/tokio/tests/task_local_set.rs b/tokio/tests/task_local_set.rs index 23e92586b78..443ca0f585f 100644 --- a/tokio/tests/task_local_set.rs +++ b/tokio/tests/task_local_set.rs @@ -133,11 +133,7 @@ fn local_threadpool_blocking_in_place() { ON_RT_THREAD.with(|cell| cell.set(true)); - let rt = runtime::Builder::new() - .threaded_scheduler() - .enable_all() - .build() - .unwrap(); + let rt = runtime::Builder::new().enable_all().build().unwrap(); LocalSet::new().block_on(&rt, async { assert!(ON_RT_THREAD.with(|cell| cell.get())); let join = task::spawn_local(async move { @@ -246,10 +242,7 @@ fn join_local_future_elsewhere() { ON_RT_THREAD.with(|cell| cell.set(true)); - let rt = runtime::Builder::new() - .threaded_scheduler() - .build() - .unwrap(); + let rt = runtime::Runtime::new().unwrap(); let local = LocalSet::new(); local.block_on(&rt, async move { let (tx, rx) = oneshot::channel(); @@ -492,7 +485,7 @@ async fn acquire_mutex_in_drop() { fn rt() -> Runtime { tokio::runtime::Builder::new() - .basic_scheduler() + .core_threads(0) .enable_all() .build() .unwrap() diff --git a/tokio/tests/time_rt.rs b/tokio/tests/time_rt.rs index 19bcd27d9b5..dfae7117cae 100644 --- a/tokio/tests/time_rt.rs +++ b/tokio/tests/time_rt.rs @@ -28,11 +28,7 @@ fn timer_with_threaded_runtime() { fn timer_with_basic_scheduler() { use tokio::runtime::Builder; - let rt = Builder::new() - .basic_scheduler() - .enable_all() - .build() - .unwrap(); + let rt = Builder::new().core_threads(0).enable_all().build().unwrap(); let (tx, rx) = mpsc::channel(); rt.block_on(async move { From 692b418b313df581984114a94bacc15fd9aee777 Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Fri, 25 Sep 2020 14:28:16 +0000 Subject: [PATCH 02/39] Fix docs --- tokio/src/runtime/mod.rs | 10 ++------ tokio/src/task/blocking.rs | 6 ++--- tokio/tests/signal_ctrl_c.rs | 50 +++++++++--------------------------- 3 files changed, 16 insertions(+), 50 deletions(-) diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 44bc97b8f7e..9e9496b1130 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -384,14 +384,8 @@ impl Runtime { /// /// # Panics /// - /// This function will not panic unless task execution is disabled on the - /// executor. This can only happen if the runtime was built using - /// [`Builder`] without picking either [`basic_scheduler`] or - /// [`threaded_scheduler`]. - /// - /// [`Builder`]: struct@Builder - /// [`threaded_scheduler`]: fn@Builder::threaded_scheduler - /// [`basic_scheduler`]: fn@Builder::basic_scheduler + /// This function will panic if `rt-core` or `rt-threaded` features + /// are not enabled. #[cfg(feature = "rt-core")] pub fn spawn(&self, future: F) -> JoinHandle where diff --git a/tokio/src/task/blocking.rs b/tokio/src/task/blocking.rs index ed60f4c4734..362c1c01dcb 100644 --- a/tokio/src/task/blocking.rs +++ b/tokio/src/task/blocking.rs @@ -17,7 +17,7 @@ cfg_rt_threaded! { /// using the [`join!`] macro. To avoid this issue, use [`spawn_blocking`] /// instead. /// - /// Note that this function can only be used on the [threaded scheduler]. + /// Note that this function can only be used when `core_threads > 1`. /// /// Code running behind `block_in_place` cannot be cancelled. When you shut /// down the executor, it will wait indefinitely for all blocking operations @@ -27,7 +27,6 @@ cfg_rt_threaded! { /// returns. /// /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code - /// [threaded scheduler]: fn@crate::runtime::Builder::threaded_scheduler /// [`spawn_blocking`]: fn@crate::task::spawn_blocking /// [`join!`]: macro@join /// [`thread::spawn`]: fn@std::thread::spawn @@ -83,14 +82,13 @@ cfg_blocking! { /// cancel the tasks — they are simply allowed to keep running after the /// method returns. /// - /// Note that if you are using the [basic scheduler], this function will + /// Note that if you are using the single threaded runtime, this function will /// still spawn additional threads for blocking operations. The basic /// scheduler's single thread is only used for asynchronous code. /// /// [`Builder`]: struct@crate::runtime::Builder /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code /// [rayon]: https://docs.rs/rayon - /// [basic scheduler]: fn@crate::runtime::Builder::basic_scheduler /// [`thread::spawn`]: fn@std::thread::spawn /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout /// diff --git a/tokio/tests/signal_ctrl_c.rs b/tokio/tests/signal_ctrl_c.rs index 37c03da8391..4b057ee7e14 100644 --- a/tokio/tests/signal_ctrl_c.rs +++ b/tokio/tests/signal_ctrl_c.rs @@ -11,46 +11,20 @@ use tokio::signal; use tokio::sync::oneshot; use tokio_test::assert_ok; -// #[tokio::test] -// async fn ctrl_c() { -// let ctrl_c = signal::ctrl_c(); +#[tokio::test] +async fn ctrl_c() { + let ctrl_c = signal::ctrl_c(); -// let (fire, wait) = oneshot::channel(); + let (fire, wait) = oneshot::channel(); -// // NB: simulate a signal coming in by exercising our signal handler -// // to avoid complications with sending SIGINT to the test process -// tokio::spawn(async { -// wait.await.expect("wait failed"); -// send_signal(libc::SIGINT); -// }); - -// let _ = fire.send(()); - -// assert_ok!(ctrl_c.await); -// } - -#[test] -fn ctrl_c() { - let rt = tokio::runtime::Builder::new() - .core_threads(0) - .enable_all() - .build() - .unwrap(); - - rt.block_on(async move { - let ctrl_c = signal::ctrl_c(); - - let (fire, wait) = oneshot::channel(); - - // NB: simulate a signal coming in by exercising our signal handler - // to avoid complications with sending SIGINT to the test process - tokio::spawn(async { - wait.await.expect("wait failed"); - send_signal(libc::SIGINT); - }); + // NB: simulate a signal coming in by exercising our signal handler + // to avoid complications with sending SIGINT to the test process + tokio::spawn(async { + wait.await.expect("wait failed"); + send_signal(libc::SIGINT); + }); - let _ = fire.send(()); + let _ = fire.send(()); - assert_ok!(ctrl_c.await); - }); + assert_ok!(ctrl_c.await); } From 1db81a9d9c00847f162a533978cd0b4c8f9e1254 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Sat, 3 Oct 2020 20:26:12 +0200 Subject: [PATCH 03/39] Rewrite tokio-macros to new argument format --- tokio-macros/src/entry.rs | 447 ++++++++++++++++++-------------------- tokio-macros/src/lib.rs | 149 +++---------- tokio/src/lib.rs | 14 +- 3 files changed, 245 insertions(+), 365 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 2681f50d9c0..b0be79b7e99 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -1,11 +1,171 @@ use proc_macro::TokenStream; +use proc_macro2::Span; use quote::quote; -use std::num::NonZeroUsize; +use syn::spanned::Spanned; #[derive(Clone, Copy, PartialEq)] -enum Runtime { - Basic, - Threaded, +enum RuntimeFlavor { + InPlace, + WorkStealing, +} + +impl RuntimeFlavor { + fn from_str(s: &str) -> Result { + match s { + "in_place" => Ok(RuntimeFlavor::InPlace), + "work_stealing" => Ok(RuntimeFlavor::WorkStealing), + "single_threaded" => Err(format!("The single threaded runtime flavor is called `in_place`.")), + "basic_scheduler" => Err(format!("The `basic_scheduler` runtime flavor has been renamed to `in_place`.")), + "threaded_scheduler" => Err(format!("The `threaded_scheduler` runtime flavor has been renamed to `work_stealing`.")), + _ => Err(format!("No such runtime flavor `{}`.", s)), + } + } +} + +struct FinalConfig { + flavor: RuntimeFlavor, + num_workers: Option, + max_threads: Option, +} + +struct Configuration { + rt_threaded_available: bool, + default_flavor: RuntimeFlavor, + flavor: Option, + num_workers: Option<(usize, Span)>, + max_threads: Option<(usize, Span)>, +} +impl Configuration { + fn new(is_test: bool, rt_threaded: bool) -> Self { + Configuration { + rt_threaded_available: rt_threaded, + default_flavor: match is_test { + true => RuntimeFlavor::InPlace, + false => RuntimeFlavor::WorkStealing, + }, + flavor: None, + num_workers: None, + max_threads: None, + } + } + fn set_flavor( + &mut self, + runtime: syn::Lit, + span: Span, + ) -> Result<(), syn::Error> { + if self.flavor.is_some() { + return Err(syn::Error::new(span, "`flavor` set multiple times.")); + } + + let runtime_str = parse_string(runtime, span, "flavor")?; + let runtime = RuntimeFlavor::from_str(&runtime_str) + .map_err(|err| syn::Error::new(span, err))?; + self.flavor = Some(runtime); + Ok(()) + } + fn set_num_workers( + &mut self, + num_workers: syn::Lit, + span: Span, + ) -> Result<(), syn::Error> { + if self.num_workers.is_some() { + return Err(syn::Error::new(span, "`num_workers` set multiple times.")); + } + + let num_workers = parse_int(num_workers, span, "num_workers")?; + if num_workers == 0 { + return Err(syn::Error::new(span, "`num_workers` may not be 0.")); + } + self.num_workers = Some((num_workers, span)); + Ok(()) + } + fn set_max_threads( + &mut self, + max_threads: syn::Lit, + span: Span, + ) -> Result<(), syn::Error> { + if self.max_threads.is_some() { + return Err(syn::Error::new(span, "`max_threads` set multiple times.")); + } + + let max_threads = parse_int(max_threads, span, "max_threads")?; + if max_threads == 0 { + return Err(syn::Error::new(span, "`max_threads` may not be 0.")); + } + self.max_threads = Some((max_threads, span)); + Ok(()) + } + fn build(&self) -> Result { + let flavor = self.flavor.unwrap_or(self.default_flavor); + match flavor { + RuntimeFlavor::InPlace => { + if let Some((_, num_workers_span)) = &self.num_workers { + return Err(syn::Error::new( + num_workers_span.clone(), + "The `num_workers` option requires the `work_stealing` runtime flavor." + )); + } + assert!(self.num_workers.is_none()); + Ok(FinalConfig { + flavor, + num_workers: None, + max_threads: self.max_threads.map(|(val, _span)| val), + }) + }, + RuntimeFlavor::WorkStealing => { + if !self.rt_threaded_available { + let msg = if self.flavor.is_none() { + "The default runtime flavor is `work_stealing`, but the `rt-threaded` feature is disabled." + } else { + "The runtime flavor `work_stealing` requires the `rt-threaded` feature." + }; + return Err(syn::Error::new(Span::call_site(), msg)); + } + match (self.num_workers, self.max_threads) { + (None, Some((_, span))) => { + return Err(syn::Error::new( + span, + "`num_workers` must also be set when using `max_threads`" + )); + }, + (Some((num_workers, _)), Some((max_threads, span))) if max_threads <= num_workers => { + return Err(syn::Error::new( + span, + "`max_threads` must be larger than `num_workers`", + )); + }, + _ => {}, + } + Ok(FinalConfig { + flavor, + num_workers: self.num_workers.map(|(val, _span)| val), + max_threads: self.max_threads.map(|(val, _span)| val), + }) + }, + } + } +} + +fn parse_int(int: syn::Lit, span: Span, field: &str) -> Result { + match int { + syn::Lit::Int(lit) => { + match lit.base10_parse::() { + Ok(value) => Ok(value), + Err(e) => Err(syn::Error::new( + span, + format!("Failed to parse {} as integer: {}", field, e), + )), + } + }, + _ => Err(syn::Error::new(span, format!("Failed to parse {} as integer.", field))), + } +} +fn parse_string(int: syn::Lit, span: Span, field: &str) -> Result { + match int { + syn::Lit::Str(s) => Ok(s.value()), + syn::Lit::Verbatim(s) => Ok(s.to_string()), + _ => Err(syn::Error::new(span, format!("Failed to parse {} as string.", field))), + } } fn parse_knobs( @@ -26,9 +186,8 @@ fn parse_knobs( sig.asyncness = None; - let mut runtime = None; - let mut core_threads = None; - let mut max_threads = None; + let macro_name = if is_test { "tokio::test" } else { "tokio::main" }; + let mut config = Configuration::new(is_test, rt_threaded); for arg in args { match arg { @@ -39,65 +198,21 @@ fn parse_knobs( return Err(syn::Error::new_spanned(namevalue, msg)); } match ident.unwrap().to_string().to_lowercase().as_str() { - "core_threads" => { - if rt_threaded { - match &namevalue.lit { - syn::Lit::Int(expr) => { - let num = expr.base10_parse::().unwrap(); - if num.get() > 1 { - runtime = Some(Runtime::Threaded); - } else { - runtime = Some(Runtime::Basic); - } - - if let Some(v) = max_threads { - if v < num { - return Err(syn::Error::new_spanned( - namevalue, - "max_threads cannot be less than core_threads", - )); - } - } - - core_threads = Some(num); - } - _ => { - return Err(syn::Error::new_spanned( - namevalue, - "core_threads argument must be an int", - )) - } - } - } else { - return Err(syn::Error::new_spanned( - namevalue, - "core_threads can only be set with rt-threaded feature flag enabled", - )); - } + "num_workers" => { + config.set_num_workers(namevalue.lit.clone(), namevalue.span())?; } - "max_threads" => match &namevalue.lit { - syn::Lit::Int(expr) => { - let num = expr.base10_parse::().unwrap(); - - if let Some(v) = core_threads { - if num < v { - return Err(syn::Error::new_spanned( - namevalue, - "max_threads cannot be less than core_threads", - )); - } - } - max_threads = Some(num); - } - _ => { - return Err(syn::Error::new_spanned( - namevalue, - "max_threads argument must be an int", - )) - } + "max_threads" => { + config.set_max_threads(namevalue.lit.clone(), namevalue.span())?; + }, + "flavor" => { + config.set_flavor(namevalue.lit.clone(), namevalue.span())?; }, + "core_threads" => { + let msg = "Attribute `core_threads` is renamed to `num_workers`"; + return Err(syn::Error::new_spanned(namevalue, msg)); + } name => { - let msg = format!("Unknown attribute pair {} is specified; expected one of: `core_threads`, `max_threads`", name); + let msg = format!("Unknown attribute {} is specified; expected one of: `flavor`, `num_workers`, `max_threads`", name); return Err(syn::Error::new_spanned(namevalue, msg)); } } @@ -108,16 +223,22 @@ fn parse_knobs( let msg = "Must have specified ident"; return Err(syn::Error::new_spanned(path, msg)); } - match ident.unwrap().to_string().to_lowercase().as_str() { - "threaded_scheduler" => { - runtime = Some(runtime.unwrap_or_else(|| Runtime::Threaded)) - } - "basic_scheduler" => runtime = Some(runtime.unwrap_or_else(|| Runtime::Basic)), + let name = ident.unwrap().to_string().to_lowercase(); + let msg = match name.as_str() { + "threaded_scheduler" | "work_stealing" => { + format!("Set the runtime flavor with #[{}(flavor = \"work_stealing\")].", macro_name) + }, + "basic_scheduler" | "in_place" => { + format!("Set the runtime flavor with #[{}(flavor = \"in_place\")].", macro_name) + }, + "flavor" | "num_workers" | "max_threads" => { + format!("The `{}` attribute requires an argument.", name) + }, name => { - let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name); - return Err(syn::Error::new_spanned(path, msg)); - } - } + format!("Unkown attribute {} is specified; expected one of: `flavor`, `num_workers`, `max_threads`", name) + }, + }; + return Err(syn::Error::new_spanned(path, msg)); } other => { return Err(syn::Error::new_spanned( @@ -128,14 +249,20 @@ fn parse_knobs( } } - let mut rt = quote! { tokio::runtime::Builder::new().basic_scheduler() }; - if rt_threaded && (runtime == Some(Runtime::Threaded) || (runtime.is_none() && !is_test)) { - rt = quote! { #rt.threaded_scheduler() }; - } - if let Some(v) = core_threads.map(|v| v.get()) { + let config = config.build()?; + + let mut rt = match config.flavor { + RuntimeFlavor::InPlace => quote! { + tokio::runtime::Builder::new().basic_scheduler() + }, + RuntimeFlavor::WorkStealing => quote! { + tokio::runtime::Builder::new().threaded_scheduler() + }, + }; + if let Some(v) = config.num_workers { rt = quote! { #rt.core_threads(#v) }; } - if let Some(v) = max_threads.map(|v| v.get()) { + if let Some(v) = config.max_threads { rt = quote! { #rt.max_threads(#v) }; } @@ -171,12 +298,13 @@ pub(crate) fn main(args: TokenStream, item: TokenStream, rt_threaded: bool) -> T if input.sig.ident == "main" && !input.sig.inputs.is_empty() { let msg = "the main function cannot accept arguments"; - return syn::Error::new_spanned(&input.sig.inputs, msg) + return syn::Error::new_spanned(&input.sig.ident, msg) .to_compile_error() .into(); } - parse_knobs(input, args, false, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into()) + parse_knobs(input, args, false, rt_threaded) + .unwrap_or_else(|e| e.to_compile_error().into()) } pub(crate) fn test(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream { @@ -199,161 +327,6 @@ pub(crate) fn test(args: TokenStream, item: TokenStream, rt_threaded: bool) -> T .into(); } - parse_knobs(input, args, true, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into()) -} - -pub(crate) mod old { - use proc_macro::TokenStream; - use quote::quote; - - enum Runtime { - Basic, - Threaded, - Auto, - } - - #[cfg(not(test))] // Work around for rust-lang/rust#62127 - pub(crate) fn main(args: TokenStream, item: TokenStream) -> TokenStream { - let mut input = syn::parse_macro_input!(item as syn::ItemFn); - let args = syn::parse_macro_input!(args as syn::AttributeArgs); - - let sig = &mut input.sig; - let name = &sig.ident; - let inputs = &sig.inputs; - let body = &input.block; - let attrs = &input.attrs; - let vis = input.vis; - - if sig.asyncness.is_none() { - let msg = "the async keyword is missing from the function declaration"; - return syn::Error::new_spanned(sig.fn_token, msg) - .to_compile_error() - .into(); - } else if name == "main" && !inputs.is_empty() { - let msg = "the main function cannot accept arguments"; - return syn::Error::new_spanned(&sig.inputs, msg) - .to_compile_error() - .into(); - } - - sig.asyncness = None; - - let mut runtime = Runtime::Auto; - - for arg in args { - if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg { - let ident = path.get_ident(); - if ident.is_none() { - let msg = "Must have specified ident"; - return syn::Error::new_spanned(path, msg).to_compile_error().into(); - } - match ident.unwrap().to_string().to_lowercase().as_str() { - "threaded_scheduler" => runtime = Runtime::Threaded, - "basic_scheduler" => runtime = Runtime::Basic, - name => { - let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name); - return syn::Error::new_spanned(path, msg).to_compile_error().into(); - } - } - } - } - - let result = match runtime { - Runtime::Threaded | Runtime::Auto => quote! { - #(#attrs)* - #vis #sig { - tokio::runtime::Runtime::new().unwrap().block_on(async { #body }) - } - }, - Runtime::Basic => quote! { - #(#attrs)* - #vis #sig { - tokio::runtime::Builder::new() - .basic_scheduler() - .enable_all() - .build() - .unwrap() - .block_on(async { #body }) - } - }, - }; - - result.into() - } - - pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream { - let input = syn::parse_macro_input!(item as syn::ItemFn); - let args = syn::parse_macro_input!(args as syn::AttributeArgs); - - let ret = &input.sig.output; - let name = &input.sig.ident; - let body = &input.block; - let attrs = &input.attrs; - let vis = input.vis; - - for attr in attrs { - if attr.path.is_ident("test") { - let msg = "second test attribute is supplied"; - return syn::Error::new_spanned(&attr, msg) - .to_compile_error() - .into(); - } - } - - if input.sig.asyncness.is_none() { - let msg = "the async keyword is missing from the function declaration"; - return syn::Error::new_spanned(&input.sig.fn_token, msg) - .to_compile_error() - .into(); - } else if !input.sig.inputs.is_empty() { - let msg = "the test function cannot accept arguments"; - return syn::Error::new_spanned(&input.sig.inputs, msg) - .to_compile_error() - .into(); - } - - let mut runtime = Runtime::Auto; - - for arg in args { - if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg { - let ident = path.get_ident(); - if ident.is_none() { - let msg = "Must have specified ident"; - return syn::Error::new_spanned(path, msg).to_compile_error().into(); - } - match ident.unwrap().to_string().to_lowercase().as_str() { - "threaded_scheduler" => runtime = Runtime::Threaded, - "basic_scheduler" => runtime = Runtime::Basic, - name => { - let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name); - return syn::Error::new_spanned(path, msg).to_compile_error().into(); - } - } - } - } - - let result = match runtime { - Runtime::Threaded => quote! { - #[::core::prelude::v1::test] - #(#attrs)* - #vis fn #name() #ret { - tokio::runtime::Runtime::new().unwrap().block_on(async { #body }) - } - }, - Runtime::Basic | Runtime::Auto => quote! { - #[::core::prelude::v1::test] - #(#attrs)* - #vis fn #name() #ret { - tokio::runtime::Builder::new() - .basic_scheduler() - .enable_all() - .build() - .unwrap() - .block_on(async { #body }) - } - }, - }; - - result.into() - } + parse_knobs(input, args, true, rt_threaded) + .unwrap_or_else(|e| e.to_compile_error().into()) } diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 09733ba5d4c..20150bb1f74 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -29,7 +29,7 @@ use proc_macro::TokenStream; /// [Builder](../tokio/runtime/struct.Builder.html) directly. /// /// Note: This macro is designed to be simplistic and targets applications that do not require -/// a complex setup. If provided functionality is not sufficient, user may be interested in +/// a complex setup. If the provided functionality is not sufficient, you may be interested in /// using [Builder](../tokio/runtime/struct.Builder.html), which provides a more powerful /// interface. /// @@ -101,7 +101,7 @@ use proc_macro::TokenStream; /// ### Set number of core threads /// /// ```rust -/// #[tokio::main(core_threads = 2)] +/// #[tokio::main(num_workers = 2)] /// async fn main() { /// println!("Hello world"); /// } @@ -132,86 +132,8 @@ use proc_macro::TokenStream; /// macro is expanded. #[proc_macro_attribute] #[cfg(not(test))] // Work around for rust-lang/rust#62127 -pub fn main_threaded(args: TokenStream, item: TokenStream) -> TokenStream { - entry::main(args, item, true) -} - -/// Marks async function to be executed by selected runtime. This macro helps set up a `Runtime` -/// without requiring the user to use [Runtime](../tokio/runtime/struct.Runtime.html) or -/// [Builder](../tokio/runtime/struct.Builder.html) directly. -/// -/// Note: This macro is designed to be simplistic and targets applications that do not require -/// a complex setup. If provided functionality is not sufficient, user may be interested in -/// using [Builder](../tokio/runtime/struct.Builder.html), which provides a more powerful -/// interface. -/// -/// ## Options: -/// -/// - `basic_scheduler` - All tasks are executed on the current thread. -/// - `threaded_scheduler` - Uses the multi-threaded scheduler. Used by default (requires `rt-threaded` feature). -/// -/// ## Function arguments: -/// -/// Arguments are allowed for any functions aside from `main` which is special -/// -/// ## Usage -/// -/// ### Using default -/// -/// ```rust -/// #[tokio::main] -/// async fn main() { -/// println!("Hello world"); -/// } -/// ``` -/// -/// Equivalent code not using `#[tokio::main]` -/// -/// ```rust -/// fn main() { -/// tokio::runtime::Runtime::new() -/// .unwrap() -/// .block_on(async { -/// println!("Hello world"); -/// }) -/// } -/// ``` -/// -/// ### Select runtime -/// -/// ```rust -/// #[tokio::main(basic_scheduler)] -/// async fn main() { -/// println!("Hello world"); -/// } -/// ``` -/// -/// Equivalent code not using `#[tokio::main]` -/// -/// ```rust -/// fn main() { -/// tokio::runtime::Builder::new() -/// .basic_scheduler() -/// .enable_all() -/// .build() -/// .unwrap() -/// .block_on(async { -/// println!("Hello world"); -/// }) -/// } -/// ``` -/// -/// ### NOTE: -/// -/// If you rename the tokio crate in your dependencies this macro -/// will not work. If you must rename the 0.2 version of tokio because -/// you're also using the 0.1 version of tokio, you _must_ make the -/// tokio 0.2 crate available as `tokio` in the module where this -/// macro is expanded. -#[proc_macro_attribute] -#[cfg(not(test))] // Work around for rust-lang/rust#62127 pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { - entry::old::main(args, item) + entry::main(args, item, true) } /// Marks async function to be executed by selected runtime. This macro helps set up a `Runtime` @@ -261,7 +183,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { /// macro is expanded. #[proc_macro_attribute] #[cfg(not(test))] // Work around for rust-lang/rust#62127 -pub fn main_basic(args: TokenStream, item: TokenStream) -> TokenStream { +pub fn main_rt_core(args: TokenStream, item: TokenStream) -> TokenStream { entry::main(args, item, false) } @@ -300,7 +222,7 @@ pub fn main_basic(args: TokenStream, item: TokenStream) -> TokenStream { /// tokio 0.2 crate available as `tokio` in the module where this /// macro is expanded. #[proc_macro_attribute] -pub fn test_threaded(args: TokenStream, item: TokenStream) -> TokenStream { +pub fn test(args: TokenStream, item: TokenStream) -> TokenStream { entry::test(args, item, true) } @@ -308,22 +230,10 @@ pub fn test_threaded(args: TokenStream, item: TokenStream) -> TokenStream { /// /// ## Options: /// -/// - `basic_scheduler` - All tasks are executed on the current thread. Used by default. -/// - `threaded_scheduler` - Use multi-threaded scheduler (requires `rt-threaded` feature). +/// - `max_threads=n` - Sets max threads to `n`. /// /// ## Usage /// -/// ### Select runtime -/// -/// ```no_run -/// #[tokio::test(threaded_scheduler)] -/// async fn my_test() { -/// assert!(true); -/// } -/// ``` -/// -/// ### Using default -/// /// ```no_run /// #[tokio::test] /// async fn my_test() { @@ -339,35 +249,32 @@ pub fn test_threaded(args: TokenStream, item: TokenStream) -> TokenStream { /// tokio 0.2 crate available as `tokio` in the module where this /// macro is expanded. #[proc_macro_attribute] -pub fn test(args: TokenStream, item: TokenStream) -> TokenStream { - entry::old::test(args, item) +pub fn test_rt_core(args: TokenStream, item: TokenStream) -> TokenStream { + entry::test(args, item, false) } -/// Marks async function to be executed by runtime, suitable to test environment -/// -/// ## Options: -/// -/// - `max_threads=n` - Sets max threads to `n`. -/// -/// ## Usage -/// -/// ```no_run -/// #[tokio::test] -/// async fn my_test() { -/// assert!(true); -/// } +/// Always fails with the error message below. +/// ```text +/// The #[tokio::main] macro requires rt-core or rt-threaded. /// ``` -/// -/// ### NOTE: -/// -/// If you rename the tokio crate in your dependencies this macro -/// will not work. If you must rename the 0.2 version of tokio because -/// you're also using the 0.1 version of tokio, you _must_ make the -/// tokio 0.2 crate available as `tokio` in the module where this -/// macro is expanded. #[proc_macro_attribute] -pub fn test_basic(args: TokenStream, item: TokenStream) -> TokenStream { - entry::test(args, item, false) +pub fn main_fail(_args: TokenStream, _item: TokenStream) -> TokenStream { + syn::Error::new( + proc_macro2::Span::call_site(), + "The #[tokio::main] macro requires rt-core or rt-threaded.", + ).to_compile_error().into() +} + +/// Always fails with the error message below. +/// ```text +/// The #[tokio::test] macro requires rt-core or rt-threaded. +/// ``` +#[proc_macro_attribute] +pub fn test_fail(_args: TokenStream, _item: TokenStream) -> TokenStream { + syn::Error::new( + proc_macro2::Span::call_site(), + "The #[tokio::test] macro requires rt-core or rt-threaded.", + ).to_compile_error().into() } /// Implementation detail of the `select!` macro. This macro is **not** intended diff --git a/tokio/src/lib.rs b/tokio/src/lib.rs index 1b0dad5d667..e511e87cbf1 100644 --- a/tokio/src/lib.rs +++ b/tokio/src/lib.rs @@ -415,24 +415,24 @@ cfg_macros! { #[cfg(not(test))] // Work around for rust-lang/rust#62127 #[cfg_attr(docsrs, doc(cfg(feature = "macros")))] - pub use tokio_macros::main_threaded as main; + pub use tokio_macros::main; #[cfg_attr(docsrs, doc(cfg(feature = "macros")))] - pub use tokio_macros::test_threaded as test; + pub use tokio_macros::test; } cfg_not_rt_threaded! { #[cfg(not(test))] // Work around for rust-lang/rust#62127 - pub use tokio_macros::main_basic as main; - pub use tokio_macros::test_basic as test; + pub use tokio_macros::main_rt_core as main; + pub use tokio_macros::test_rt_core as test; } } - // Maintains old behavior + // Always fail if rt-core is not enabled. cfg_not_rt_core! { #[cfg(not(test))] - pub use tokio_macros::main; - pub use tokio_macros::test; + pub use tokio_macros::main_fail as main; + pub use tokio_macros::test_fail as main; } } From 1ecd3bc42b0ce1645ee1ce3a976a0d7dc7170e5d Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Sat, 3 Oct 2020 20:27:00 +0200 Subject: [PATCH 04/39] Update tests --- tokio/src/stream/mod.rs | 2 +- tokio/tests/sync_rwlock.rs | 2 +- tokio/tests/task_blocking.rs | 6 +++--- tokio/tests/task_local.rs | 2 +- tokio/tests/task_local_set.rs | 16 ++++++++-------- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tokio/src/stream/mod.rs b/tokio/src/stream/mod.rs index ec48392be27..376d97d91e3 100644 --- a/tokio/src/stream/mod.rs +++ b/tokio/src/stream/mod.rs @@ -267,7 +267,7 @@ pub trait StreamExt: Stream { /// # /* /// #[tokio::main] /// # */ - /// # #[tokio::main(basic_scheduler)] + /// # #[tokio::main(flavor = "in_place")] /// async fn main() { /// # time::pause(); /// let (tx1, rx1) = mpsc::channel(10); diff --git a/tokio/tests/sync_rwlock.rs b/tokio/tests/sync_rwlock.rs index 87010b658e0..e803ca1f4f9 100644 --- a/tokio/tests/sync_rwlock.rs +++ b/tokio/tests/sync_rwlock.rs @@ -166,7 +166,7 @@ async fn write_order() { } // A single RwLock is contested by tasks in multiple threads -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing", num_workers = 8)] async fn multithreaded() { let barrier = Arc::new(Barrier::new(5)); let rwlock = Arc::new(RwLock::::new(0)); diff --git a/tokio/tests/task_blocking.rs b/tokio/tests/task_blocking.rs index 6cb11584b4a..c79581a9e01 100644 --- a/tokio/tests/task_blocking.rs +++ b/tokio/tests/task_blocking.rs @@ -28,7 +28,7 @@ async fn basic_blocking() { } } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn block_in_blocking() { // Run a few times for _ in 0..100 { @@ -51,7 +51,7 @@ async fn block_in_blocking() { } } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn block_in_block() { // Run a few times for _ in 0..100 { @@ -71,7 +71,7 @@ async fn block_in_block() { } } -#[tokio::test(basic_scheduler)] +#[tokio::test(flavor = "in_place")] #[should_panic] async fn no_block_in_basic_scheduler() { task::block_in_place(|| {}); diff --git a/tokio/tests/task_local.rs b/tokio/tests/task_local.rs index 58b58183c29..ce143e93163 100644 --- a/tokio/tests/task_local.rs +++ b/tokio/tests/task_local.rs @@ -3,7 +3,7 @@ tokio::task_local! { pub static FOO: bool; } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn local() { let j1 = tokio::spawn(REQ_ID.scope(1, async move { assert_eq!(REQ_ID.get(), 1); diff --git a/tokio/tests/task_local_set.rs b/tokio/tests/task_local_set.rs index 1dc779ced57..fc1a324caf2 100644 --- a/tokio/tests/task_local_set.rs +++ b/tokio/tests/task_local_set.rs @@ -11,7 +11,7 @@ use std::sync::atomic::Ordering::{self, SeqCst}; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::time::Duration; -#[tokio::test(basic_scheduler)] +#[tokio::test(flavor = "in_place")] async fn local_basic_scheduler() { LocalSet::new() .run_until(async { @@ -20,7 +20,7 @@ async fn local_basic_scheduler() { .await; } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn local_threadpool() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); @@ -40,7 +40,7 @@ async fn local_threadpool() { .await; } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn localset_future_threadpool() { thread_local! { static ON_LOCAL_THREAD: Cell = Cell::new(false); @@ -55,7 +55,7 @@ async fn localset_future_threadpool() { local.await; } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn localset_future_timers() { static RAN1: AtomicBool = AtomicBool::new(false); static RAN2: AtomicBool = AtomicBool::new(false); @@ -99,7 +99,7 @@ async fn localset_future_drives_all_local_futs() { assert!(RAN3.load(Ordering::SeqCst)); } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn local_threadpool_timer() { // This test ensures that runtime services like the timer are properly // set for the local task set. @@ -149,7 +149,7 @@ fn local_threadpool_blocking_in_place() { }); } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn local_threadpool_blocking_run() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); @@ -177,7 +177,7 @@ async fn local_threadpool_blocking_run() { .await; } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn all_spawns_are_local() { use futures::future; thread_local! { @@ -203,7 +203,7 @@ async fn all_spawns_are_local() { .await; } -#[tokio::test(threaded_scheduler)] +#[tokio::test(flavor = "work_stealing")] async fn nested_spawn_is_local() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); From ccd426d6367e206b95dde1f6befaf43dd5a1983d Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 5 Oct 2020 18:31:39 +0200 Subject: [PATCH 05/39] Rename to current_thread/threaded and remove max_threads --- tokio-macros/src/entry.rs | 95 +++++++++++++-------------------------- 1 file changed, 30 insertions(+), 65 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index b0be79b7e99..22493f3eebb 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -5,19 +5,19 @@ use syn::spanned::Spanned; #[derive(Clone, Copy, PartialEq)] enum RuntimeFlavor { - InPlace, - WorkStealing, + CurrentThread, + Threaded, } impl RuntimeFlavor { fn from_str(s: &str) -> Result { match s { - "in_place" => Ok(RuntimeFlavor::InPlace), - "work_stealing" => Ok(RuntimeFlavor::WorkStealing), - "single_threaded" => Err(format!("The single threaded runtime flavor is called `in_place`.")), - "basic_scheduler" => Err(format!("The `basic_scheduler` runtime flavor has been renamed to `in_place`.")), - "threaded_scheduler" => Err(format!("The `threaded_scheduler` runtime flavor has been renamed to `work_stealing`.")), - _ => Err(format!("No such runtime flavor `{}`.", s)), + "current_thread" => Ok(RuntimeFlavor::CurrentThread), + "threaded" => Ok(RuntimeFlavor::Threaded), + "single_threaded" => Err(format!("The single threaded runtime flavor is called `current_thread`.")), + "basic_scheduler" => Err(format!("The `basic_scheduler` runtime flavor has been renamed to `current_thread`.")), + "threaded_scheduler" => Err(format!("The `threaded_scheduler` runtime flavor has been renamed to `threaded`.")), + _ => Err(format!("No such runtime flavor `{}`. The runtime flavors are `current_thread` and `threaded`.", s)), } } } @@ -25,7 +25,6 @@ impl RuntimeFlavor { struct FinalConfig { flavor: RuntimeFlavor, num_workers: Option, - max_threads: Option, } struct Configuration { @@ -33,21 +32,21 @@ struct Configuration { default_flavor: RuntimeFlavor, flavor: Option, num_workers: Option<(usize, Span)>, - max_threads: Option<(usize, Span)>, } + impl Configuration { fn new(is_test: bool, rt_threaded: bool) -> Self { Configuration { rt_threaded_available: rt_threaded, default_flavor: match is_test { - true => RuntimeFlavor::InPlace, - false => RuntimeFlavor::WorkStealing, + true => RuntimeFlavor::CurrentThread, + false => RuntimeFlavor::Threaded, }, flavor: None, num_workers: None, - max_threads: None, } } + fn set_flavor( &mut self, runtime: syn::Lit, @@ -63,6 +62,7 @@ impl Configuration { self.flavor = Some(runtime); Ok(()) } + fn set_num_workers( &mut self, num_workers: syn::Lit, @@ -79,67 +79,37 @@ impl Configuration { self.num_workers = Some((num_workers, span)); Ok(()) } - fn set_max_threads( - &mut self, - max_threads: syn::Lit, - span: Span, - ) -> Result<(), syn::Error> { - if self.max_threads.is_some() { - return Err(syn::Error::new(span, "`max_threads` set multiple times.")); - } - let max_threads = parse_int(max_threads, span, "max_threads")?; - if max_threads == 0 { - return Err(syn::Error::new(span, "`max_threads` may not be 0.")); - } - self.max_threads = Some((max_threads, span)); - Ok(()) - } fn build(&self) -> Result { let flavor = self.flavor.unwrap_or(self.default_flavor); match flavor { - RuntimeFlavor::InPlace => { + RuntimeFlavor::CurrentThread => { if let Some((_, num_workers_span)) = &self.num_workers { return Err(syn::Error::new( num_workers_span.clone(), - "The `num_workers` option requires the `work_stealing` runtime flavor." + "The `num_workers` option requires the `threaded` runtime flavor." )); } + assert!(self.num_workers.is_none()); Ok(FinalConfig { flavor, num_workers: None, - max_threads: self.max_threads.map(|(val, _span)| val), }) }, - RuntimeFlavor::WorkStealing => { + RuntimeFlavor::Threaded => { if !self.rt_threaded_available { let msg = if self.flavor.is_none() { - "The default runtime flavor is `work_stealing`, but the `rt-threaded` feature is disabled." + "The default runtime flavor is `threaded`, but the `rt-threaded` feature is disabled." } else { - "The runtime flavor `work_stealing` requires the `rt-threaded` feature." + "The runtime flavor `threaded` requires the `rt-threaded` feature." }; return Err(syn::Error::new(Span::call_site(), msg)); } - match (self.num_workers, self.max_threads) { - (None, Some((_, span))) => { - return Err(syn::Error::new( - span, - "`num_workers` must also be set when using `max_threads`" - )); - }, - (Some((num_workers, _)), Some((max_threads, span))) if max_threads <= num_workers => { - return Err(syn::Error::new( - span, - "`max_threads` must be larger than `num_workers`", - )); - }, - _ => {}, - } + Ok(FinalConfig { flavor, num_workers: self.num_workers.map(|(val, _span)| val), - max_threads: self.max_threads.map(|(val, _span)| val), }) }, } @@ -160,6 +130,7 @@ fn parse_int(int: syn::Lit, span: Span, field: &str) -> Result Err(syn::Error::new(span, format!("Failed to parse {} as integer.", field))), } } + fn parse_string(int: syn::Lit, span: Span, field: &str) -> Result { match int { syn::Lit::Str(s) => Ok(s.value()), @@ -201,12 +172,9 @@ fn parse_knobs( "num_workers" => { config.set_num_workers(namevalue.lit.clone(), namevalue.span())?; } - "max_threads" => { - config.set_max_threads(namevalue.lit.clone(), namevalue.span())?; - }, "flavor" => { config.set_flavor(namevalue.lit.clone(), namevalue.span())?; - }, + } "core_threads" => { let msg = "Attribute `core_threads` is renamed to `num_workers`"; return Err(syn::Error::new_spanned(namevalue, msg)); @@ -225,17 +193,17 @@ fn parse_knobs( } let name = ident.unwrap().to_string().to_lowercase(); let msg = match name.as_str() { - "threaded_scheduler" | "work_stealing" => { - format!("Set the runtime flavor with #[{}(flavor = \"work_stealing\")].", macro_name) + "threaded_scheduler" | "threaded" => { + format!("Set the runtime flavor with #[{}(flavor = \"threaded\")].", macro_name) }, - "basic_scheduler" | "in_place" => { - format!("Set the runtime flavor with #[{}(flavor = \"in_place\")].", macro_name) + "basic_scheduler" | "current_thread" | "single_threaded" => { + format!("Set the runtime flavor with #[{}(flavor = \"current_thread\")].", macro_name) }, - "flavor" | "num_workers" | "max_threads" => { + "flavor" | "num_workers" => { format!("The `{}` attribute requires an argument.", name) }, name => { - format!("Unkown attribute {} is specified; expected one of: `flavor`, `num_workers`, `max_threads`", name) + format!("Unkown attribute {} is specified; expected one of: `flavor`, `num_workers`", name) }, }; return Err(syn::Error::new_spanned(path, msg)); @@ -252,19 +220,16 @@ fn parse_knobs( let config = config.build()?; let mut rt = match config.flavor { - RuntimeFlavor::InPlace => quote! { + RuntimeFlavor::CurrentThread => quote! { tokio::runtime::Builder::new().basic_scheduler() }, - RuntimeFlavor::WorkStealing => quote! { + RuntimeFlavor::Threaded => quote! { tokio::runtime::Builder::new().threaded_scheduler() }, }; if let Some(v) = config.num_workers { rt = quote! { #rt.core_threads(#v) }; } - if let Some(v) = config.max_threads { - rt = quote! { #rt.max_threads(#v) }; - } let header = { if is_test { From 019945ffacd8313aaa70b08fb3138ce5c9b0576f Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 6 Oct 2020 18:56:56 +0200 Subject: [PATCH 06/39] Use match in build --- tokio-macros/src/entry.rs | 40 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 22493f3eebb..73f9fc557e7 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -82,36 +82,34 @@ impl Configuration { fn build(&self) -> Result { let flavor = self.flavor.unwrap_or(self.default_flavor); - match flavor { - RuntimeFlavor::CurrentThread => { - if let Some((_, num_workers_span)) = &self.num_workers { - return Err(syn::Error::new( - num_workers_span.clone(), - "The `num_workers` option requires the `threaded` runtime flavor." - )); - } - - assert!(self.num_workers.is_none()); + use RuntimeFlavor::*; + match (flavor, self.num_workers) { + (CurrentThread, Some((_, num_workers_span))) => { + Err(syn::Error::new( + num_workers_span, + "The `num_workers` option requires the `threaded` runtime flavor." + )) + }, + (CurrentThread, None) => { Ok(FinalConfig { flavor, num_workers: None, }) }, - RuntimeFlavor::Threaded => { - if !self.rt_threaded_available { - let msg = if self.flavor.is_none() { - "The default runtime flavor is `threaded`, but the `rt-threaded` feature is disabled." - } else { - "The runtime flavor `threaded` requires the `rt-threaded` feature." - }; - return Err(syn::Error::new(Span::call_site(), msg)); - } - + (Threaded, num_workers) if self.rt_threaded_available => { Ok(FinalConfig { flavor, - num_workers: self.num_workers.map(|(val, _span)| val), + num_workers: num_workers.map(|(val, _span)| val), }) }, + (Threaded, _) => { + let msg = if self.flavor.is_none() { + "The default runtime flavor is `threaded`, but the `rt-threaded` feature is disabled." + } else { + "The runtime flavor `threaded` requires the `rt-threaded` feature." + }; + Err(syn::Error::new(Span::call_site(), msg)) + }, } } } From 8c2b54a43533513c714b5e10f84b5b8b50ea2fa8 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 7 Oct 2020 18:13:47 +0200 Subject: [PATCH 07/39] Fix tests --- .../tests/fail/macros_invalid_input.stderr | 4 ++-- tokio-macros/src/entry.rs | 2 +- tokio-util/src/codec/bytes_codec.rs | 2 +- tokio/src/stream/mod.rs | 2 +- tokio/tests/sync_rwlock.rs | 2 +- tokio/tests/task_blocking.rs | 6 +++--- tokio/tests/task_local.rs | 2 +- tokio/tests/task_local_set.rs | 16 ++++++++-------- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests-build/tests/fail/macros_invalid_input.stderr b/tests-build/tests/fail/macros_invalid_input.stderr index 96fdcb177fd..1b343c778b9 100644 --- a/tests-build/tests/fail/macros_invalid_input.stderr +++ b/tests-build/tests/fail/macros_invalid_input.stderr @@ -4,7 +4,7 @@ error: the async keyword is missing from the function declaration 4 | fn main_is_not_async() {} | ^^ -error: Unknown attribute foo is specified; expected `basic_scheduler` or `threaded_scheduler` +error: Unknown attribute foo is specified; expected one of: `flavor`, `num_workers` --> $DIR/macros_invalid_input.rs:6:15 | 6 | #[tokio::main(foo)] @@ -28,7 +28,7 @@ error: the test function cannot accept arguments 16 | async fn test_fn_has_args(_x: u8) {} | ^^^^^^ -error: Unknown attribute foo is specified; expected `basic_scheduler` or `threaded_scheduler` +error: Unknown attribute foo is specified; expected one of: `flavor`, `num_workers` --> $DIR/macros_invalid_input.rs:18:15 | 18 | #[tokio::test(foo)] diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 73f9fc557e7..191631bcba8 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -201,7 +201,7 @@ fn parse_knobs( format!("The `{}` attribute requires an argument.", name) }, name => { - format!("Unkown attribute {} is specified; expected one of: `flavor`, `num_workers`", name) + format!("Unknown attribute {} is specified; expected one of: `flavor`, `num_workers`", name) }, }; return Err(syn::Error::new_spanned(path, msg)); diff --git a/tokio-util/src/codec/bytes_codec.rs b/tokio-util/src/codec/bytes_codec.rs index a5e73749ef1..275031c066c 100644 --- a/tokio-util/src/codec/bytes_codec.rs +++ b/tokio-util/src/codec/bytes_codec.rs @@ -33,7 +33,7 @@ use std::io; /// # } /// # } /// # -/// # #[tokio::main(core_threads = 1)] +/// # #[tokio::main(flavor = "current_thread")] /// # async fn main() -> Result<(), std::io::Error> { /// let my_async_read = File::open("filename.txt").await?; /// let my_stream_of_bytes = FramedRead::new(my_async_read, BytesCodec::new()); diff --git a/tokio/src/stream/mod.rs b/tokio/src/stream/mod.rs index 376d97d91e3..30534f6935f 100644 --- a/tokio/src/stream/mod.rs +++ b/tokio/src/stream/mod.rs @@ -267,7 +267,7 @@ pub trait StreamExt: Stream { /// # /* /// #[tokio::main] /// # */ - /// # #[tokio::main(flavor = "in_place")] + /// # #[tokio::main(flavor = "current_thread")] /// async fn main() { /// # time::pause(); /// let (tx1, rx1) = mpsc::channel(10); diff --git a/tokio/tests/sync_rwlock.rs b/tokio/tests/sync_rwlock.rs index e803ca1f4f9..9fbf3d6fe0b 100644 --- a/tokio/tests/sync_rwlock.rs +++ b/tokio/tests/sync_rwlock.rs @@ -166,7 +166,7 @@ async fn write_order() { } // A single RwLock is contested by tasks in multiple threads -#[tokio::test(flavor = "work_stealing", num_workers = 8)] +#[tokio::test(flavor = "threaded", num_workers = 8)] async fn multithreaded() { let barrier = Arc::new(Barrier::new(5)); let rwlock = Arc::new(RwLock::::new(0)); diff --git a/tokio/tests/task_blocking.rs b/tokio/tests/task_blocking.rs index c79581a9e01..334a9646f85 100644 --- a/tokio/tests/task_blocking.rs +++ b/tokio/tests/task_blocking.rs @@ -28,7 +28,7 @@ async fn basic_blocking() { } } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn block_in_blocking() { // Run a few times for _ in 0..100 { @@ -51,7 +51,7 @@ async fn block_in_blocking() { } } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn block_in_block() { // Run a few times for _ in 0..100 { @@ -71,7 +71,7 @@ async fn block_in_block() { } } -#[tokio::test(flavor = "in_place")] +#[tokio::test(flavor = "current_thread")] #[should_panic] async fn no_block_in_basic_scheduler() { task::block_in_place(|| {}); diff --git a/tokio/tests/task_local.rs b/tokio/tests/task_local.rs index ce143e93163..87ced4eae00 100644 --- a/tokio/tests/task_local.rs +++ b/tokio/tests/task_local.rs @@ -3,7 +3,7 @@ tokio::task_local! { pub static FOO: bool; } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn local() { let j1 = tokio::spawn(REQ_ID.scope(1, async move { assert_eq!(REQ_ID.get(), 1); diff --git a/tokio/tests/task_local_set.rs b/tokio/tests/task_local_set.rs index fc1a324caf2..a7b08c22b2a 100644 --- a/tokio/tests/task_local_set.rs +++ b/tokio/tests/task_local_set.rs @@ -11,7 +11,7 @@ use std::sync::atomic::Ordering::{self, SeqCst}; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::time::Duration; -#[tokio::test(flavor = "in_place")] +#[tokio::test(flavor = "current_thread")] async fn local_basic_scheduler() { LocalSet::new() .run_until(async { @@ -20,7 +20,7 @@ async fn local_basic_scheduler() { .await; } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn local_threadpool() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); @@ -40,7 +40,7 @@ async fn local_threadpool() { .await; } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn localset_future_threadpool() { thread_local! { static ON_LOCAL_THREAD: Cell = Cell::new(false); @@ -55,7 +55,7 @@ async fn localset_future_threadpool() { local.await; } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn localset_future_timers() { static RAN1: AtomicBool = AtomicBool::new(false); static RAN2: AtomicBool = AtomicBool::new(false); @@ -99,7 +99,7 @@ async fn localset_future_drives_all_local_futs() { assert!(RAN3.load(Ordering::SeqCst)); } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn local_threadpool_timer() { // This test ensures that runtime services like the timer are properly // set for the local task set. @@ -149,7 +149,7 @@ fn local_threadpool_blocking_in_place() { }); } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn local_threadpool_blocking_run() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); @@ -177,7 +177,7 @@ async fn local_threadpool_blocking_run() { .await; } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn all_spawns_are_local() { use futures::future; thread_local! { @@ -203,7 +203,7 @@ async fn all_spawns_are_local() { .await; } -#[tokio::test(flavor = "work_stealing")] +#[tokio::test(flavor = "threaded")] async fn nested_spawn_is_local() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); From a1ae97c57d8ee69fff0e1cd77daf97a18a756592 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 7 Oct 2020 18:16:57 +0200 Subject: [PATCH 08/39] rustfmt --- tokio-macros/src/entry.rs | 84 ++++++++++++++++++--------------------- tokio-macros/src/lib.rs | 8 +++- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 191631bcba8..a576a81d02b 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -47,27 +47,19 @@ impl Configuration { } } - fn set_flavor( - &mut self, - runtime: syn::Lit, - span: Span, - ) -> Result<(), syn::Error> { + fn set_flavor(&mut self, runtime: syn::Lit, span: Span) -> Result<(), syn::Error> { if self.flavor.is_some() { return Err(syn::Error::new(span, "`flavor` set multiple times.")); } let runtime_str = parse_string(runtime, span, "flavor")?; - let runtime = RuntimeFlavor::from_str(&runtime_str) - .map_err(|err| syn::Error::new(span, err))?; + let runtime = + RuntimeFlavor::from_str(&runtime_str).map_err(|err| syn::Error::new(span, err))?; self.flavor = Some(runtime); Ok(()) } - fn set_num_workers( - &mut self, - num_workers: syn::Lit, - span: Span, - ) -> Result<(), syn::Error> { + fn set_num_workers(&mut self, num_workers: syn::Lit, span: Span) -> Result<(), syn::Error> { if self.num_workers.is_some() { return Err(syn::Error::new(span, "`num_workers` set multiple times.")); } @@ -84,24 +76,18 @@ impl Configuration { let flavor = self.flavor.unwrap_or(self.default_flavor); use RuntimeFlavor::*; match (flavor, self.num_workers) { - (CurrentThread, Some((_, num_workers_span))) => { - Err(syn::Error::new( - num_workers_span, - "The `num_workers` option requires the `threaded` runtime flavor." - )) - }, - (CurrentThread, None) => { - Ok(FinalConfig { - flavor, - num_workers: None, - }) - }, - (Threaded, num_workers) if self.rt_threaded_available => { - Ok(FinalConfig { - flavor, - num_workers: num_workers.map(|(val, _span)| val), - }) - }, + (CurrentThread, Some((_, num_workers_span))) => Err(syn::Error::new( + num_workers_span, + "The `num_workers` option requires the `threaded` runtime flavor.", + )), + (CurrentThread, None) => Ok(FinalConfig { + flavor, + num_workers: None, + }), + (Threaded, num_workers) if self.rt_threaded_available => Ok(FinalConfig { + flavor, + num_workers: num_workers.map(|(val, _span)| val), + }), (Threaded, _) => { let msg = if self.flavor.is_none() { "The default runtime flavor is `threaded`, but the `rt-threaded` feature is disabled." @@ -109,23 +95,24 @@ impl Configuration { "The runtime flavor `threaded` requires the `rt-threaded` feature." }; Err(syn::Error::new(Span::call_site(), msg)) - }, + } } } } fn parse_int(int: syn::Lit, span: Span, field: &str) -> Result { match int { - syn::Lit::Int(lit) => { - match lit.base10_parse::() { - Ok(value) => Ok(value), - Err(e) => Err(syn::Error::new( - span, - format!("Failed to parse {} as integer: {}", field, e), - )), - } + syn::Lit::Int(lit) => match lit.base10_parse::() { + Ok(value) => Ok(value), + Err(e) => Err(syn::Error::new( + span, + format!("Failed to parse {} as integer: {}", field, e), + )), }, - _ => Err(syn::Error::new(span, format!("Failed to parse {} as integer.", field))), + _ => Err(syn::Error::new( + span, + format!("Failed to parse {} as integer.", field), + )), } } @@ -133,7 +120,10 @@ fn parse_string(int: syn::Lit, span: Span, field: &str) -> Result Ok(s.value()), syn::Lit::Verbatim(s) => Ok(s.to_string()), - _ => Err(syn::Error::new(span, format!("Failed to parse {} as string.", field))), + _ => Err(syn::Error::new( + span, + format!("Failed to parse {} as string.", field), + )), } } @@ -155,7 +145,11 @@ fn parse_knobs( sig.asyncness = None; - let macro_name = if is_test { "tokio::test" } else { "tokio::main" }; + let macro_name = if is_test { + "tokio::test" + } else { + "tokio::main" + }; let mut config = Configuration::new(is_test, rt_threaded); for arg in args { @@ -266,8 +260,7 @@ pub(crate) fn main(args: TokenStream, item: TokenStream, rt_threaded: bool) -> T .into(); } - parse_knobs(input, args, false, rt_threaded) - .unwrap_or_else(|e| e.to_compile_error().into()) + parse_knobs(input, args, false, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into()) } pub(crate) fn test(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream { @@ -290,6 +283,5 @@ pub(crate) fn test(args: TokenStream, item: TokenStream, rt_threaded: bool) -> T .into(); } - parse_knobs(input, args, true, rt_threaded) - .unwrap_or_else(|e| e.to_compile_error().into()) + parse_knobs(input, args, true, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into()) } diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 20150bb1f74..c7a5f8b7e8a 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -262,7 +262,9 @@ pub fn main_fail(_args: TokenStream, _item: TokenStream) -> TokenStream { syn::Error::new( proc_macro2::Span::call_site(), "The #[tokio::main] macro requires rt-core or rt-threaded.", - ).to_compile_error().into() + ) + .to_compile_error() + .into() } /// Always fails with the error message below. @@ -274,7 +276,9 @@ pub fn test_fail(_args: TokenStream, _item: TokenStream) -> TokenStream { syn::Error::new( proc_macro2::Span::call_site(), "The #[tokio::test] macro requires rt-core or rt-threaded.", - ).to_compile_error().into() + ) + .to_compile_error() + .into() } /// Implementation detail of the `select!` macro. This macro is **not** intended From 430993d24a73fbc48a0bc4b375f4deb4caba7931 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 7 Oct 2020 18:17:57 +0200 Subject: [PATCH 09/39] clippy --- tokio-macros/src/entry.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index a576a81d02b..66e61bfd538 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -14,9 +14,9 @@ impl RuntimeFlavor { match s { "current_thread" => Ok(RuntimeFlavor::CurrentThread), "threaded" => Ok(RuntimeFlavor::Threaded), - "single_threaded" => Err(format!("The single threaded runtime flavor is called `current_thread`.")), - "basic_scheduler" => Err(format!("The `basic_scheduler` runtime flavor has been renamed to `current_thread`.")), - "threaded_scheduler" => Err(format!("The `threaded_scheduler` runtime flavor has been renamed to `threaded`.")), + "single_threaded" => Err("The single threaded runtime flavor is called `current_thread`.".to_string()), + "basic_scheduler" => Err("The `basic_scheduler` runtime flavor has been renamed to `current_thread`.".to_string()), + "threaded_scheduler" => Err("The `threaded_scheduler` runtime flavor has been renamed to `threaded`.".to_string()), _ => Err(format!("No such runtime flavor `{}`. The runtime flavors are `current_thread` and `threaded`.", s)), } } From 10a27352fb8d85623de190dc2690663b66c964c1 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 7 Oct 2020 19:25:21 +0200 Subject: [PATCH 10/39] Try to fix doctests --- tokio-macros/src/lib.rs | 44 +++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index c7a5f8b7e8a..971f6254cae 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -33,14 +33,23 @@ use proc_macro::TokenStream; /// using [Builder](../tokio/runtime/struct.Builder.html), which provides a more powerful /// interface. /// -/// ## Options: +/// # Multi-threaded runtime +/// To use the multi-threaded runtime, the macro can be configured using +/// ``` +/// #[tokio::main(flavor = "threaded", num_workers = 10)] +/// # async fn main() {} +/// ``` +/// The `num_workers` option configures the number of worker threads, and defaults to the number of +/// cpus on the system. This is the default flavor. /// -/// If you want to set the number of worker threads used for asynchronous code, use the -/// `core_threads` option. +/// # Current thread runtime /// -/// - `core_threads=n` - Sets core threads to `n` (requires `rt-threaded` feature). -/// - `max_threads=n` - Sets max threads to `n` (requires `rt-core` or `rt-threaded` feature). -/// - `basic_scheduler` - Use the basic schduler (requires `rt-core`). +/// To use the single-threaded runtime known as the `current_thread` runtime, the macro can be +/// configured using +/// ``` +/// #[tokio::main(flavor = "current_thread")] +/// # async fn main() {} +/// ``` /// /// ## Function arguments: /// @@ -48,7 +57,7 @@ use proc_macro::TokenStream; /// /// ## Usage /// -/// ### Using default +/// ### Using threaded runtime /// /// ```rust /// #[tokio::main] @@ -72,12 +81,12 @@ use proc_macro::TokenStream; /// } /// ``` /// -/// ### Using basic scheduler +/// ### Using current thread runtime /// /// The basic scheduler is single-threaded. /// /// ```rust -/// #[tokio::main(basic_scheduler)] +/// #[tokio::main(flavor = "current_thread")] /// async fn main() { /// println!("Hello world"); /// } @@ -98,7 +107,7 @@ use proc_macro::TokenStream; /// } /// ``` /// -/// ### Set number of core threads +/// ### Set number of worker threads /// /// ```rust /// #[tokio::main(num_workers = 2)] @@ -140,10 +149,6 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { /// without requiring the user to use [Runtime](../tokio/runtime/struct.Runtime.html) or /// [Builder](../tokio/runtime/struct.builder.html) directly. /// -/// ## Options: -/// -/// - `max_threads=n` - Sets max threads to `n`. -/// /// ## Function arguments: /// /// Arguments are allowed for any functions aside from `main` which is special @@ -189,17 +194,12 @@ pub fn main_rt_core(args: TokenStream, item: TokenStream) -> TokenStream { /// Marks async function to be executed by runtime, suitable to test environment /// -/// ## Options: -/// -/// - `core_threads=n` - Sets core threads to `n` (requires `rt-threaded` feature). -/// - `max_threads=n` - Sets max threads to `n` (requires `rt-core` or `rt-threaded` feature). -/// /// ## Usage /// -/// ### Select runtime +/// ### Threaded runtime /// /// ```no_run -/// #[tokio::test(core_threads = 1)] +/// #[tokio::test(flavor = "threaded", num_workers = 1)] /// async fn my_test() { /// assert!(true); /// } @@ -207,6 +207,8 @@ pub fn main_rt_core(args: TokenStream, item: TokenStream) -> TokenStream { /// /// ### Using default /// +/// The default test runtime is single-threaded. +/// /// ```no_run /// #[tokio::test] /// async fn my_test() { From 0775bd4396d619ac4d91c173e78a5a8718d76c6c Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 7 Oct 2020 19:45:20 +0200 Subject: [PATCH 11/39] test_fail as main -> test --- tokio/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/src/lib.rs b/tokio/src/lib.rs index e511e87cbf1..65adc1d9a29 100644 --- a/tokio/src/lib.rs +++ b/tokio/src/lib.rs @@ -432,7 +432,7 @@ cfg_macros! { cfg_not_rt_core! { #[cfg(not(test))] pub use tokio_macros::main_fail as main; - pub use tokio_macros::test_fail as main; + pub use tokio_macros::test_fail as test; } } From 9c22b8573a569f0bf990554bf5674bee0d2909fb Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Wed, 7 Oct 2020 18:18:01 +0000 Subject: [PATCH 12/39] Add `new_multi_thread`/`new_current_thread`/`new_single_thread` --- benches/mpsc.rs | 34 ++++---- benches/scheduler.rs | 4 +- benches/signal.rs | 4 +- benches/spawn.rs | 12 +-- benches/sync_rwlock.rs | 18 ++--- benches/sync_semaphore.rs | 19 +++-- tests-integration/tests/rt_shell.rs | 32 -------- tokio-macros/src/entry.rs | 8 +- tokio-test/src/lib.rs | 3 +- tokio-util/tests/context.rs | 5 +- tokio/src/io/stdio_common.rs | 3 +- tokio/src/runtime/builder.rs | 117 +++++++++++++++------------- tokio/src/runtime/mod.rs | 9 +-- tokio/src/signal/registry.rs | 2 +- tokio/tests/io_driver.rs | 3 +- tokio/tests/io_driver_drop.rs | 3 +- tokio/tests/rt_basic.rs | 3 +- tokio/tests/rt_common.rs | 25 ++++-- tokio/tests/rt_threaded.rs | 13 ++-- tokio/tests/signal_drop_rt.rs | 3 +- tokio/tests/signal_multi_rt.rs | 3 +- tokio/tests/task_blocking.rs | 16 ++-- tokio/tests/task_local_set.rs | 8 +- tokio/tests/time_rt.rs | 2 +- 24 files changed, 159 insertions(+), 190 deletions(-) delete mode 100644 tests-integration/tests/rt_shell.rs diff --git a/benches/mpsc.rs b/benches/mpsc.rs index a1fb1858d21..62a76ef6c84 100644 --- a/benches/mpsc.rs +++ b/benches/mpsc.rs @@ -4,6 +4,13 @@ use tokio::sync::mpsc; type Medium = [usize; 64]; type Large = [Medium; 64]; +fn rt() -> tokio::runtime::Runtime { + tokio::runtime::Builder::new_multi_thread() + .worker_threads(6) + .build() + .unwrap() +} + fn create_1_medium(b: &mut Bencher) { b.iter(|| { black_box(&mpsc::channel::(1)); @@ -43,12 +50,9 @@ fn send_large(b: &mut Bencher) { } fn contention_bounded(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) - .build() - .unwrap(); + let rt = rt(); - b.iter(|| { + let rt = b.iter(|| { rt.block_on(async move { let (tx, mut rx) = mpsc::channel::(1_000_000); @@ -69,10 +73,7 @@ fn contention_bounded(b: &mut Bencher) { } fn contention_bounded_full(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) - .build() - .unwrap(); + let rt = rt(); b.iter(|| { rt.block_on(async move { @@ -95,10 +96,7 @@ fn contention_bounded_full(b: &mut Bencher) { } fn contention_unbounded(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) - .build() - .unwrap(); + let rt = rt(); b.iter(|| { rt.block_on(async move { @@ -121,10 +119,7 @@ fn contention_unbounded(b: &mut Bencher) { } fn uncontented_bounded(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) - .build() - .unwrap(); + let rt = rt(); b.iter(|| { rt.block_on(async move { @@ -142,10 +137,7 @@ fn uncontented_bounded(b: &mut Bencher) { } fn uncontented_unbounded(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) - .build() - .unwrap(); + let rt = rt(); b.iter(|| { rt.block_on(async move { diff --git a/benches/scheduler.rs b/benches/scheduler.rs index 906528064e0..68a6d6a4fa1 100644 --- a/benches/scheduler.rs +++ b/benches/scheduler.rs @@ -139,8 +139,8 @@ fn chained_spawn(b: &mut Bencher) { } fn rt() -> Runtime { - runtime::Builder::new() - .core_threads(4) + runtime::Builder::new_multi_thread() + .worker_threads(4) .enable_all() .build() .unwrap() diff --git a/benches/signal.rs b/benches/signal.rs index e3ad714c718..5a5f6517de4 100644 --- a/benches/signal.rs +++ b/benches/signal.rs @@ -45,9 +45,9 @@ fn many_signals(bench: &mut Bencher) { let num_signals = 10; let (tx, mut rx) = mpsc::channel(num_signals); - let rt = runtime::Builder::new() + let rt = runtime::Builder::new_multi_thread() // Intentionally single threaded to measure delays in propagating wakes - .core_threads(0) + .worker_threads(0) .enable_all() .build() .unwrap(); diff --git a/benches/spawn.rs b/benches/spawn.rs index 717aad73741..72a4035757a 100644 --- a/benches/spawn.rs +++ b/benches/spawn.rs @@ -10,8 +10,7 @@ async fn work() -> usize { } fn basic_scheduler_local_spawn(bench: &mut Bencher) { - let runtime = tokio::runtime::Builder::new() - .core_threads(0) + let runtime = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); runtime.block_on(async { @@ -23,7 +22,9 @@ fn basic_scheduler_local_spawn(bench: &mut Bencher) { } fn threaded_scheduler_local_spawn(bench: &mut Bencher) { - let runtime = tokio::runtime::Builder::new().build().unwrap(); + let runtime = tokio::runtime::Builder::new_current_thread() + .build() + .unwrap(); runtime.block_on(async { bench.iter(|| { let h = tokio::spawn(work()); @@ -33,8 +34,7 @@ fn threaded_scheduler_local_spawn(bench: &mut Bencher) { } fn basic_scheduler_remote_spawn(bench: &mut Bencher) { - let runtime = tokio::runtime::Builder::new() - .core_threads(0) + let runtime = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); @@ -45,7 +45,7 @@ fn basic_scheduler_remote_spawn(bench: &mut Bencher) { } fn threaded_scheduler_remote_spawn(bench: &mut Bencher) { - let runtime = tokio::runtime::Builder::new().build().unwrap(); + let runtime = tokio::runtime::Builder::new_multi_thread().build().unwrap(); bench.iter(|| { let h = runtime.spawn(work()); diff --git a/benches/sync_rwlock.rs b/benches/sync_rwlock.rs index 18f68a70271..46eeac0c1d0 100644 --- a/benches/sync_rwlock.rs +++ b/benches/sync_rwlock.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use tokio::{sync::RwLock, task}; fn read_uncontended(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(6) .build() .unwrap(); @@ -21,8 +21,8 @@ fn read_uncontended(b: &mut Bencher) { } fn read_concurrent_uncontended_multi(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(6) .build() .unwrap(); @@ -49,8 +49,7 @@ fn read_concurrent_uncontended_multi(b: &mut Bencher) { } fn read_concurrent_uncontended(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(0) + let rt = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); @@ -76,8 +75,8 @@ fn read_concurrent_uncontended(b: &mut Bencher) { } fn read_concurrent_contended_multi(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(6) .build() .unwrap(); @@ -105,8 +104,7 @@ fn read_concurrent_contended_multi(b: &mut Bencher) { } fn read_concurrent_contended(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(0) + let rt = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); diff --git a/benches/sync_semaphore.rs b/benches/sync_semaphore.rs index 91f497ee274..19a1dd33c87 100644 --- a/benches/sync_semaphore.rs +++ b/benches/sync_semaphore.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use tokio::{sync::Semaphore, task}; fn uncontended(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(6) .build() .unwrap(); @@ -26,8 +26,8 @@ async fn task(s: Arc) { } fn uncontended_concurrent_multi(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(6) .build() .unwrap(); @@ -49,8 +49,8 @@ fn uncontended_concurrent_multi(b: &mut Bencher) { } fn uncontended_concurrent_single(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(0) + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(0) .build() .unwrap(); @@ -71,8 +71,8 @@ fn uncontended_concurrent_single(b: &mut Bencher) { } fn contended_concurrent_multi(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(6) + let rt = tokio::runtime::Builder::new_multi_thread() + .worker_threads(6) .build() .unwrap(); @@ -94,8 +94,7 @@ fn contended_concurrent_multi(b: &mut Bencher) { } fn contended_concurrent_single(b: &mut Bencher) { - let rt = tokio::runtime::Builder::new() - .core_threads(0) + let rt = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); diff --git a/tests-integration/tests/rt_shell.rs b/tests-integration/tests/rt_shell.rs deleted file mode 100644 index 012f44a71b3..00000000000 --- a/tests-integration/tests/rt_shell.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![warn(rust_2018_idioms)] -#![cfg(feature = "sync")] - -use tokio::runtime; -use tokio::sync::oneshot; - -use std::sync::mpsc; -use std::thread; - -#[test] -fn basic_shell_rt() { - let (feed_tx, feed_rx) = mpsc::channel::>(); - - let th = thread::spawn(move || { - for tx in feed_rx.iter() { - tx.send(()).unwrap(); - } - }); - - for _ in 0..1_000 { - let rt = runtime::Builder::new().build().unwrap(); - - let (tx, rx) = oneshot::channel(); - - feed_tx.send(tx).unwrap(); - - rt.block_on(rx).unwrap(); - } - - drop(feed_tx); - th.join().unwrap(); -} diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index dea839f4b54..7634c9688c7 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -127,7 +127,7 @@ fn parse_knobs( } } - let mut rt = quote! { tokio::runtime::Builder::new() }; + let mut rt = quote! { tokio::runtime::Builder::new_current_thread() }; if rt_threaded && (runtime == Some(Runtime::Threaded) || (runtime.is_none() && !is_test)) { rt = quote! { #rt }; @@ -278,8 +278,7 @@ pub(crate) mod old { Runtime::Basic => quote! { #(#attrs)* #vis #sig { - tokio::runtime::Builder::new() - .core_threads(0) + tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() @@ -354,8 +353,7 @@ pub(crate) mod old { #[::core::prelude::v1::test] #(#attrs)* #vis fn #name() #ret { - tokio::runtime::Builder::new() - .core_threads(0) + tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() diff --git a/tokio-test/src/lib.rs b/tokio-test/src/lib.rs index 7bcb4df4918..a20d0acd7c0 100644 --- a/tokio-test/src/lib.rs +++ b/tokio-test/src/lib.rs @@ -28,8 +28,7 @@ pub mod task; pub fn block_on(future: F) -> F::Output { use tokio::runtime; - let rt = runtime::Builder::new() - .core_threads(0) + let rt = runtime::Builder::new_current_thread() .enable_all() .build() .unwrap(); diff --git a/tokio-util/tests/context.rs b/tokio-util/tests/context.rs index 7b6d1989cb1..375941ec26f 100644 --- a/tokio-util/tests/context.rs +++ b/tokio-util/tests/context.rs @@ -6,12 +6,11 @@ use tokio_util::context::RuntimeExt; #[test] fn tokio_context_with_another_runtime() { - let rt1 = Builder::new() - .core_threads(1) + let rt1 = Builder::new_single_thread() // no timer! .build() .unwrap(); - let rt2 = Builder::new().core_threads(1).enable_all().build().unwrap(); + let rt2 = Builder::new_single_thread().enable_all().build().unwrap(); // Without the `HandleExt.wrap()` there would be a panic because there is // no timer running, since it would be referencing runtime r1. diff --git a/tokio/src/io/stdio_common.rs b/tokio/src/io/stdio_common.rs index 0e47ac1555a..4c30307005a 100644 --- a/tokio/src/io/stdio_common.rs +++ b/tokio/src/io/stdio_common.rs @@ -123,8 +123,7 @@ mod tests { let fut = async move { wr.write_all(data.as_bytes()).await.unwrap(); }; - crate::runtime::Builder::new() - .core_threads(0) + crate::runtime::Builder::new_current_thread() .build() .unwrap() .block_on(fut); diff --git a/tokio/src/runtime/builder.rs b/tokio/src/runtime/builder.rs index e50a349c52a..7c4812a2f59 100644 --- a/tokio/src/runtime/builder.rs +++ b/tokio/src/runtime/builder.rs @@ -26,8 +26,8 @@ use std::time::Duration; /// /// fn main() { /// // build runtime -/// let runtime = Builder::new() -/// .core_threads(4) +/// let runtime = Builder::new_multi_thread() +/// .worker_threads(4) /// .thread_name("my-custom-name") /// .thread_stack_size(3 * 1024 * 1024) /// .build() @@ -37,6 +37,9 @@ use std::time::Duration; /// } /// ``` pub struct Builder { + /// Runtime type + kind: Kind, + /// Whether or not to enable the I/O driver enable_io: bool, @@ -46,7 +49,7 @@ pub struct Builder { /// The number of worker threads, used by Runtime. /// /// Only used when not using the current-thread executor. - core_threads: Option, + worker_threads: Option, /// Cap on thread usage. max_threads: usize, @@ -71,13 +74,33 @@ pub struct Builder { pub(crate) type ThreadNameFn = std::sync::Arc String + Send + Sync + 'static>; +pub(crate) enum Kind { + CurrentThread, + SingleThread, + MultiThread, +} + impl Builder { + pub fn new_current_thread() -> Builder { + Builder::new(Kind::CurrentThread) + } + + pub fn new_single_thread() -> Builder { + Builder::new(Kind::SingleThread) + } + + pub fn new_multi_thread() -> Builder { + Builder::new(Kind::MultiThread) + } + /// Returns a new runtime builder initialized with default configuration /// values. /// /// Configuration methods can be chained on the return value. - pub fn new() -> Builder { + pub(crate) fn new(kind: Kind) -> Builder { Builder { + kind, + // I/O defaults to "off" enable_io: false, @@ -85,7 +108,7 @@ impl Builder { enable_time: false, // Default to lazy auto-detection (one thread per CPU core) - core_threads: None, + worker_threads: None, max_threads: 512, @@ -115,7 +138,7 @@ impl Builder { /// ``` /// use tokio::runtime; /// - /// let rt = runtime::Builder::new() + /// let rt = runtime::Builder::new_multi_thread() /// .enable_all() /// .build() /// .unwrap(); @@ -129,40 +152,45 @@ impl Builder { self } - /// Sets the number of threads the `Runtime` will use. When `val` is set to - /// `0` or `1` this will use a single-threaded runtime. When `val` is set to - /// some value `>1` it will create a work-stealing runtime. + /// Sets the number of worker threads the `Runtime` will use. /// /// This should be a number between 0 and 32,768 though it is advised to keep /// this value on the smaller side. /// + /// # Default + /// /// The default value is the number of cores available to the system. /// + /// # Panic + /// + /// When using the `current_thread` or `single_thread` runtime's this method will + /// panic, since those variants do not allow setting worker thread counts. + /// + /// /// # Examples /// - /// ## Work stealing runtime with 4 threads + /// ## Multi threaded runtime with 4 threads /// /// ``` /// use tokio::runtime; /// /// // This will spawn a work-stealing runtime with 4 worker threads. - /// let rt = runtime::Builder::new() - /// .core_threads(4) + /// let rt = runtime::Builder::new_multi_thread() + /// .worker_threads(4) /// .build() /// .unwrap(); /// /// rt.spawn(async move {}); /// ``` /// - /// ## Single threaded runtime on the current thread + /// ## Current thread runtime (will only run on the current thread via `Runtime::block_on`) /// /// ``` /// use tokio::runtime; /// /// // Create a runtime that _must_ be driven from a call /// // to `Runtime::block_on`. - /// let rt = runtime::Builder::new() - /// .core_threads(0) + /// let rt = runtime::Builder::new_current_thread() /// .build() /// .unwrap(); /// @@ -170,32 +198,31 @@ impl Builder { /// rt.block_on(async move {}); /// ``` /// - /// ## Single threaded runtime with 1 worker thread + /// ## Single threaded runtime /// /// ``` /// use tokio::runtime; /// /// // Spawn a single threaded runtime on a background thread. - /// let rt = runtime::Builder::new() - /// .core_threads(1) + /// let rt = runtime::Builder::new_single_thread() /// .build() /// .unwrap(); /// /// // This will run the future on the single worker thread. /// rt.spawn(async move {}); /// ``` - pub fn core_threads(&mut self, val: usize) -> &mut Self { - self.core_threads = Some(val); + pub fn worker_threads(&mut self, val: usize) -> &mut Self { + self.worker_threads = Some(val); self } /// Specifies limit for threads, spawned by the Runtime. /// /// This is number of threads to be used by Runtime, including `core_threads` - /// Having `max_threads` less than `core_threads` results in invalid configuration + /// Having `max_threads` less than `worker_threads` results in invalid configuration /// when building multi-threaded `Runtime`, which would cause a panic. /// - /// Similarly to the `core_threads`, this number should be between 0 and 32,768. + /// Similarly to the `worker_threads`, this number should be between 0 and 32,768. /// /// The default value is 512. /// @@ -218,7 +245,7 @@ impl Builder { /// # use tokio::runtime; /// /// # pub fn main() { - /// let rt = runtime::Builder::new() + /// let rt = runtime::Builder::new_multi_thread() /// .thread_name("my-pool") /// .build(); /// # } @@ -240,7 +267,7 @@ impl Builder { /// # use std::sync::atomic::{AtomicUsize, Ordering}; /// /// # pub fn main() { - /// let rt = runtime::Builder::new() + /// let rt = runtime::Builder::new_multi_thread() /// .thread_name_fn(|| { /// static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0); /// let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst); @@ -271,7 +298,7 @@ impl Builder { /// # use tokio::runtime; /// /// # pub fn main() { - /// let rt = runtime::Builder::new() + /// let rt = runtime::Builder::new_multi_thread() /// .thread_stack_size(32 * 1024) /// .build(); /// # } @@ -292,7 +319,7 @@ impl Builder { /// # use tokio::runtime; /// /// # pub fn main() { - /// let runtime = runtime::Builder::new() + /// let runtime = runtime::Builder::new_multi_thread() /// .on_thread_start(|| { /// println!("thread started"); /// }) @@ -318,7 +345,7 @@ impl Builder { /// # use tokio::runtime; /// /// # pub fn main() { - /// let runtime = runtime::Builder::new() + /// let runtime = runtime::Builder::new_multi_thread() /// .on_thread_stop(|| { /// println!("thread stopping"); /// }) @@ -343,26 +370,17 @@ impl Builder { /// ``` /// use tokio::runtime::Builder; /// - /// let rt = Builder::new().build().unwrap(); + /// let rt = Builder::new_multi_thread().build().unwrap(); /// /// rt.block_on(async { /// println!("Hello from the Tokio runtime"); /// }); /// ``` pub fn build(&mut self) -> io::Result { - match self.core_threads { - #[cfg(feature = "rt-core")] - Some(n) if n == 0 => self.build_basic_runtime(), - - #[cfg(feature = "rt-threaded")] - Some(_) | None => self.build_threaded_runtime(), - - #[cfg(not(feature = "rt-threaded"))] - #[cfg(feature = "rt-core")] - Some(_) | None => self.build_basic_runtime(), - - #[cfg(not(feature = "rt-core"))] - Some(_) | None => self.build_shell_runtime(), + match &self.kind { + Kind::SingleThread => self.build_basic_runtime(), + Kind::CurrentThread => self.build_basic_runtime(), + Kind::MultiThread => self.build_threaded_runtime(), } } @@ -373,7 +391,6 @@ impl Builder { } } - #[cfg_attr(feature = "rt-core", allow(dead_code))] fn build_shell_runtime(&mut self) -> io::Result { use crate::runtime::Kind; @@ -412,7 +429,7 @@ impl Builder { /// # use std::time::Duration; /// /// # pub fn main() { - /// let rt = runtime::Builder::new() + /// let rt = runtime::Builder::new_multi_thread() /// .thread_keep_alive(Duration::from_millis(100)) /// .build(); /// # } @@ -435,7 +452,7 @@ cfg_io_driver! { /// ``` /// use tokio::runtime; /// - /// let rt = runtime::Builder::new() + /// let rt = runtime::Builder::new_multi_thread() /// .enable_io() /// .build() /// .unwrap(); @@ -458,7 +475,7 @@ cfg_time! { /// ``` /// use tokio::runtime; /// - /// let rt = runtime::Builder::new() + /// let rt = runtime::Builder::new_multi_thread() /// .enable_time() /// .build() /// .unwrap(); @@ -512,7 +529,7 @@ cfg_rt_threaded! { use crate::runtime::park::Parker; use std::cmp; - let core_threads = self.core_threads.unwrap_or_else(|| cmp::min(self.max_threads, num_cpus())); + let core_threads = self.worker_threads.unwrap_or_else(|| cmp::min(self.max_threads, num_cpus())); assert!(core_threads <= self.max_threads, "Core threads number cannot be above max limit"); let (driver, resources) = driver::Driver::new(self.get_cfg())?; @@ -546,16 +563,10 @@ cfg_rt_threaded! { } } -impl Default for Builder { - fn default() -> Self { - Self::new() - } -} - impl fmt::Debug for Builder { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Builder") - .field("core_threads", &self.core_threads) + .field("worker_threads", &self.worker_threads) .field("max_threads", &self.max_threads) .field( "thread_name", diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 9e9496b1130..49ae167b0db 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -121,8 +121,7 @@ //! use tokio::runtime; //! //! # fn main() -> Result<(), Box> { -//! let basic_rt = runtime::Builder::new() -//! .core_threads(0) +//! let basic_rt = runtime::Builder::new_current_thread() //! .build()?; //! # Ok(()) } //! ``` @@ -345,13 +344,13 @@ impl Runtime { /// [runtime builder]: crate::runtime::Builder pub fn new() -> io::Result { #[cfg(feature = "rt-threaded")] - let ret = Builder::new().enable_all().build(); + let ret = Builder::new_multi_thread().enable_all().build(); #[cfg(all(not(feature = "rt-threaded"), feature = "rt-core"))] - let ret = Builder::new().core_threads(0).enable_all().build(); + let ret = Builder::new_single_thread().enable_all().build(); #[cfg(not(feature = "rt-core"))] - let ret = Builder::new().enable_all().build(); + let ret = Builder::new_current_thread().enable_all().build(); ret } diff --git a/tokio/src/signal/registry.rs b/tokio/src/signal/registry.rs index 94fd6955c20..5d6f608c607 100644 --- a/tokio/src/signal/registry.rs +++ b/tokio/src/signal/registry.rs @@ -306,7 +306,7 @@ mod tests { } fn rt() -> Runtime { - runtime::Builder::new().core_threads(0).build().unwrap() + runtime::Builder::new_current_thread().build().unwrap() } async fn collect(mut rx: crate::sync::mpsc::Receiver<()>) -> Vec<()> { diff --git a/tokio/tests/io_driver.rs b/tokio/tests/io_driver.rs index e630d0e6d0c..a32bb8aa1e4 100644 --- a/tokio/tests/io_driver.rs +++ b/tokio/tests/io_driver.rs @@ -45,8 +45,7 @@ fn test_drop_on_notify() { // shutting down. Then, when the task handle is dropped, the task itself is // dropped. - let rt = runtime::Builder::new() - .core_threads(0) + let rt = runtime::Builder::new_current_thread() .enable_all() .build() .unwrap(); diff --git a/tokio/tests/io_driver_drop.rs b/tokio/tests/io_driver_drop.rs index 8a6f5f8cd62..2d70288492a 100644 --- a/tokio/tests/io_driver_drop.rs +++ b/tokio/tests/io_driver_drop.rs @@ -45,8 +45,7 @@ fn drop_wakes() { } fn rt() -> runtime::Runtime { - runtime::Builder::new() - .core_threads(0) + runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() diff --git a/tokio/tests/rt_basic.rs b/tokio/tests/rt_basic.rs index e7364b96f51..7b5b622b63f 100644 --- a/tokio/tests/rt_basic.rs +++ b/tokio/tests/rt_basic.rs @@ -129,8 +129,7 @@ fn acquire_mutex_in_drop() { } fn rt() -> Runtime { - tokio::runtime::Builder::new() - .core_threads(0) + tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() diff --git a/tokio/tests/rt_common.rs b/tokio/tests/rt_common.rs index 7032e381cdc..66b2c66d9a6 100644 --- a/tokio/tests/rt_common.rs +++ b/tokio/tests/rt_common.rs @@ -6,12 +6,23 @@ macro_rules! rt_test { ($($t:tt)*) => { - mod basic_scheduler { + mod current_thread_scheduler { $($t)* fn rt() -> Arc { - tokio::runtime::Builder::new() - .core_threads(0) + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .into() + } + } + + mod single_thread_scheduler { + $($t)* + + fn rt() -> Arc { + tokio::runtime::Builder::new_single_thread() .enable_all() .build() .unwrap() @@ -23,8 +34,8 @@ macro_rules! rt_test { $($t)* fn rt() -> Arc { - tokio::runtime::Builder::new() - .core_threads(4) + tokio::runtime::Builder::new_multi_thread() + .worker_threads(4) .enable_all() .build() .unwrap() @@ -36,8 +47,8 @@ macro_rules! rt_test { $($t)* fn rt() -> Arc { - tokio::runtime::Builder::new() - .core_threads(1) + tokio::runtime::Builder::new_multi_thread() + .worker_threads(1) .enable_all() .build() .unwrap() diff --git a/tokio/tests/rt_threaded.rs b/tokio/tests/rt_threaded.rs index 3d5b7529f84..c14c4856146 100644 --- a/tokio/tests/rt_threaded.rs +++ b/tokio/tests/rt_threaded.rs @@ -18,7 +18,10 @@ use std::task::{Context, Poll}; #[test] fn single_thread() { // No panic when starting a runtime w/ a single thread - let _ = runtime::Builder::new().enable_all().core_threads(1).build(); + let _ = runtime::Builder::new_multi_thread() + .enable_all() + .worker_threads(1) + .build(); } #[test] @@ -184,7 +187,7 @@ fn drop_threadpool_drops_futures() { let a = num_inc.clone(); let b = num_dec.clone(); - let rt = runtime::Builder::new() + let rt = runtime::Builder::new_multi_thread() .enable_all() .on_thread_start(move || { a.fetch_add(1, Relaxed); @@ -223,7 +226,7 @@ fn start_stop_callbacks_called() { let after_inner = after_start.clone(); let before_inner = before_stop.clone(); - let rt = tokio::runtime::Builder::new() + let rt = tokio::runtime::Builder::new_multi_thread() .enable_all() .on_thread_start(move || { after_inner.clone().fetch_add(1, Ordering::Relaxed); @@ -323,7 +326,7 @@ fn multi_threadpool() { // channel yields occasionally even if there are values ready to receive. #[test] fn coop_and_block_in_place() { - let rt = tokio::runtime::Builder::new() + let rt = tokio::runtime::Builder::new_multi_thread() // Setting max threads to 1 prevents another thread from claiming the // runtime worker yielded as part of `block_in_place` and guarantees the // same thread will reclaim the worker at the end of the @@ -373,7 +376,7 @@ fn coop_and_block_in_place() { // Testing this does not panic #[test] fn max_threads() { - let _rt = tokio::runtime::Builder::new() + let _rt = tokio::runtime::Builder::new_multi_thread() .max_threads(1) .build() .unwrap(); diff --git a/tokio/tests/signal_drop_rt.rs b/tokio/tests/signal_drop_rt.rs index 1bf6dd6a0b9..b931d7a9033 100644 --- a/tokio/tests/signal_drop_rt.rs +++ b/tokio/tests/signal_drop_rt.rs @@ -37,8 +37,7 @@ fn dropping_loops_does_not_cause_starvation() { } fn rt() -> Runtime { - tokio::runtime::Builder::new() - .core_threads(0) + tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() diff --git a/tokio/tests/signal_multi_rt.rs b/tokio/tests/signal_multi_rt.rs index 051c8b0da51..1e0402c4794 100644 --- a/tokio/tests/signal_multi_rt.rs +++ b/tokio/tests/signal_multi_rt.rs @@ -47,8 +47,7 @@ fn multi_loop() { } fn rt() -> Runtime { - tokio::runtime::Builder::new() - .core_threads(0) + tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() diff --git a/tokio/tests/task_blocking.rs b/tokio/tests/task_blocking.rs index be1e2ce7095..97d4c1b1cf3 100644 --- a/tokio/tests/task_blocking.rs +++ b/tokio/tests/task_blocking.rs @@ -88,7 +88,7 @@ fn yes_block_in_threaded_block_on() { #[test] #[should_panic] fn no_block_in_basic_block_on() { - let rt = runtime::Builder::new().core_threads(0).build().unwrap(); + let rt = runtime::Builder::new_current_thread().build().unwrap(); rt.block_on(async { task::block_in_place(|| {}); }); @@ -100,8 +100,7 @@ fn can_enter_basic_rt_from_within_block_in_place() { outer.block_on(async { tokio::task::block_in_place(|| { - let inner = tokio::runtime::Builder::new() - .core_threads(0) + let inner = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); @@ -118,8 +117,7 @@ fn useful_panic_message_when_dropping_rt_in_rt() { let result = catch_unwind(AssertUnwindSafe(|| { outer.block_on(async { - let _ = tokio::runtime::Builder::new() - .core_threads(0) + let _ = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); }); @@ -141,8 +139,7 @@ fn can_shutdown_with_zero_timeout_in_runtime() { let outer = tokio::runtime::Runtime::new().unwrap(); outer.block_on(async { - let rt = tokio::runtime::Builder::new() - .core_threads(0) + let rt = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); rt.shutdown_timeout(Duration::from_nanos(0)); @@ -154,8 +151,7 @@ fn can_shutdown_now_in_runtime() { let outer = tokio::runtime::Runtime::new().unwrap(); outer.block_on(async { - let rt = tokio::runtime::Builder::new() - .core_threads(0) + let rt = tokio::runtime::Builder::new_current_thread() .build() .unwrap(); rt.shutdown_background(); @@ -164,7 +160,7 @@ fn can_shutdown_now_in_runtime() { #[test] fn coop_disabled_in_block_in_place() { - let outer = tokio::runtime::Builder::new() + let outer = tokio::runtime::Builder::new_multi_thread() .enable_time() .build() .unwrap(); diff --git a/tokio/tests/task_local_set.rs b/tokio/tests/task_local_set.rs index 443ca0f585f..c7ecd929b8c 100644 --- a/tokio/tests/task_local_set.rs +++ b/tokio/tests/task_local_set.rs @@ -133,7 +133,10 @@ fn local_threadpool_blocking_in_place() { ON_RT_THREAD.with(|cell| cell.set(true)); - let rt = runtime::Builder::new().enable_all().build().unwrap(); + let rt = runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); LocalSet::new().block_on(&rt, async { assert!(ON_RT_THREAD.with(|cell| cell.get())); let join = task::spawn_local(async move { @@ -484,8 +487,7 @@ async fn acquire_mutex_in_drop() { } fn rt() -> Runtime { - tokio::runtime::Builder::new() - .core_threads(0) + tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() diff --git a/tokio/tests/time_rt.rs b/tokio/tests/time_rt.rs index dfae7117cae..908b7f24197 100644 --- a/tokio/tests/time_rt.rs +++ b/tokio/tests/time_rt.rs @@ -28,7 +28,7 @@ fn timer_with_threaded_runtime() { fn timer_with_basic_scheduler() { use tokio::runtime::Builder; - let rt = Builder::new().core_threads(0).enable_all().build().unwrap(); + let rt = Builder::new_current_thread().enable_all().build().unwrap(); let (tx, rx) = mpsc::channel(); rt.block_on(async move { From 45c497707de28ce1ab73968e1d8421073b1c6abe Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Wed, 7 Oct 2020 19:07:26 +0000 Subject: [PATCH 13/39] Add runtime builders --- tokio-macros/src/entry.rs | 4 +- tokio-macros/src/lib.rs | 2 +- tokio/src/runtime/builder.rs | 47 +++++++++++---------- tokio/src/runtime/mod.rs | 76 +++++++++------------------------- tokio/src/signal/registry.rs | 2 +- tokio/src/sync/mpsc/bounded.rs | 4 +- tokio/src/task/local.rs | 4 +- tokio/tests/rt_threaded.rs | 2 +- tokio/tests/sync_mpsc.rs | 4 +- tokio/tests/task_blocking.rs | 12 +++--- tokio/tests/task_local_set.rs | 2 +- tokio/tests/time_rt.rs | 2 +- 12 files changed, 62 insertions(+), 99 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 7634c9688c7..fd7b021d136 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -272,7 +272,7 @@ pub(crate) mod old { Runtime::Threaded | Runtime::Auto => quote! { #(#attrs)* #vis #sig { - tokio::runtime::Runtime::new().unwrap().block_on(async { #body }) + tokio::runtime::Runtime::new_multi_thread().unwrap().block_on(async { #body }) } }, Runtime::Basic => quote! { @@ -346,7 +346,7 @@ pub(crate) mod old { #[::core::prelude::v1::test] #(#attrs)* #vis fn #name() #ret { - tokio::runtime::Runtime::new().unwrap().block_on(async { #body }) + tokio::runtime::Runtime::new_multi_thread().unwrap().block_on(async { #body }) } }, Runtime::Basic | Runtime::Auto => quote! { diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 77eaaf78a41..05e1471ba82 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -167,7 +167,7 @@ pub fn main_threaded(args: TokenStream, item: TokenStream) -> TokenStream { /// /// ```rust /// fn main() { -/// tokio::runtime::Runtime::new() +/// tokio::runtime::Runtime::new_multi_thread() /// .unwrap() /// .block_on(async { /// println!("Hello world"); diff --git a/tokio/src/runtime/builder.rs b/tokio/src/runtime/builder.rs index 7c4812a2f59..1f30838f26a 100644 --- a/tokio/src/runtime/builder.rs +++ b/tokio/src/runtime/builder.rs @@ -89,6 +89,7 @@ impl Builder { Builder::new(Kind::SingleThread) } + #[cfg(feature = "rt-threaded")] pub fn new_multi_thread() -> Builder { Builder::new(Kind::MultiThread) } @@ -391,29 +392,29 @@ impl Builder { } } - fn build_shell_runtime(&mut self) -> io::Result { - use crate::runtime::Kind; - - let (driver, resources) = driver::Driver::new(self.get_cfg())?; - - let spawner = Spawner::Shell; - - let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); - let blocking_spawner = blocking_pool.spawner().clone(); - - Ok(Runtime { - kind: Kind::Shell(Shell::new(driver)), - handle: Handle { - spawner, - io_handle: resources.io_handle, - time_handle: resources.time_handle, - signal_handle: resources.signal_handle, - clock: resources.clock, - blocking_spawner, - }, - blocking_pool, - }) - } + // fn build_shell_runtime(&mut self) -> io::Result { + // use crate::runtime::Kind; + + // let (driver, resources) = driver::Driver::new(self.get_cfg())?; + + // let spawner = Spawner::Shell; + + // let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); + // let blocking_spawner = blocking_pool.spawner().clone(); + + // Ok(Runtime { + // kind: Kind::Shell(Shell::new(driver)), + // handle: Handle { + // spawner, + // io_handle: resources.io_handle, + // time_handle: resources.time_handle, + // signal_handle: resources.signal_handle, + // clock: resources.clock, + // blocking_spawner, + // }, + // blocking_pool, + // }) + // } #[cfg(feature = "blocking")] #[cfg_attr(docsrs, doc(cfg(feature = "blocking")))] diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 49ae167b0db..dc9a4c82504 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -69,7 +69,7 @@ //! //! fn main() -> Result<(), Box> { //! // Create the runtime -//! let rt = Runtime::new()?; +//! let rt = Runtime::new_multi_thread()?; //! //! // Spawn the root task //! rt.block_on(async { @@ -144,13 +144,10 @@ //! use tokio::runtime; //! //! # fn main() -> Result<(), Box> { -//! let threaded_rt = runtime::Runtime::new()?; +//! let threaded_rt = runtime::Runtime::new_multi_thread()?; //! # Ok(()) } //! ``` //! -//! If the `rt-threaded` feature flag is enabled, [`Runtime::new`] will return a -//! threaded scheduler runtime by default. -//! //! Most applications should use the threaded scheduler, except in some niche //! use-cases, such as when running only a single thread is required. //! @@ -252,8 +249,9 @@ use std::time::Duration; /// The runtime provides an I/O driver, task scheduler, [timer], and blocking /// pool, necessary for running asynchronous tasks. /// -/// Instances of `Runtime` can be created using [`new`] or [`Builder`]. However, -/// most users will use the `#[tokio::main]` annotation on their entry point instead. +/// Instances of `Runtime` can be created using [`new_multi_thread`], [`new_current_thread`], +/// [`new_single_thread`], or [`Builder`]. However, most users will use the `#[tokio::main]` +/// annotation on their entry point instead. /// /// See [module level][mod] documentation for more details. /// @@ -307,52 +305,16 @@ enum Kind { type Callback = std::sync::Arc; impl Runtime { - /// Create a new runtime instance with default configuration values. - /// - /// This results in a scheduler, I/O driver, and time driver being - /// initialized. The type of scheduler used depends on what feature flags - /// are enabled: if the `rt-threaded` feature is enabled, the [threaded - /// scheduler] is used, while if only the `rt-core` feature is enabled, the - /// [basic scheduler] is used instead. - /// - /// If the threaded scheduler is selected, it will not spawn - /// any worker threads until it needs to, i.e. tasks are scheduled to run. - /// - /// Most applications will not need to call this function directly. Instead, - /// they will use the [`#[tokio::main]` attribute][main]. When more complex - /// configuration is necessary, the [runtime builder] may be used. - /// - /// See [module level][mod] documentation for more details. - /// - /// # Examples - /// - /// Creating a new `Runtime` with default configuration values. - /// - /// ``` - /// use tokio::runtime::Runtime; - /// - /// let rt = Runtime::new() - /// .unwrap(); - /// - /// // Use the runtime... - /// ``` - /// - /// [mod]: index.html - /// [main]: ../attr.main.html - /// [threaded scheduler]: index.html#threaded-scheduler - /// [basic scheduler]: index.html#basic-scheduler - /// [runtime builder]: crate::runtime::Builder - pub fn new() -> io::Result { - #[cfg(feature = "rt-threaded")] - let ret = Builder::new_multi_thread().enable_all().build(); - - #[cfg(all(not(feature = "rt-threaded"), feature = "rt-core"))] - let ret = Builder::new_single_thread().enable_all().build(); + pub fn new_multi_thread() -> io::Result { + Builder::new_multi_thread().enable_all().build() + } - #[cfg(not(feature = "rt-core"))] - let ret = Builder::new_current_thread().enable_all().build(); + pub fn new_single_thread() -> io::Result { + Builder::new_multi_thread().enable_all().build() + } - ret + pub fn new_current_thread() -> io::Result { + Builder::new_multi_thread().enable_all().build() } /// Spawn a future onto the Tokio runtime. @@ -372,7 +334,7 @@ impl Runtime { /// /// # fn dox() { /// // Create the runtime - /// let rt = Runtime::new().unwrap(); + /// let rt = Runtime::new_multi_thread().unwrap(); /// /// // Spawn a future onto the runtime /// rt.spawn(async { @@ -425,7 +387,7 @@ impl Runtime { /// use tokio::runtime::Runtime; /// /// // Create the runtime - /// let rt = Runtime::new().unwrap(); + /// let rt = Runtime::new_multi_thread().unwrap(); /// /// // Execute the future, blocking the current thread until completion /// rt.block_on(async { @@ -465,7 +427,7 @@ impl Runtime { /// } /// /// fn main() { - /// let rt = Runtime::new().unwrap(); + /// let rt = Runtime::new_multi_thread().unwrap(); /// /// let s = "Hello World!".to_string(); /// @@ -504,7 +466,7 @@ impl Runtime { /// use std::time::Duration; /// /// fn main() { - /// let runtime = Runtime::new().unwrap(); + /// let runtime = Runtime::new_multi_thread().unwrap(); /// /// runtime.block_on(async move { /// task::spawn_blocking(move || { @@ -538,10 +500,10 @@ impl Runtime { /// use tokio::runtime::Runtime; /// /// fn main() { - /// let runtime = Runtime::new().unwrap(); + /// let runtime = Runtime::new_multi_thread().unwrap(); /// /// runtime.block_on(async move { - /// let inner_runtime = Runtime::new().unwrap(); + /// let inner_runtime = Runtime::new_multi_thread().unwrap(); /// // ... /// inner_runtime.shutdown_background(); /// }); diff --git a/tokio/src/signal/registry.rs b/tokio/src/signal/registry.rs index 5d6f608c607..bc8473040d1 100644 --- a/tokio/src/signal/registry.rs +++ b/tokio/src/signal/registry.rs @@ -247,7 +247,7 @@ mod tests { #[test] fn broadcast_cleans_up_disconnected_listeners() { - let rt = Runtime::new().unwrap(); + let rt = Runtime::new_multi_thread().unwrap(); rt.block_on(async { let registry = Registry::new(vec![EventInfo::default()]); diff --git a/tokio/src/sync/mpsc/bounded.rs b/tokio/src/sync/mpsc/bounded.rs index 14e4731aaae..95b2089c1ef 100644 --- a/tokio/src/sync/mpsc/bounded.rs +++ b/tokio/src/sync/mpsc/bounded.rs @@ -184,7 +184,7 @@ impl Receiver { /// assert_eq!(Some(10), rx.blocking_recv()); /// }); /// - /// Runtime::new() + /// Runtime::new_multi_thread() /// .unwrap() /// .block_on(async move { /// let _ = tx.send(10).await; @@ -456,7 +456,7 @@ impl Sender { /// tx.blocking_send(10).unwrap(); /// }); /// - /// Runtime::new().unwrap().block_on(async move { + /// Runtime::new_multi_thread().unwrap().block_on(async move { /// assert_eq!(Some(10), rx.recv().await); /// }); /// sync_code.join().unwrap() diff --git a/tokio/src/task/local.rs b/tokio/src/task/local.rs index 1d7b99d500b..923e0c21701 100644 --- a/tokio/src/task/local.rs +++ b/tokio/src/task/local.rs @@ -312,7 +312,7 @@ impl LocalSet { /// use tokio::runtime::Runtime; /// use tokio::task; /// - /// let rt = Runtime::new().unwrap(); + /// let rt = Runtime::new_multi_thread().unwrap(); /// let local = task::LocalSet::new(); /// local.block_on(&rt, async { /// let join = task::spawn_local(async { @@ -329,7 +329,7 @@ impl LocalSet { /// use tokio::runtime::Runtime; /// use tokio::task; /// - /// let rt = Runtime::new().unwrap(); + /// let rt = Runtime::new_multi_thread().unwrap(); /// let local = task::LocalSet::new(); /// local.block_on(&rt, async { /// let join = task::spawn_local(async { diff --git a/tokio/tests/rt_threaded.rs b/tokio/tests/rt_threaded.rs index c14c4856146..335f7e3331f 100644 --- a/tokio/tests/rt_threaded.rs +++ b/tokio/tests/rt_threaded.rs @@ -383,5 +383,5 @@ fn max_threads() { } fn rt() -> Runtime { - Runtime::new().unwrap() + Runtime::new_multi_thread().unwrap() } diff --git a/tokio/tests/sync_mpsc.rs b/tokio/tests/sync_mpsc.rs index 919bddbfb18..ab2969bc4cd 100644 --- a/tokio/tests/sync_mpsc.rs +++ b/tokio/tests/sync_mpsc.rs @@ -501,7 +501,7 @@ fn blocking_recv() { assert_eq!(Some(10), rx.blocking_recv()); }); - Runtime::new().unwrap().block_on(async move { + Runtime::new_multi_thread().unwrap().block_on(async move { let _ = tx.send(10).await; }); sync_code.join().unwrap() @@ -522,7 +522,7 @@ fn blocking_send() { tx.blocking_send(10).unwrap(); }); - Runtime::new().unwrap().block_on(async move { + Runtime::new_multi_thread().unwrap().block_on(async move { assert_eq!(Some(10), rx.recv().await); }); sync_code.join().unwrap() diff --git a/tokio/tests/task_blocking.rs b/tokio/tests/task_blocking.rs index 97d4c1b1cf3..337bb703d1f 100644 --- a/tokio/tests/task_blocking.rs +++ b/tokio/tests/task_blocking.rs @@ -79,7 +79,7 @@ async fn no_block_in_basic_scheduler() { #[test] fn yes_block_in_threaded_block_on() { - let rt = runtime::Runtime::new().unwrap(); + let rt = runtime::Runtime::new_multi_thread().unwrap(); rt.block_on(async { task::block_in_place(|| {}); }); @@ -96,7 +96,7 @@ fn no_block_in_basic_block_on() { #[test] fn can_enter_basic_rt_from_within_block_in_place() { - let outer = tokio::runtime::Runtime::new().unwrap(); + let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); outer.block_on(async { tokio::task::block_in_place(|| { @@ -113,7 +113,7 @@ fn can_enter_basic_rt_from_within_block_in_place() { fn useful_panic_message_when_dropping_rt_in_rt() { use std::panic::{catch_unwind, AssertUnwindSafe}; - let outer = tokio::runtime::Runtime::new().unwrap(); + let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); let result = catch_unwind(AssertUnwindSafe(|| { outer.block_on(async { @@ -136,7 +136,7 @@ fn useful_panic_message_when_dropping_rt_in_rt() { #[test] fn can_shutdown_with_zero_timeout_in_runtime() { - let outer = tokio::runtime::Runtime::new().unwrap(); + let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); outer.block_on(async { let rt = tokio::runtime::Builder::new_current_thread() @@ -148,7 +148,7 @@ fn can_shutdown_with_zero_timeout_in_runtime() { #[test] fn can_shutdown_now_in_runtime() { - let outer = tokio::runtime::Runtime::new().unwrap(); + let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); outer.block_on(async { let rt = tokio::runtime::Builder::new_current_thread() @@ -193,7 +193,7 @@ fn coop_disabled_in_block_in_place_in_block_on() { let (done_tx, done_rx) = std::sync::mpsc::channel(); let done = done_tx.clone(); thread::spawn(move || { - let outer = tokio::runtime::Runtime::new().unwrap(); + let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); for i in 0..200 { diff --git a/tokio/tests/task_local_set.rs b/tokio/tests/task_local_set.rs index c7ecd929b8c..f535e89db41 100644 --- a/tokio/tests/task_local_set.rs +++ b/tokio/tests/task_local_set.rs @@ -245,7 +245,7 @@ fn join_local_future_elsewhere() { ON_RT_THREAD.with(|cell| cell.set(true)); - let rt = runtime::Runtime::new().unwrap(); + let rt = runtime::Runtime::new_multi_thread().unwrap(); let local = LocalSet::new(); local.block_on(&rt, async move { let (tx, rx) = oneshot::channel(); diff --git a/tokio/tests/time_rt.rs b/tokio/tests/time_rt.rs index 908b7f24197..d3d7419bdd5 100644 --- a/tokio/tests/time_rt.rs +++ b/tokio/tests/time_rt.rs @@ -9,7 +9,7 @@ use std::sync::mpsc; fn timer_with_threaded_runtime() { use tokio::runtime::Runtime; - let rt = Runtime::new().unwrap(); + let rt = Runtime::new_multi_thread().unwrap(); let (tx, rx) = mpsc::channel(); rt.spawn(async move { From 2178252d4eaeb35490b322a3d36ad1fdb71e1eec Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Wed, 7 Oct 2020 19:51:22 +0000 Subject: [PATCH 14/39] remove shell runtime --- benches/mpsc.rs | 2 +- tokio/src/runtime/builder.rs | 109 +++++++++++++++++++---------------- tokio/src/runtime/mod.rs | 24 ++++---- tokio/src/runtime/spawner.rs | 2 - 4 files changed, 71 insertions(+), 66 deletions(-) diff --git a/benches/mpsc.rs b/benches/mpsc.rs index 62a76ef6c84..610a90f4ac7 100644 --- a/benches/mpsc.rs +++ b/benches/mpsc.rs @@ -52,7 +52,7 @@ fn send_large(b: &mut Bencher) { fn contention_bounded(b: &mut Bencher) { let rt = rt(); - let rt = b.iter(|| { + b.iter(|| { rt.block_on(async move { let (tx, mut rx) = mpsc::channel::(1_000_000); diff --git a/tokio/src/runtime/builder.rs b/tokio/src/runtime/builder.rs index 1f30838f26a..7d6f3c6184e 100644 --- a/tokio/src/runtime/builder.rs +++ b/tokio/src/runtime/builder.rs @@ -1,5 +1,4 @@ use crate::runtime::handle::Handle; -use crate::runtime::shell::Shell; use crate::runtime::{blocking, driver, io, Callback, Runtime, Spawner}; use std::fmt; @@ -379,8 +378,8 @@ impl Builder { /// ``` pub fn build(&mut self) -> io::Result { match &self.kind { - Kind::SingleThread => self.build_basic_runtime(), - Kind::CurrentThread => self.build_basic_runtime(), + Kind::CurrentThread => self.build_basic_runtime(true), + Kind::SingleThread => self.build_basic_runtime(false), Kind::MultiThread => self.build_threaded_runtime(), } } @@ -392,30 +391,6 @@ impl Builder { } } - // fn build_shell_runtime(&mut self) -> io::Result { - // use crate::runtime::Kind; - - // let (driver, resources) = driver::Driver::new(self.get_cfg())?; - - // let spawner = Spawner::Shell; - - // let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); - // let blocking_spawner = blocking_pool.spawner().clone(); - - // Ok(Runtime { - // kind: Kind::Shell(Shell::new(driver)), - // handle: Handle { - // spawner, - // io_handle: resources.io_handle, - // time_handle: resources.time_handle, - // signal_handle: resources.signal_handle, - // clock: resources.clock, - // blocking_spawner, - // }, - // blocking_pool, - // }) - // } - #[cfg(feature = "blocking")] #[cfg_attr(docsrs, doc(cfg(feature = "blocking")))] /// Sets a custom timeout for a thread in the blocking pool. @@ -490,34 +465,66 @@ cfg_time! { cfg_rt_core! { impl Builder { - fn build_basic_runtime(&mut self) -> io::Result { + fn build_basic_runtime(&mut self, current_thread: bool) -> io::Result { use crate::runtime::{BasicScheduler, Kind}; let (driver, resources) = driver::Driver::new(self.get_cfg())?; - // And now put a single-threaded scheduler on top of the timer. When - // there are no futures ready to do something, it'll let the timer or - // the reactor to generate some new stimuli for the futures to continue - // in their life. - let scheduler = BasicScheduler::new(driver); - let spawner = Spawner::Basic(scheduler.spawner().clone()); - - // Blocking pool - let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); - let blocking_spawner = blocking_pool.spawner().clone(); - - Ok(Runtime { - kind: Kind::Basic(scheduler), - handle: Handle { - spawner, - io_handle: resources.io_handle, - time_handle: resources.time_handle, - signal_handle: resources.signal_handle, - clock: resources.clock, - blocking_spawner, - }, - blocking_pool, - }) + if current_thread { + // And now put a single-threaded scheduler on top of the timer. When + // there are no futures ready to do something, it'll let the timer or + // the reactor to generate some new stimuli for the futures to continue + // in their life. + let scheduler = BasicScheduler::new(driver); + let spawner = Spawner::Basic(scheduler.spawner().clone()); + + // Blocking pool + let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); + let blocking_spawner = blocking_pool.spawner().clone(); + + Ok(Runtime { + kind: Kind::CurrentThread(scheduler), + handle: Handle { + spawner, + io_handle: resources.io_handle, + time_handle: resources.time_handle, + signal_handle: resources.signal_handle, + clock: resources.clock, + blocking_spawner, + }, + blocking_pool, + }) + } else { + use crate::loom::sync::Arc; + // use crate::future::poll_fn; + // use std::task::Poll; + + let scheduler = Arc::new(BasicScheduler::new(driver)); + let spawner = Spawner::Basic(scheduler.spawner().clone()); + + // Blocking pool + let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); + let blocking_spawner = blocking_pool.spawner().clone(); + + // TODO(lucio): fix this in the basic scheduler + // let scheduler2 = scheduler.clone(); + // std::thread::spawn(move || { + // scheduler2.block_on(poll_fn::<(), _>(|_| Poll::Pending)); + // }); + + Ok(Runtime { + kind: Kind::SingleThread(scheduler), + handle: Handle { + spawner, + io_handle: resources.io_handle, + time_handle: resources.time_handle, + signal_handle: resources.signal_handle, + clock: resources.clock, + blocking_spawner, + }, + blocking_pool, + }) + } } } } diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index dc9a4c82504..4ecf500b0b3 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -181,6 +181,8 @@ //! [`Builder::enable_time`]: crate::runtime::Builder::enable_time //! [`Builder::enable_all`]: crate::runtime::Builder::enable_all +#![allow(missing_docs)] + // At the top due to macros #[cfg(test)] #[macro_use] @@ -224,9 +226,6 @@ cfg_rt_threaded! { use park::Parker; } -mod shell; -use self::shell::Shell; - mod spawner; use self::spawner::Spawner; @@ -239,6 +238,7 @@ cfg_rt_threaded! { cfg_rt_core! { use crate::task::JoinHandle; + use crate::loom::sync::Arc; } use std::future::Future; @@ -288,13 +288,12 @@ pub struct Runtime { /// The runtime executor is either a thread-pool or a current-thread executor. #[derive(Debug)] enum Kind { - /// Not able to execute concurrent tasks. This variant is mostly used to get - /// access to the driver handles. - Shell(Shell), - /// Execute all tasks on the current-thread. #[cfg(feature = "rt-core")] - Basic(BasicScheduler), + CurrentThread(BasicScheduler), + + #[cfg(feature = "rt-core")] + SingleThread(Arc>), /// Execute tasks across multiple threads. #[cfg(feature = "rt-threaded")] @@ -354,10 +353,10 @@ impl Runtime { F::Output: Send + 'static, { match &self.kind { - Kind::Shell(_) => panic!("task execution disabled"), #[cfg(feature = "rt-threaded")] Kind::ThreadPool(exec) => exec.spawn(future), - Kind::Basic(exec) => exec.spawn(future), + Kind::CurrentThread(exec) => exec.spawn(future), + Kind::SingleThread(exec) => exec.spawn(future), } } @@ -398,9 +397,10 @@ impl Runtime { /// [handle]: fn@Handle::block_on pub fn block_on(&self, future: F) -> F::Output { self.handle.enter(|| match &self.kind { - Kind::Shell(exec) => exec.block_on(future), #[cfg(feature = "rt-core")] - Kind::Basic(exec) => exec.block_on(future), + Kind::CurrentThread(exec) => exec.block_on(future), + #[cfg(feature = "rt-core")] + Kind::SingleThread(exec) => exec.block_on(future), #[cfg(feature = "rt-threaded")] Kind::ThreadPool(exec) => exec.block_on(future), }) diff --git a/tokio/src/runtime/spawner.rs b/tokio/src/runtime/spawner.rs index c5f2d17cdd3..28ff7c04460 100644 --- a/tokio/src/runtime/spawner.rs +++ b/tokio/src/runtime/spawner.rs @@ -11,7 +11,6 @@ cfg_rt_threaded! { #[derive(Debug, Clone)] pub(crate) enum Spawner { - Shell, #[cfg(feature = "rt-core")] Basic(basic_scheduler::Spawner), #[cfg(feature = "rt-threaded")] @@ -37,7 +36,6 @@ cfg_rt_core! { F::Output: Send + 'static, { match self { - Spawner::Shell => panic!("spawning not enabled for runtime"), #[cfg(feature = "rt-core")] Spawner::Basic(spawner) => spawner.spawn(future), #[cfg(feature = "rt-threaded")] From 97717ac6864ab2c090d03e189a0e3b72c64002a7 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 7 Oct 2020 22:50:54 +0200 Subject: [PATCH 15/39] Remove shell runtime test --- tests-integration/tests/macros_main.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/tests-integration/tests/macros_main.rs b/tests-integration/tests/macros_main.rs index 42f5be3bde0..868adb0f056 100644 --- a/tests-integration/tests/macros_main.rs +++ b/tests-integration/tests/macros_main.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "macros")] +#![cfg(all(feature = "macros", feature = "rt-core"))] #[tokio::main] async fn basic_main() -> usize { @@ -10,18 +10,15 @@ async fn generic_fun() -> T { T::default() } -#[cfg(feature = "rt-core")] -mod spawn { - #[tokio::main] - async fn spawning() -> usize { - let join = tokio::spawn(async { 1 }); - join.await.unwrap() - } +#[tokio::main] +async fn spawning() -> usize { + let join = tokio::spawn(async { 1 }); + join.await.unwrap() +} - #[test] - fn main_with_spawn() { - assert_eq!(1, spawning()); - } +#[test] +fn main_with_spawn() { + assert_eq!(1, spawning()); } #[test] From 0a8c40140796b9072dc8db2814cb7a771c3133ac Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Fri, 9 Oct 2020 17:22:01 +0000 Subject: [PATCH 16/39] more feature flag mess --- tokio-util/Cargo.toml | 1 + tokio-util/src/cfg.rs | 10 +++ tokio-util/src/lib.rs | 4 +- tokio-util/tests/context.rs | 1 + tokio/src/coop.rs | 44 +++++----- tokio/src/io/driver/mod.rs | 38 ++++++--- tokio/src/lib.rs | 4 +- tokio/src/loom/mod.rs | 2 + tokio/src/park/mod.rs | 9 +- tokio/src/runtime/builder.rs | 130 +++++++++++++++-------------- tokio/src/runtime/mod.rs | 19 ++--- tokio/src/signal/unix/driver.rs | 43 +++++++--- tokio/src/sync/mod.rs | 6 +- tokio/src/sync/mpsc/bounded.rs | 140 +++++++++++++++++--------------- tokio/src/time/driver/handle.rs | 72 +++++++++++----- tokio/src/util/mod.rs | 6 +- 16 files changed, 312 insertions(+), 217 deletions(-) diff --git a/tokio-util/Cargo.toml b/tokio-util/Cargo.toml index 45daa2b13cc..9c99444e41a 100644 --- a/tokio-util/Cargo.toml +++ b/tokio-util/Cargo.toml @@ -30,6 +30,7 @@ full = ["codec", "compat", "io"] compat = ["futures-io",] codec = ["tokio/stream"] io = [] +rt-core = ["tokio/rt-core"] [dependencies] tokio = { version = "0.3.0", path = "../tokio" } diff --git a/tokio-util/src/cfg.rs b/tokio-util/src/cfg.rs index f9176747902..a848223f66e 100644 --- a/tokio-util/src/cfg.rs +++ b/tokio-util/src/cfg.rs @@ -39,3 +39,13 @@ macro_rules! cfg_io { )* } } + +macro_rules! cfg_rt_core { + ($($item:item)*) => { + $( + #[cfg(feature = "rt-core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rt-core")))] + $item + )* + } +} diff --git a/tokio-util/src/lib.rs b/tokio-util/src/lib.rs index b96d9044ea1..07fe28456ca 100644 --- a/tokio-util/src/lib.rs +++ b/tokio-util/src/lib.rs @@ -47,7 +47,9 @@ cfg_io! { pub mod io; } -pub mod context; +cfg_rt_core! { + pub mod context; +} pub mod sync; diff --git a/tokio-util/tests/context.rs b/tokio-util/tests/context.rs index 375941ec26f..6903348d8ff 100644 --- a/tokio-util/tests/context.rs +++ b/tokio-util/tests/context.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "rt-core")] #![warn(rust_2018_idioms)] use tokio::runtime::Builder; diff --git a/tokio/src/coop.rs b/tokio/src/coop.rs index 27e969c59d4..5a7ba5fdd17 100644 --- a/tokio/src/coop.rs +++ b/tokio/src/coop.rs @@ -61,26 +61,30 @@ thread_local! { pub(crate) struct Budget(Option); impl Budget { - /// Budget assigned to a task on each poll. - /// - /// The value itself is chosen somewhat arbitrarily. It needs to be high - /// enough to amortize wakeup and scheduling costs, but low enough that we - /// do not starve other tasks for too long. The value also needs to be high - /// enough that particularly deep tasks are able to do at least some useful - /// work at all. - /// - /// Note that as more yield points are added in the ecosystem, this value - /// will probably also have to be raised. - const fn initial() -> Budget { - Budget(Some(128)) - } - /// Returns an unconstrained budget. Operations will not be limited. const fn unconstrained() -> Budget { Budget(None) } } +cfg_rt_core! { + impl Budget { + /// Budget assigned to a task on each poll. + /// + /// The value itself is chosen somewhat arbitrarily. It needs to be high + /// enough to amortize wakeup and scheduling costs, but low enough that we + /// do not starve other tasks for too long. The value also needs to be high + /// enough that particularly deep tasks are able to do at least some useful + /// work at all. + /// + /// Note that as more yield points are added in the ecosystem, this value + /// will probably also have to be raised. + const fn initial() -> Budget { + Budget(Some(128)) + } + } +} + cfg_rt_threaded! { impl Budget { fn has_remaining(self) -> bool { @@ -89,11 +93,13 @@ cfg_rt_threaded! { } } -/// Run the given closure with a cooperative task budget. When the function -/// returns, the budget is reset to the value prior to calling the function. -#[inline(always)] -pub(crate) fn budget(f: impl FnOnce() -> R) -> R { - with_budget(Budget::initial(), f) +cfg_rt_core! { + /// Run the given closure with a cooperative task budget. When the function + /// returns, the budget is reset to the value prior to calling the function. + #[inline(always)] + pub(crate) fn budget(f: impl FnOnce() -> R) -> R { + with_budget(Budget::initial(), f) + } } cfg_rt_threaded! { diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index 30b30203995..384485c3100 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -4,7 +4,6 @@ mod scheduled_io; pub(crate) use scheduled_io::ScheduledIo; // pub(crate) for tests use crate::park::{Park, Unpark}; -use crate::runtime::context; use crate::util::bit; use crate::util::slab::{self, Slab}; @@ -228,17 +227,36 @@ impl fmt::Debug for Driver { // ===== impl Handle ===== -impl Handle { - /// Returns a handle to the current reactor - /// - /// # Panics - /// - /// This function panics if there is no current reactor set. - pub(super) fn current() -> Self { - context::io_handle() - .expect("there is no reactor running, must be called from the context of Tokio runtime") +cfg_rt_core! { + impl Handle { + /// Returns a handle to the current reactor + /// + /// # Panics + /// + /// This function panics if there is no current reactor set and `rt-core` 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") + } + } +} + +cfg_not_rt_core! { + impl Handle { + /// Returns a handle to the current reactor + /// + /// # Panics + /// + /// This function panics if there is no current reactor set and `rt-core` 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-core` enabled.") + } } +} +impl Handle { /// Forces a reactor blocked in a call to `turn` to wakeup, or otherwise /// makes the next call to `turn` return immediately. /// diff --git a/tokio/src/lib.rs b/tokio/src/lib.rs index 2d01823987d..d8dfb934848 100644 --- a/tokio/src/lib.rs +++ b/tokio/src/lib.rs @@ -364,7 +364,9 @@ cfg_process! { pub mod process; } -pub mod runtime; +cfg_rt_core! { + pub mod runtime; +} pub(crate) mod coop; diff --git a/tokio/src/loom/mod.rs b/tokio/src/loom/mod.rs index 56a41f25a05..5957b5377d3 100644 --- a/tokio/src/loom/mod.rs +++ b/tokio/src/loom/mod.rs @@ -1,6 +1,8 @@ //! This module abstracts over `loom` and `std::sync` depending on whether we //! are running tests or not. +#![allow(unused)] + #[cfg(not(all(test, loom)))] mod std; #[cfg(not(all(test, loom)))] diff --git a/tokio/src/park/mod.rs b/tokio/src/park/mod.rs index 4085a99a975..b6c44d5e1a7 100644 --- a/tokio/src/park/mod.rs +++ b/tokio/src/park/mod.rs @@ -39,10 +39,11 @@ cfg_resource_drivers! { pub(crate) use self::either::Either; } -mod thread; -pub(crate) use self::thread::ParkThread; - -pub(crate) use self::thread::{CachedParkThread, ParkError}; +cfg_rt_core! { + mod thread; + pub(crate) use self::thread::ParkThread; + pub(crate) use self::thread::{CachedParkThread, ParkError}; +} use std::sync::Arc; use std::time::Duration; diff --git a/tokio/src/runtime/builder.rs b/tokio/src/runtime/builder.rs index 7d6f3c6184e..a71cce82937 100644 --- a/tokio/src/runtime/builder.rs +++ b/tokio/src/runtime/builder.rs @@ -76,6 +76,7 @@ pub(crate) type ThreadNameFn = std::sync::Arc String + Send + Sync + pub(crate) enum Kind { CurrentThread, SingleThread, + #[cfg(feature = "rt-threaded")] MultiThread, } @@ -380,6 +381,7 @@ impl Builder { match &self.kind { Kind::CurrentThread => self.build_basic_runtime(true), Kind::SingleThread => self.build_basic_runtime(false), + #[cfg(feature = "rt-threaded")] Kind::MultiThread => self.build_threaded_runtime(), } } @@ -414,6 +416,68 @@ impl Builder { self.keep_alive = Some(duration); self } + + fn build_basic_runtime(&mut self, current_thread: bool) -> io::Result { + use crate::runtime::{BasicScheduler, Kind}; + + let (driver, resources) = driver::Driver::new(self.get_cfg())?; + + if current_thread { + // And now put a single-threaded scheduler on top of the timer. When + // there are no futures ready to do something, it'll let the timer or + // the reactor to generate some new stimuli for the futures to continue + // in their life. + let scheduler = BasicScheduler::new(driver); + let spawner = Spawner::Basic(scheduler.spawner().clone()); + + // Blocking pool + let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); + let blocking_spawner = blocking_pool.spawner().clone(); + + Ok(Runtime { + kind: Kind::CurrentThread(scheduler), + handle: Handle { + spawner, + io_handle: resources.io_handle, + time_handle: resources.time_handle, + signal_handle: resources.signal_handle, + clock: resources.clock, + blocking_spawner, + }, + blocking_pool, + }) + } else { + use crate::loom::sync::Arc; + // use crate::future::poll_fn; + // use std::task::Poll; + + let scheduler = Arc::new(BasicScheduler::new(driver)); + let spawner = Spawner::Basic(scheduler.spawner().clone()); + + // Blocking pool + let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); + let blocking_spawner = blocking_pool.spawner().clone(); + + // TODO(lucio): fix this in the basic scheduler + // let scheduler2 = scheduler.clone(); + // std::thread::spawn(move || { + // scheduler2.block_on(poll_fn::<(), _>(|_| Poll::Pending)); + // }); + + Ok(Runtime { + kind: Kind::SingleThread(scheduler), + handle: Handle { + spawner, + io_handle: resources.io_handle, + time_handle: resources.time_handle, + signal_handle: resources.signal_handle, + clock: resources.clock, + blocking_spawner, + }, + blocking_pool, + }) + } + } } cfg_io_driver! { @@ -463,72 +527,6 @@ cfg_time! { } } -cfg_rt_core! { - impl Builder { - fn build_basic_runtime(&mut self, current_thread: bool) -> io::Result { - use crate::runtime::{BasicScheduler, Kind}; - - let (driver, resources) = driver::Driver::new(self.get_cfg())?; - - if current_thread { - // And now put a single-threaded scheduler on top of the timer. When - // there are no futures ready to do something, it'll let the timer or - // the reactor to generate some new stimuli for the futures to continue - // in their life. - let scheduler = BasicScheduler::new(driver); - let spawner = Spawner::Basic(scheduler.spawner().clone()); - - // Blocking pool - let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); - let blocking_spawner = blocking_pool.spawner().clone(); - - Ok(Runtime { - kind: Kind::CurrentThread(scheduler), - handle: Handle { - spawner, - io_handle: resources.io_handle, - time_handle: resources.time_handle, - signal_handle: resources.signal_handle, - clock: resources.clock, - blocking_spawner, - }, - blocking_pool, - }) - } else { - use crate::loom::sync::Arc; - // use crate::future::poll_fn; - // use std::task::Poll; - - let scheduler = Arc::new(BasicScheduler::new(driver)); - let spawner = Spawner::Basic(scheduler.spawner().clone()); - - // Blocking pool - let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); - let blocking_spawner = blocking_pool.spawner().clone(); - - // TODO(lucio): fix this in the basic scheduler - // let scheduler2 = scheduler.clone(); - // std::thread::spawn(move || { - // scheduler2.block_on(poll_fn::<(), _>(|_| Poll::Pending)); - // }); - - Ok(Runtime { - kind: Kind::SingleThread(scheduler), - handle: Handle { - spawner, - io_handle: resources.io_handle, - time_handle: resources.time_handle, - signal_handle: resources.signal_handle, - clock: resources.clock, - blocking_spawner, - }, - blocking_pool, - }) - } - } - } -} - cfg_rt_threaded! { impl Builder { fn build_threaded_runtime(&mut self) -> io::Result { diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 4ecf500b0b3..64af98f74ea 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -190,12 +190,10 @@ mod tests; pub(crate) mod context; -cfg_rt_core! { - mod basic_scheduler; - use basic_scheduler::BasicScheduler; +mod basic_scheduler; +use basic_scheduler::BasicScheduler; - pub(crate) mod task; -} +pub(crate) mod task; mod blocking; use blocking::BlockingPool; @@ -236,10 +234,8 @@ cfg_rt_threaded! { use self::thread_pool::ThreadPool; } -cfg_rt_core! { - use crate::task::JoinHandle; - use crate::loom::sync::Arc; -} +use crate::loom::sync::Arc; +use crate::task::JoinHandle; use std::future::Future; use std::time::Duration; @@ -304,16 +300,17 @@ enum Kind { type Callback = std::sync::Arc; impl Runtime { + #[cfg(feature = "rt-threaded")] pub fn new_multi_thread() -> io::Result { Builder::new_multi_thread().enable_all().build() } pub fn new_single_thread() -> io::Result { - Builder::new_multi_thread().enable_all().build() + Builder::new_single_thread().enable_all().build() } pub fn new_current_thread() -> io::Result { - Builder::new_multi_thread().enable_all().build() + Builder::new_current_thread().enable_all().build() } /// Spawn a future onto the Tokio runtime. diff --git a/tokio/src/signal/unix/driver.rs b/tokio/src/signal/unix/driver.rs index 639a483ef24..ccc6225ca07 100644 --- a/tokio/src/signal/unix/driver.rs +++ b/tokio/src/signal/unix/driver.rs @@ -3,7 +3,6 @@ use crate::io::driver::Driver as IoDriver; use crate::io::PollEvented; use crate::park::Park; -use crate::runtime::context; use crate::signal::registry::globals; use mio_uds::UnixStream; use std::io::{self, Read}; @@ -145,17 +144,6 @@ impl Park for Driver { // ===== impl Handle ===== impl Handle { - /// Returns a handle to the current driver - /// - /// # Panics - /// - /// This function panics if there is no current signal driver set. - pub(super) fn current() -> Self { - context::signal_handle().expect( - "there is no signal driver running, must be called from the context of Tokio runtime", - ) - } - pub(super) fn check_inner(&self) -> io::Result<()> { if self.inner.strong_count() > 0 { Ok(()) @@ -164,3 +152,34 @@ impl Handle { } } } + +cfg_rt_core! { + impl Handle { + /// Returns a handle to the current driver + /// + /// # Panics + /// + /// This function panics if there is no current signal driver set. + pub(super) fn current() -> Self { + crate::runtime::context::signal_handle().expect( + "there is no signal driver running, must be called from the context of Tokio runtime", + ) + } + } +} + +cfg_not_rt_core! { + impl Handle { + /// Returns a handle to the current driver + /// + /// # Panics + /// + /// This function panics if there is no current signal driver set. + pub(super) fn current() -> Self { + panic!( + "there is no signal driver running, must be called from the context of Tokio runtime or with\ + `rt-core` enabled.", + ) + } + } +} diff --git a/tokio/src/sync/mod.rs b/tokio/src/sync/mod.rs index 4c069467dee..4a347206a95 100644 --- a/tokio/src/sync/mod.rs +++ b/tokio/src/sync/mod.rs @@ -457,8 +457,10 @@ cfg_sync! { } cfg_not_sync! { - mod notify; - pub(crate) use notify::Notify; + cfg_rt_core! { + mod notify; + pub(crate) use notify::Notify; + } cfg_atomic_waker_impl! { mod task; diff --git a/tokio/src/sync/mpsc/bounded.rs b/tokio/src/sync/mpsc/bounded.rs index 95b2089c1ef..5f298360f8f 100644 --- a/tokio/src/sync/mpsc/bounded.rs +++ b/tokio/src/sync/mpsc/bounded.rs @@ -163,40 +163,6 @@ impl Receiver { self.chan.recv(cx) } - /// Blocking receive to call outside of asynchronous contexts. - /// - /// # Panics - /// - /// This function panics if called within an asynchronous execution - /// context. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// use tokio::runtime::Runtime; - /// use tokio::sync::mpsc; - /// - /// fn main() { - /// let (mut tx, mut rx) = mpsc::channel::(10); - /// - /// let sync_code = thread::spawn(move || { - /// assert_eq!(Some(10), rx.blocking_recv()); - /// }); - /// - /// Runtime::new_multi_thread() - /// .unwrap() - /// .block_on(async move { - /// let _ = tx.send(10).await; - /// }); - /// sync_code.join().unwrap() - /// } - /// ``` - pub fn blocking_recv(&mut self) -> Option { - let mut enter_handle = crate::runtime::enter::enter(false); - enter_handle.block_on(self.recv()).unwrap() - } - /// Attempts to return a pending value on this receiver without blocking. /// /// This method will never block the caller in order to wait for data to @@ -223,6 +189,44 @@ impl Receiver { impl Unpin for Receiver {} +cfg_rt_core! { + impl Receiver { + /// Blocking receive to call outside of asynchronous contexts. + /// + /// # Panics + /// + /// This function panics if called within an asynchronous execution + /// context. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use tokio::runtime::Runtime; + /// use tokio::sync::mpsc; + /// + /// fn main() { + /// let (mut tx, mut rx) = mpsc::channel::(10); + /// + /// let sync_code = thread::spawn(move || { + /// assert_eq!(Some(10), rx.blocking_recv()); + /// }); + /// + /// Runtime::new_multi_thread() + /// .unwrap() + /// .block_on(async move { + /// let _ = tx.send(10).await; + /// }); + /// sync_code.join().unwrap() + /// } + /// ``` + pub fn blocking_recv(&mut self) -> Option { + let mut enter_handle = crate::runtime::enter::enter(false); + enter_handle.block_on(self.recv()).unwrap() + } + } +} + cfg_stream! { impl crate::stream::Stream for Receiver { type Item = T; @@ -435,38 +439,6 @@ impl Sender { } } - /// Blocking send to call outside of asynchronous contexts. - /// - /// # Panics - /// - /// This function panics if called within an asynchronous execution - /// context. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// use tokio::runtime::Runtime; - /// use tokio::sync::mpsc; - /// - /// fn main() { - /// let (mut tx, mut rx) = mpsc::channel::(1); - /// - /// let sync_code = thread::spawn(move || { - /// tx.blocking_send(10).unwrap(); - /// }); - /// - /// Runtime::new_multi_thread().unwrap().block_on(async move { - /// assert_eq!(Some(10), rx.recv().await); - /// }); - /// sync_code.join().unwrap() - /// } - /// ``` - pub fn blocking_send(&mut self, value: T) -> Result<(), SendError> { - let mut enter_handle = crate::runtime::enter::enter(false); - enter_handle.block_on(self.send(value)).unwrap() - } - /// Returns `Poll::Ready(Ok(()))` when the channel is able to accept another item. /// /// If the channel is full, then `Poll::Pending` is returned and the task is notified when a @@ -551,3 +523,39 @@ impl Sender { } } } + +cfg_rt_core! { + impl Sender { + /// Blocking send to call outside of asynchronous contexts. + /// + /// # Panics + /// + /// This function panics if called within an asynchronous execution + /// context. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use tokio::runtime::Runtime; + /// use tokio::sync::mpsc; + /// + /// fn main() { + /// let (mut tx, mut rx) = mpsc::channel::(1); + /// + /// let sync_code = thread::spawn(move || { + /// tx.blocking_send(10).unwrap(); + /// }); + /// + /// Runtime::new_multi_thread().unwrap().block_on(async move { + /// assert_eq!(Some(10), rx.recv().await); + /// }); + /// sync_code.join().unwrap() + /// } + /// ``` + pub fn blocking_send(&mut self, value: T) -> Result<(), SendError> { + let mut enter_handle = crate::runtime::enter::enter(false); + enter_handle.block_on(self.send(value)).unwrap() + } + } +} diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index f79f62b46f7..93d8cd7be1c 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -1,4 +1,3 @@ -use crate::runtime::context; use crate::time::driver::Inner; use std::fmt; use std::sync::{Arc, Weak}; @@ -15,33 +14,62 @@ impl Handle { Handle { inner } } - /// Tries to get a handle to the current timer. - /// - /// # Panics - /// - /// This function panics if there is no current timer set. - /// - /// It can be triggered when `Builder::enable_time()` or - /// `Builder::enable_all()` are not included in the builder. - /// - /// It can also panic whenever a timer is created outside of a Tokio - /// runtime. That is why `rt.block_on(delay_for(...))` will panic, - /// since the function is executed outside of the runtime. - /// Whereas `rt.block_on(async {delay_for(...).await})` doesn't - /// panic. And this is because wrapping the function on an async makes it - /// lazy, and so gets executed inside the runtime successfuly without - /// panicking. - pub(crate) fn current() -> Self { - context::time_handle() - .expect("there is no timer running, must be called from the context of Tokio runtime") - } - /// Tries to return a strong ref to the inner pub(crate) fn inner(&self) -> Option> { self.inner.upgrade() } } +cfg_rt_core! { + impl Handle { + /// Tries to get a handle to the current timer. + /// + /// # Panics + /// + /// This function panics if there is no current timer set. + /// + /// It can be triggered when `Builder::enable_time()` or + /// `Builder::enable_all()` are not included in the builder. + /// + /// It can also panic whenever a timer is created outside of a Tokio + /// runtime. That is why `rt.block_on(delay_for(...))` will panic, + /// since the function is executed outside of the runtime. + /// Whereas `rt.block_on(async {delay_for(...).await})` doesn't + /// panic. And this is because wrapping the function on an async makes it + /// lazy, and so gets executed inside the runtime successfuly without + /// 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") + } + } +} + +cfg_not_rt_core! { + impl Handle { + /// Tries to get a handle to the current timer. + /// + /// # Panics + /// + /// This function panics if there is no current timer set. + /// + /// It can be triggered when `Builder::enable_time()` or + /// `Builder::enable_all()` are not included in the builder. + /// + /// It can also panic whenever a timer is created outside of a Tokio + /// runtime. That is why `rt.block_on(delay_for(...))` will panic, + /// since the function is executed outside of the runtime. + /// Whereas `rt.block_on(async {delay_for(...).await})` doesn't + /// panic. And this is because wrapping the function on an async makes it + /// lazy, and so gets 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-core` is not enabled") + } + } +} + impl fmt::Debug for Handle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Handle") diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index ffe901670ae..8c1342c4ecf 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -3,16 +3,16 @@ cfg_io_driver! { pub(crate) mod slab; } +#[cfg(any(feature = "sync", feature = "rt-core", feature = "io-driver"))] pub(crate) mod linked_list; #[cfg(any(feature = "rt-threaded", feature = "macros", feature = "stream"))] mod rand; -mod wake; -pub(crate) use wake::{waker_ref, Wake}; - cfg_rt_core! { + mod wake; pub(crate) use wake::WakerRef; + pub(crate) use wake::{waker_ref, Wake}; } cfg_rt_threaded! { From 5c9e72de5e7b169efd45ef579a346c015fb70ee0 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 16:01:30 -0700 Subject: [PATCH 17/39] fix feature flags --- tokio/Cargo.toml | 8 +- tokio/src/blocking.rs | 41 ++ tokio/src/coop.rs | 57 +- tokio/src/fs/mod.rs | 4 +- tokio/src/future/block_on.rs | 15 + tokio/src/future/mod.rs | 18 +- tokio/src/future/poll_fn.rs | 2 + tokio/src/future/try_join.rs | 2 +- tokio/src/io/driver/mod.rs | 2 + tokio/src/io/mod.rs | 4 +- tokio/src/lib.rs | 10 +- tokio/src/macros/cfg.rs | 90 +-- tokio/src/macros/mod.rs | 2 +- tokio/src/macros/support.rs | 3 +- tokio/src/net/addr.rs | 45 +- tokio/src/park/either.rs | 2 + tokio/src/park/mod.rs | 12 +- tokio/src/park/thread.rs | 25 +- tokio/src/process/unix/driver.rs | 2 + tokio/src/runtime/basic_scheduler.rs | 2 +- tokio/src/runtime/blocking/mod.rs | 20 +- tokio/src/runtime/builder.rs | 6 +- tokio/src/runtime/context.rs | 6 +- tokio/src/runtime/driver.rs | 20 +- tokio/src/runtime/enter.rs | 214 ++++---- tokio/src/runtime/mod.rs | 546 +++++++++---------- tokio/src/runtime/task/error.rs | 2 +- tokio/src/runtime/task/join.rs | 2 +- tokio/src/runtime/task/mod.rs | 34 +- tokio/src/runtime/thread_pool/atomic_cell.rs | 1 - tokio/src/runtime/thread_pool/mod.rs | 4 +- tokio/src/runtime/thread_pool/worker.rs | 161 +++--- tokio/src/signal/unix/driver.rs | 2 + tokio/src/sync/mod.rs | 6 +- tokio/src/sync/mpsc/bounded.rs | 8 +- tokio/src/sync/mpsc/chan.rs | 2 +- tokio/src/task/blocking.rs | 148 +++-- tokio/src/task/local.rs | 2 + tokio/src/task/mod.rs | 19 +- tokio/src/task/yield_now.rs | 2 +- tokio/src/time/clock.rs | 2 + tokio/src/time/driver/mod.rs | 2 + tokio/src/util/linked_list.rs | 2 + tokio/src/util/mod.rs | 12 +- tokio/src/util/slab.rs | 2 + tokio/src/util/trace.rs | 4 +- 46 files changed, 792 insertions(+), 783 deletions(-) create mode 100644 tokio/src/blocking.rs create mode 100644 tokio/src/future/block_on.rs diff --git a/tokio/Cargo.toml b/tokio/Cargo.toml index 4d5f833c365..cb407f9311d 100644 --- a/tokio/Cargo.toml +++ b/tokio/Cargo.toml @@ -30,7 +30,6 @@ default = [] # enable everything full = [ - "blocking", "dns", "fs", "io-util", @@ -47,12 +46,11 @@ full = [ "time", ] -blocking = ["rt-core"] -dns = ["rt-core"] -fs = ["rt-core", "io-util"] +dns = [] +fs = [] io-util = ["memchr"] # stdin, stdout, stderr -io-std = ["rt-core"] +io-std = [] macros = ["tokio-macros"] net = ["dns", "tcp", "udp", "uds"] process = [ diff --git a/tokio/src/blocking.rs b/tokio/src/blocking.rs new file mode 100644 index 00000000000..64cdf2c76c3 --- /dev/null +++ b/tokio/src/blocking.rs @@ -0,0 +1,41 @@ +cfg_rt_core! { + pub(crate) use crate::runtime::spawn_blocking; + pub(crate) use crate::task::JoinHandle; +} + +cfg_not_rt_core! { + use std::fmt; + use std::future::Future; + use std::pin::Pin; + use std::task::{Context, Poll}; + + pub(crate) fn spawn_blocking(_f: F) -> JoinHandle + where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, + { + panic!("requires the `rt-core` Tokio feature flag") + + } + + pub(crate) struct JoinHandle { + _p: std::marker::PhantomData, + } + + impl Future for JoinHandle { + type Output = Result; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + unreachable!() + } + } + + impl fmt::Debug for JoinHandle + where + T: fmt::Debug, + { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("JoinHandle").finish() + } + } +} diff --git a/tokio/src/coop.rs b/tokio/src/coop.rs index 5a7ba5fdd17..0f5a4956a69 100644 --- a/tokio/src/coop.rs +++ b/tokio/src/coop.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "full"), allow(dead_code))] + //! Opt-in yield points for improved cooperative scheduling. //! //! A single call to [`poll`] on a top-level task may potentially do a lot of @@ -67,21 +69,19 @@ impl Budget { } } -cfg_rt_core! { - impl Budget { - /// Budget assigned to a task on each poll. - /// - /// The value itself is chosen somewhat arbitrarily. It needs to be high - /// enough to amortize wakeup and scheduling costs, but low enough that we - /// do not starve other tasks for too long. The value also needs to be high - /// enough that particularly deep tasks are able to do at least some useful - /// work at all. - /// - /// Note that as more yield points are added in the ecosystem, this value - /// will probably also have to be raised. - const fn initial() -> Budget { - Budget(Some(128)) - } +impl Budget { + /// Budget assigned to a task on each poll. + /// + /// The value itself is chosen somewhat arbitrarily. It needs to be high + /// enough to amortize wakeup and scheduling costs, but low enough that we + /// do not starve other tasks for too long. The value also needs to be high + /// enough that particularly deep tasks are able to do at least some useful + /// work at all. + /// + /// Note that as more yield points are added in the ecosystem, this value + /// will probably also have to be raised. + const fn initial() -> Budget { + Budget(Some(128)) } } @@ -93,21 +93,11 @@ cfg_rt_threaded! { } } -cfg_rt_core! { - /// Run the given closure with a cooperative task budget. When the function - /// returns, the budget is reset to the value prior to calling the function. - #[inline(always)] - pub(crate) fn budget(f: impl FnOnce() -> R) -> R { - with_budget(Budget::initial(), f) - } -} - -cfg_rt_threaded! { - /// Set the current task's budget - #[cfg(feature = "blocking")] - pub(crate) fn set(budget: Budget) { - CURRENT.with(|cell| cell.set(budget)) - } +/// Run the given closure with a cooperative task budget. When the function +/// returns, the budget is reset to the value prior to calling the function. +#[inline(always)] +pub(crate) fn budget(f: impl FnOnce() -> R) -> R { + with_budget(Budget::initial(), f) } #[inline(always)] @@ -135,13 +125,18 @@ fn with_budget(budget: Budget, f: impl FnOnce() -> R) -> R { } cfg_rt_threaded! { + /// Set the current task's budget + pub(crate) fn set(budget: Budget) { + CURRENT.with(|cell| cell.set(budget)) + } + #[inline(always)] pub(crate) fn has_budget_remaining() -> bool { CURRENT.with(|cell| cell.get().has_remaining()) } } -cfg_blocking_impl! { +cfg_rt_core! { /// Forcibly remove the budgeting constraints early. /// /// Returns the remaining budget diff --git a/tokio/src/fs/mod.rs b/tokio/src/fs/mod.rs index a2b062b1a30..d2757a5fab5 100644 --- a/tokio/src/fs/mod.rs +++ b/tokio/src/fs/mod.rs @@ -107,6 +107,6 @@ mod sys { pub(crate) use std::fs::File; // TODO: don't rename - pub(crate) use crate::runtime::spawn_blocking as run; - pub(crate) use crate::task::JoinHandle as Blocking; + pub(crate) use crate::blocking::spawn_blocking as run; + pub(crate) use crate::blocking::JoinHandle as Blocking; } diff --git a/tokio/src/future/block_on.rs b/tokio/src/future/block_on.rs new file mode 100644 index 00000000000..d12482bccf4 --- /dev/null +++ b/tokio/src/future/block_on.rs @@ -0,0 +1,15 @@ +use std::future::Future; + +cfg_rt_core! { + pub(crate) fn block_on(f: F) -> F::Output { + let mut e = crate::runtime::enter::enter(false); + e.block_on(f).unwrap() + } +} + +cfg_not_rt_core! { + pub(crate) fn block_on(f: F) -> F::Output { + let mut park = crate::park::thread::CachedParkThread::new(); + park.block_on(f) + } +} diff --git a/tokio/src/future/mod.rs b/tokio/src/future/mod.rs index 770753f3191..02e66338985 100644 --- a/tokio/src/future/mod.rs +++ b/tokio/src/future/mod.rs @@ -1,9 +1,10 @@ -#![allow(unused_imports, dead_code)] +// #![allow(unused_imports, dead_code)] +#![cfg_attr(not(feature = "macros"), allow(unreachable_pub))] //! Asynchronous values. -mod maybe_done; -pub use maybe_done::{maybe_done, MaybeDone}; +#[cfg(any(feature = "macros", feature = "process"))] +pub(crate) mod maybe_done; mod poll_fn; pub use poll_fn::poll_fn; @@ -11,5 +12,12 @@ pub use poll_fn::poll_fn; mod ready; pub(crate) use ready::{ok, Ready}; -mod try_join; -pub(crate) use try_join::try_join3; +cfg_process! { + mod try_join; + pub(crate) use try_join::try_join3; +} + +cfg_sync! { + mod block_on; + pub(crate) use block_on::block_on; +} diff --git a/tokio/src/future/poll_fn.rs b/tokio/src/future/poll_fn.rs index 9b3d1370ea9..0169bd5fcd4 100644 --- a/tokio/src/future/poll_fn.rs +++ b/tokio/src/future/poll_fn.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + //! Definition of the `PollFn` adapter combinator use std::fmt; diff --git a/tokio/src/future/try_join.rs b/tokio/src/future/try_join.rs index 5bd80dc89a2..8943f61a1eb 100644 --- a/tokio/src/future/try_join.rs +++ b/tokio/src/future/try_join.rs @@ -1,4 +1,4 @@ -use crate::future::{maybe_done, MaybeDone}; +use crate::future::maybe_done::{maybe_done, MaybeDone}; use pin_project_lite::pin_project; use std::future::Future; diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index 7550bef406d..f51d206b126 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "rt-core"), allow(dead_code))] + mod ready; use ready::Ready; diff --git a/tokio/src/io/mod.rs b/tokio/src/io/mod.rs index e1a036fb6ce..62728ac174f 100644 --- a/tokio/src/io/mod.rs +++ b/tokio/src/io/mod.rs @@ -250,7 +250,7 @@ cfg_io_blocking! { /// Types in this module can be mocked out in tests. mod sys { // TODO: don't rename - pub(crate) use crate::runtime::spawn_blocking as run; - pub(crate) use crate::task::JoinHandle as Blocking; + pub(crate) use crate::blocking::spawn_blocking as run; + pub(crate) use crate::blocking::JoinHandle as Blocking; } } diff --git a/tokio/src/lib.rs b/tokio/src/lib.rs index 3e56f51dba4..e60b771dcf0 100644 --- a/tokio/src/lib.rs +++ b/tokio/src/lib.rs @@ -349,8 +349,7 @@ cfg_fs! { pub mod fs; } -#[doc(hidden)] -pub mod future; +mod future; pub mod io; pub mod net; @@ -364,9 +363,14 @@ cfg_process! { pub mod process; } +#[cfg(any(feature = "dns", feature = "fs", feature = "io-std"))] +mod blocking; + cfg_rt_core! { pub mod runtime; } +#[cfg(all(not(feature = "rt-core"), feature = "rt-util"))] +mod runtime; pub(crate) mod coop; @@ -392,8 +396,8 @@ cfg_not_sync! { mod sync; } +pub mod task; cfg_rt_core! { - pub mod task; pub use task::spawn; } diff --git a/tokio/src/macros/cfg.rs b/tokio/src/macros/cfg.rs index 8f1536f85f8..83102da698d 100644 --- a/tokio/src/macros/cfg.rs +++ b/tokio/src/macros/cfg.rs @@ -1,70 +1,10 @@ #![allow(unused_macros)] -macro_rules! cfg_resource_drivers { - ($($item:item)*) => { - $( - #[cfg(any( - feature = "process", - all(unix, feature = "signal"), - all(not(loom), feature = "tcp"), - feature = "time", - all(not(loom), feature = "udp"), - all(not(loom), feature = "uds"), - ))] - $item - )* - } -} - -macro_rules! cfg_blocking { - ($($item:item)*) => { - $( - #[cfg(feature = "blocking")] - #[cfg_attr(docsrs, doc(cfg(feature = "blocking")))] - $item - )* - } -} - -/// Enables blocking API internals -macro_rules! cfg_blocking_impl { - ($($item:item)*) => { - $( - #[cfg(any( - feature = "blocking", - feature = "fs", - feature = "dns", - feature = "io-std", - feature = "rt-threaded", - ))] - $item - )* - } -} - -/// Enables blocking API internals -macro_rules! cfg_blocking_impl_or_task { - ($($item:item)*) => { - $( - #[cfg(any( - feature = "blocking", - feature = "fs", - feature = "dns", - feature = "io-std", - feature = "rt-threaded", - feature = "task", - ))] - $item - )* - } -} - /// Enables enter::block_on macro_rules! cfg_block_on { ($($item:item)*) => { $( #[cfg(any( - feature = "blocking", feature = "fs", feature = "dns", feature = "io-std", @@ -75,29 +15,13 @@ macro_rules! cfg_block_on { } } -/// Enables blocking API internals -macro_rules! cfg_not_blocking_impl { - ($($item:item)*) => { - $( - #[cfg(not(any( - feature = "blocking", - feature = "fs", - feature = "dns", - feature = "io-std", - feature = "rt-threaded", - )))] - $item - )* - } -} - /// Enables internal `AtomicWaker` impl macro_rules! cfg_atomic_waker_impl { ($($item:item)*) => { $( #[cfg(any( feature = "process", - all(feature = "rt-core", feature = "rt-util"), + feature = "rt-util", feature = "signal", feature = "tcp", feature = "time", @@ -324,6 +248,16 @@ macro_rules! cfg_rt_core { } } +macro_rules! cfg_task { + ($($item:item)*) => { + $( + #[cfg(any(feature = "rt-core", feature = "rt-util"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "rt-core", feature = "rt-util"))))] + $item + )* + } +} + macro_rules! doc_rt_core { ($($item:item)*) => { $( @@ -451,12 +385,12 @@ macro_rules! cfg_coop { ($($item:item)*) => { $( #[cfg(any( - feature = "blocking", feature = "dns", feature = "fs", feature = "io-std", feature = "process", feature = "rt-core", + feature = "rt-util", feature = "signal", feature = "sync", feature = "stream", diff --git a/tokio/src/macros/mod.rs b/tokio/src/macros/mod.rs index 2643c360189..a9d87657756 100644 --- a/tokio/src/macros/mod.rs +++ b/tokio/src/macros/mod.rs @@ -16,7 +16,7 @@ mod ready; mod thread_local; #[macro_use] -#[cfg(feature = "rt-core")] +#[cfg(any(feature = "rt-core", feature = "rt-util"))] pub(crate) mod scoped_tls; cfg_macros! { diff --git a/tokio/src/macros/support.rs b/tokio/src/macros/support.rs index fc1cdfcfa00..7f11bc68001 100644 --- a/tokio/src/macros/support.rs +++ b/tokio/src/macros/support.rs @@ -1,5 +1,6 @@ cfg_macros! { - pub use crate::future::{maybe_done, poll_fn}; + pub use crate::future::poll_fn; + pub use crate::future::maybe_done::maybe_done; pub use crate::util::thread_rng_n; } diff --git a/tokio/src/net/addr.rs b/tokio/src/net/addr.rs index 86b0962b931..e2d09d47322 100644 --- a/tokio/src/net/addr.rs +++ b/tokio/src/net/addr.rs @@ -153,22 +153,22 @@ cfg_dns! { type Future = sealed::MaybeReady; fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future { - use crate::runtime::spawn_blocking; + use crate::blocking::spawn_blocking; use sealed::MaybeReady; // First check if the input parses as a socket address let res: Result = self.parse(); if let Ok(addr) = res { - return MaybeReady::Ready(Some(addr)); + return MaybeReady(sealed::State::Ready(Some(addr))); } // Run DNS lookup on the blocking pool let s = self.to_owned(); - MaybeReady::Blocking(spawn_blocking(move || { + MaybeReady(sealed::State::Blocking(spawn_blocking(move || { std::net::ToSocketAddrs::to_socket_addrs(&s) - })) + }))) } } @@ -181,7 +181,7 @@ cfg_dns! { type Future = sealed::MaybeReady; fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future { - use crate::runtime::spawn_blocking; + use crate::blocking::spawn_blocking; use sealed::MaybeReady; let (host, port) = *self; @@ -191,21 +191,21 @@ cfg_dns! { let addr = SocketAddrV4::new(addr, port); let addr = SocketAddr::V4(addr); - return MaybeReady::Ready(Some(addr)); + return MaybeReady(sealed::State::Ready(Some(addr))); } if let Ok(addr) = host.parse::() { let addr = SocketAddrV6::new(addr, port, 0, 0); let addr = SocketAddr::V6(addr); - return MaybeReady::Ready(Some(addr)); + return MaybeReady(sealed::State::Ready(Some(addr))); } let host = host.to_owned(); - MaybeReady::Blocking(spawn_blocking(move || { + MaybeReady(sealed::State::Blocking(spawn_blocking(move || { std::net::ToSocketAddrs::to_socket_addrs(&(&host[..], port)) - })) + }))) } } @@ -245,15 +245,6 @@ pub(crate) mod sealed { use std::io; use std::net::SocketAddr; - cfg_dns! { - use crate::task::JoinHandle; - - use std::option; - use std::pin::Pin; - use std::task::{Context, Poll}; - use std::vec; - } - #[doc(hidden)] pub trait ToSocketAddrsPriv { type Iter: Iterator + Send + 'static; @@ -266,9 +257,19 @@ pub(crate) mod sealed { pub struct Internal; cfg_dns! { + use crate::blocking::JoinHandle; + + use std::option; + use std::pin::Pin; + use std::task::{Context, Poll}; + use std::vec; + #[doc(hidden)] #[derive(Debug)] - pub enum MaybeReady { + pub struct MaybeReady(pub(super) State); + + #[derive(Debug)] + pub(super) enum State { Ready(Option), Blocking(JoinHandle>>), } @@ -284,12 +285,12 @@ pub(crate) mod sealed { type Output = io::Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match *self { - MaybeReady::Ready(ref mut i) => { + match self.0 { + State::Ready(ref mut i) => { let iter = OneOrMore::One(i.take().into_iter()); Poll::Ready(Ok(iter)) } - MaybeReady::Blocking(ref mut rx) => { + State::Blocking(ref mut rx) => { let res = ready!(Pin::new(rx).poll(cx))?.map(OneOrMore::More); Poll::Ready(res) diff --git a/tokio/src/park/either.rs b/tokio/src/park/either.rs index c66d1213125..ee02ec158b0 100644 --- a/tokio/src/park/either.rs +++ b/tokio/src/park/either.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "full"), allow(dead_code))] + use crate::park::{Park, Unpark}; use std::fmt; diff --git a/tokio/src/park/mod.rs b/tokio/src/park/mod.rs index b6c44d5e1a7..e4b975126d4 100644 --- a/tokio/src/park/mod.rs +++ b/tokio/src/park/mod.rs @@ -34,17 +34,13 @@ //! * `park_timeout` does the same as `park` but allows specifying a maximum //! time to block the thread for. -cfg_resource_drivers! { - mod either; - pub(crate) use self::either::Either; -} - cfg_rt_core! { - mod thread; - pub(crate) use self::thread::ParkThread; - pub(crate) use self::thread::{CachedParkThread, ParkError}; + pub(crate) mod either; } +#[cfg(any(feature = "rt-core", feature = "rt-util", feature = "sync"))] +pub(crate) mod thread; + use std::sync::Arc; use std::time::Duration; diff --git a/tokio/src/park/thread.rs b/tokio/src/park/thread.rs index 494c02b4a74..054da0a51bb 100644 --- a/tokio/src/park/thread.rs +++ b/tokio/src/park/thread.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "full"), allow(dead_code))] + use crate::loom::sync::atomic::AtomicUsize; use crate::loom::sync::{Arc, Condvar, Mutex}; use crate::park::{Park, Unpark}; @@ -212,10 +214,10 @@ impl Unpark for UnparkThread { } } +use std::future::Future; use std::marker::PhantomData; -use std::rc::Rc; - use std::mem; +use std::rc::Rc; use std::task::{RawWaker, RawWakerVTable, Waker}; /// Blocks the current thread using a condition variable. @@ -246,6 +248,25 @@ impl CachedParkThread { { CURRENT_PARKER.try_with(|inner| f(inner)).map_err(|_| ()) } + + pub(crate) fn block_on(&mut self, f: F) -> F::Output { + use std::task::Context; + use std::task::Poll::Ready; + + // `get_unpark()` should not return a Result + let waker = self.get_unpark().unwrap().into_waker(); + let mut cx = Context::from_waker(&waker); + + pin!(f); + + loop { + if let Ready(v) = crate::coop::budget(|| f.as_mut().poll(&mut cx)) { + return v; + } + + self.park().unwrap(); + } + } } impl Park for CachedParkThread { diff --git a/tokio/src/process/unix/driver.rs b/tokio/src/process/unix/driver.rs index 2eea0043c93..62fe8095ce2 100644 --- a/tokio/src/process/unix/driver.rs +++ b/tokio/src/process/unix/driver.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "rt-core"), allow(dead_code))] + //! Process driver use crate::park::Park; diff --git a/tokio/src/runtime/basic_scheduler.rs b/tokio/src/runtime/basic_scheduler.rs index 60fe92c33d9..5ca84671060 100644 --- a/tokio/src/runtime/basic_scheduler.rs +++ b/tokio/src/runtime/basic_scheduler.rs @@ -2,7 +2,7 @@ use crate::future::poll_fn; use crate::loom::sync::Mutex; use crate::park::{Park, Unpark}; use crate::runtime::task::{self, JoinHandle, Schedule, Task}; -use crate::sync::Notify; +use crate::sync::notify::Notify; use crate::util::linked_list::{Link, LinkedList}; use crate::util::{waker_ref, Wake, WakerRef}; diff --git a/tokio/src/runtime/blocking/mod.rs b/tokio/src/runtime/blocking/mod.rs index a819e9e9461..fece3c279d8 100644 --- a/tokio/src/runtime/blocking/mod.rs +++ b/tokio/src/runtime/blocking/mod.rs @@ -3,21 +3,20 @@ //! shells. This isolates the complexity of dealing with conditional //! compilation. -cfg_blocking_impl! { - mod pool; - pub(crate) use pool::{spawn_blocking, try_spawn_blocking, BlockingPool, Spawner}; +mod pool; +pub(crate) use pool::{spawn_blocking, BlockingPool, Spawner}; - mod schedule; - mod shutdown; - pub(crate) mod task; +mod schedule; +mod shutdown; +pub(crate) mod task; - use crate::runtime::Builder; +use crate::runtime::Builder; - pub(crate) fn create_blocking_pool(builder: &Builder, thread_cap: usize) -> BlockingPool { - BlockingPool::new(builder, thread_cap) - } +pub(crate) fn create_blocking_pool(builder: &Builder, thread_cap: usize) -> BlockingPool { + BlockingPool::new(builder, thread_cap) } +/* cfg_not_blocking_impl! { use crate::runtime::Builder; use std::time::Duration; @@ -40,3 +39,4 @@ cfg_not_blocking_impl! { } } } +*/ diff --git a/tokio/src/runtime/builder.rs b/tokio/src/runtime/builder.rs index d1cb27f15ae..6de1439b40b 100644 --- a/tokio/src/runtime/builder.rs +++ b/tokio/src/runtime/builder.rs @@ -1,7 +1,8 @@ use crate::runtime::handle::Handle; -use crate::runtime::{blocking, driver, io, Callback, Runtime, Spawner}; +use crate::runtime::{blocking, driver, Callback, Runtime, Spawner}; use std::fmt; +use std::io; #[cfg(feature = "blocking")] use std::time::Duration; @@ -81,14 +82,17 @@ pub(crate) enum Kind { } impl Builder { + /// TODO pub fn new_current_thread() -> Builder { Builder::new(Kind::CurrentThread) } + /// TODO pub fn new_single_thread() -> Builder { Builder::new(Kind::SingleThread) } + /// TODO #[cfg(feature = "rt-threaded")] pub fn new_multi_thread() -> Builder { Builder::new(Kind::MultiThread) diff --git a/tokio/src/runtime/context.rs b/tokio/src/runtime/context.rs index a4f88e90f45..e28d528201a 100644 --- a/tokio/src/runtime/context.rs +++ b/tokio/src/runtime/context.rs @@ -7,10 +7,8 @@ thread_local! { static CONTEXT: RefCell> = RefCell::new(None) } -cfg_blocking_impl! { - pub(crate) fn current() -> Option { - CONTEXT.with(|ctx| ctx.borrow().clone()) - } +pub(crate) fn current() -> Option { + CONTEXT.with(|ctx| ctx.borrow().clone()) } cfg_io_driver! { diff --git a/tokio/src/runtime/driver.rs b/tokio/src/runtime/driver.rs index af8e17a33dd..6fccb11e30b 100644 --- a/tokio/src/runtime/driver.rs +++ b/tokio/src/runtime/driver.rs @@ -1,16 +1,18 @@ //! Abstracts out the entire chain of runtime sub-drivers into common types. -use crate::park::{Park, ParkThread}; +use crate::park::thread::ParkThread; +use crate::park::Park; + use std::io; use std::time::Duration; // ===== io driver ===== cfg_io_driver! { - type IoDriver = crate::park::Either; + type IoDriver = crate::park::either::Either; pub(crate) type IoHandle = Option; fn create_io_driver(enable: bool) -> io::Result<(IoDriver, IoHandle)> { - use crate::park::Either; + use crate::park::either::Either; #[cfg(loom)] assert!(!enable); @@ -47,11 +49,11 @@ macro_rules! cfg_signal_internal_and_unix { } cfg_signal_internal_and_unix! { - type SignalDriver = crate::park::Either; + type SignalDriver = crate::park::either::Either; pub(crate) type SignalHandle = Option; fn create_signal_driver(io_driver: IoDriver) -> io::Result<(SignalDriver, SignalHandle)> { - use crate::park::Either; + use crate::park::either::Either; // Enable the signal driver if IO is also enabled match io_driver { @@ -77,10 +79,10 @@ cfg_not_signal_internal! { // ===== process driver ===== cfg_process_driver! { - type ProcessDriver = crate::park::Either; + type ProcessDriver = crate::park::either::Either; fn create_process_driver(signal_driver: SignalDriver) -> io::Result { - use crate::park::Either; + use crate::park::either::Either; // Enable the signal driver if IO is also enabled match signal_driver { @@ -104,7 +106,7 @@ cfg_not_process_driver! { // ===== time driver ===== cfg_time! { - type TimeDriver = crate::park::Either, ProcessDriver>; + type TimeDriver = crate::park::either::Either, ProcessDriver>; pub(crate) type Clock = crate::time::Clock; pub(crate) type TimeHandle = Option; @@ -118,7 +120,7 @@ cfg_time! { process_driver: ProcessDriver, clock: Clock, ) -> (TimeDriver, TimeHandle) { - use crate::park::Either; + use crate::park::either::Either; if enable { let driver = crate::time::driver::Driver::new(process_driver, clock); diff --git a/tokio/src/runtime/enter.rs b/tokio/src/runtime/enter.rs index f934162bb20..7bf046f75fd 100644 --- a/tokio/src/runtime/enter.rs +++ b/tokio/src/runtime/enter.rs @@ -4,8 +4,8 @@ use std::marker::PhantomData; #[derive(Debug, Clone, Copy)] pub(crate) enum EnterContext { + #[cfg_attr(not(feature = "rt-core"), allow(dead_code))] Entered { - #[allow(dead_code)] allow_blocking: bool, }, NotEntered, @@ -24,32 +24,38 @@ pub(crate) struct Enter { _p: PhantomData>, } -/// Marks the current thread as being within the dynamic extent of an -/// executor. -pub(crate) fn enter(allow_blocking: bool) -> Enter { - if let Some(enter) = try_enter(allow_blocking) { - return enter; - } +cfg_rt_core! { + use crate::park::thread::ParkError; - panic!( - "Cannot start a runtime from within a runtime. This happens \ - because a function (like `block_on`) attempted to block the \ - current thread while the thread is being used to drive \ - asynchronous tasks." - ); -} + use std::time::Duration; -/// Tries to enter a runtime context, returns `None` if already in a runtime -/// context. -pub(crate) fn try_enter(allow_blocking: bool) -> Option { - ENTERED.with(|c| { - if c.get().is_entered() { - None - } else { - c.set(EnterContext::Entered { allow_blocking }); - Some(Enter { _p: PhantomData }) + /// Marks the current thread as being within the dynamic extent of an + /// executor. + pub(crate) fn enter(allow_blocking: bool) -> Enter { + if let Some(enter) = try_enter(allow_blocking) { + return enter; } - }) + + panic!( + "Cannot start a runtime from within a runtime. This happens \ + because a function (like `block_on`) attempted to block the \ + current thread while the thread is being used to drive \ + asynchronous tasks." + ); + } + + /// Tries to enter a runtime context, returns `None` if already in a runtime + /// context. + pub(crate) fn try_enter(allow_blocking: bool) -> Option { + ENTERED.with(|c| { + if c.get().is_entered() { + None + } else { + c.set(EnterContext::Entered { allow_blocking }); + Some(Enter { _p: PhantomData }) + } + }) + } } // Forces the current "entered" state to be cleared while the closure @@ -59,113 +65,92 @@ pub(crate) fn try_enter(allow_blocking: bool) -> Option { // // This is hidden for a reason. Do not use without fully understanding // executors. Misuing can easily cause your program to deadlock. -#[cfg(all(feature = "rt-threaded", feature = "blocking"))] -pub(crate) fn exit R, R>(f: F) -> R { - // Reset in case the closure panics - struct Reset(EnterContext); - impl Drop for Reset { - fn drop(&mut self) { - ENTERED.with(|c| { - assert!(!c.get().is_entered(), "closure claimed permanent executor"); - c.set(self.0); - }); +cfg_rt_threaded! { + pub(crate) fn exit R, R>(f: F) -> R { + // Reset in case the closure panics + struct Reset(EnterContext); + impl Drop for Reset { + fn drop(&mut self) { + ENTERED.with(|c| { + assert!(!c.get().is_entered(), "closure claimed permanent executor"); + c.set(self.0); + }); + } } - } - let was = ENTERED.with(|c| { - let e = c.get(); - assert!(e.is_entered(), "asked to exit when not entered"); - c.set(EnterContext::NotEntered); - e - }); + let was = ENTERED.with(|c| { + let e = c.get(); + assert!(e.is_entered(), "asked to exit when not entered"); + c.set(EnterContext::NotEntered); + e + }); - let _reset = Reset(was); - // dropping _reset after f() will reset ENTERED - f() + let _reset = Reset(was); + // dropping _reset after f() will reset ENTERED + f() + } } -cfg_rt_core! { - cfg_rt_util! { - /// Disallow blocking in the current runtime context until the guard is dropped. - pub(crate) fn disallow_blocking() -> DisallowBlockingGuard { - let reset = ENTERED.with(|c| { - if let EnterContext::Entered { - allow_blocking: true, - } = c.get() - { - c.set(EnterContext::Entered { - allow_blocking: false, - }); - true - } else { - false - } - }); - DisallowBlockingGuard(reset) - } +cfg_rt_util! { + /// Disallow blocking in the current runtime context until the guard is dropped. + pub(crate) fn disallow_blocking() -> DisallowBlockingGuard { + let reset = ENTERED.with(|c| { + if let EnterContext::Entered { + allow_blocking: true, + } = c.get() + { + c.set(EnterContext::Entered { + allow_blocking: false, + }); + true + } else { + false + } + }); + DisallowBlockingGuard(reset) + } - pub(crate) struct DisallowBlockingGuard(bool); - impl Drop for DisallowBlockingGuard { - fn drop(&mut self) { - if self.0 { - // XXX: Do we want some kind of assertion here, or is "best effort" okay? - ENTERED.with(|c| { - if let EnterContext::Entered { - allow_blocking: false, - } = c.get() - { - c.set(EnterContext::Entered { - allow_blocking: true, - }); - } - }) - } + pub(crate) struct DisallowBlockingGuard(bool); + impl Drop for DisallowBlockingGuard { + fn drop(&mut self) { + if self.0 { + // XXX: Do we want some kind of assertion here, or is "best effort" okay? + ENTERED.with(|c| { + if let EnterContext::Entered { + allow_blocking: false, + } = c.get() + { + c.set(EnterContext::Entered { + allow_blocking: true, + }); + } + }) } } } } cfg_rt_threaded! { - cfg_blocking! { - /// Returns true if in a runtime context. - pub(crate) fn context() -> EnterContext { - ENTERED.with(|c| c.get()) - } + /// Returns true if in a runtime context. + pub(crate) fn context() -> EnterContext { + ENTERED.with(|c| c.get()) } } -impl Enter { - /// Blocks the thread on the specified future, returning the value with - /// which that future completes. - pub(crate) fn block_on(&mut self, f: F) -> Result - where - F: std::future::Future, - { - use crate::park::{CachedParkThread, Park}; - use std::task::Context; - use std::task::Poll::Ready; - - let mut park = CachedParkThread::new(); - let waker = park.get_unpark()?.into_waker(); - let mut cx = Context::from_waker(&waker); - - pin!(f); - - loop { - if let Ready(v) = crate::coop::budget(|| f.as_mut().poll(&mut cx)) { - return Ok(v); - } +cfg_rt_core! { + impl Enter { + /// Blocks the thread on the specified future, returning the value with + /// which that future completes. + pub(crate) fn block_on(&mut self, f: F) -> Result + where + F: std::future::Future, + { + use crate::park::thread::CachedParkThread; - park.park()?; + let mut park = CachedParkThread::new(); + Ok(park.block_on(f)) } - } -} -cfg_blocking_impl! { - use crate::park::ParkError; - use std::time::Duration; - - impl Enter { /// Blocks the thread on the specified future for **at most** `timeout` /// /// If the future completes before `timeout`, the result is returned. If @@ -174,7 +159,8 @@ cfg_blocking_impl! { where F: std::future::Future, { - use crate::park::{CachedParkThread, Park}; + use crate::park::Park; + use crate::park::thread::CachedParkThread; use std::task::Context; use std::task::Poll::Ready; use std::time::Instant; diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 316e3b269f2..66dda988a12 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -181,42 +181,36 @@ //! [`Builder::enable_time`]: crate::runtime::Builder::enable_time //! [`Builder::enable_all`]: crate::runtime::Builder::enable_all -#![allow(missing_docs)] - // At the top due to macros #[cfg(test)] #[macro_use] mod tests; -pub(crate) mod context; - -mod basic_scheduler; -use basic_scheduler::BasicScheduler; +pub(crate) mod enter; pub(crate) mod task; -mod blocking; -use blocking::BlockingPool; +cfg_rt_core! { + mod basic_scheduler; + use basic_scheduler::BasicScheduler; -cfg_blocking_impl! { - #[allow(unused_imports)] - pub(crate) use blocking::{spawn_blocking, try_spawn_blocking}; -} + mod blocking; + use blocking::BlockingPool; + pub(crate) use blocking::spawn_blocking; -mod builder; -pub use self::builder::Builder; + mod builder; + pub use self::builder::Builder; -pub(crate) mod driver; + pub(crate) mod context; + pub(crate) mod driver; -pub(crate) mod enter; -use self::enter::enter; + use self::enter::enter; -mod handle; -use handle::Handle; + mod handle; + use handle::Handle; -mod io { - /// Re-exported for convenience. - pub(crate) use std::io::Result; + mod spawner; + use self::spawner::Spawner; } cfg_rt_threaded! { @@ -224,9 +218,6 @@ cfg_rt_threaded! { use park::Parker; } -mod spawner; -use self::spawner::Spawner; - cfg_rt_threaded! { mod queue; @@ -234,279 +225,268 @@ cfg_rt_threaded! { use self::thread_pool::ThreadPool; } -use crate::loom::sync::Arc; -use crate::task::JoinHandle; - -use std::future::Future; -use std::time::Duration; - -/// The Tokio runtime. -/// -/// The runtime provides an I/O driver, task scheduler, [timer], and blocking -/// pool, necessary for running asynchronous tasks. -/// -/// Instances of `Runtime` can be created using [`new_multi_thread`], [`new_current_thread`], -/// [`new_single_thread`], or [`Builder`]. However, most users will use the `#[tokio::main]` -/// annotation on their entry point instead. -/// -/// See [module level][mod] documentation for more details. -/// -/// # Shutdown -/// -/// Shutting down the runtime is done by dropping the value. The current thread -/// will block until the shut down operation has completed. -/// -/// * Drain any scheduled work queues. -/// * Drop any futures that have not yet completed. -/// * Drop the reactor. -/// -/// Once the reactor has dropped, any outstanding I/O resources bound to -/// that reactor will no longer function. Calling any method on them will -/// result in an error. -/// -/// [timer]: crate::time -/// [mod]: index.html -/// [`new`]: method@Self::new -/// [`Builder`]: struct@Builder -/// [`tokio::run`]: fn@run -#[derive(Debug)] -pub struct Runtime { - /// Task executor - kind: Kind, - - /// Handle to runtime, also contains driver handles - handle: Handle, - - /// Blocking pool handle, used to signal shutdown - blocking_pool: BlockingPool, -} - -/// The runtime executor is either a thread-pool or a current-thread executor. -#[derive(Debug)] -enum Kind { - /// Execute all tasks on the current-thread. - #[cfg(feature = "rt-core")] - CurrentThread(BasicScheduler), +cfg_rt_core! { + use crate::loom::sync::Arc; + use crate::task::JoinHandle; - #[cfg(feature = "rt-core")] - SingleThread(Arc>), - - /// Execute tasks across multiple threads. - #[cfg(feature = "rt-threaded")] - ThreadPool(ThreadPool), -} + use std::future::Future; + use std::time::Duration; -/// After thread starts / before thread stops -type Callback = std::sync::Arc; - -impl Runtime { - #[cfg(feature = "rt-threaded")] - pub fn new_multi_thread() -> io::Result { - Builder::new_multi_thread().enable_all().build() - } - - pub fn new_single_thread() -> io::Result { - Builder::new_single_thread().enable_all().build() - } - - pub fn new_current_thread() -> io::Result { - Builder::new_current_thread().enable_all().build() - } - - /// Spawn a future onto the Tokio runtime. + /// The Tokio runtime. /// - /// This spawns the given future onto the runtime's executor, usually a - /// thread pool. The thread pool is then responsible for polling the future - /// until it completes. + /// The runtime provides an I/O driver, task scheduler, [timer], and blocking + /// pool, necessary for running asynchronous tasks. /// - /// See [module level][mod] documentation for more details. + /// Instances of `Runtime` can be created using [`new_multi_thread`], [`new_current_thread`], + /// [`new_single_thread`], or [`Builder`]. However, most users will use the `#[tokio::main]` + /// annotation on their entry point instead. /// - /// [mod]: index.html - /// - /// # Examples + /// See [module level][mod] documentation for more details. /// - /// ``` - /// use tokio::runtime::Runtime; + /// # Shutdown /// - /// # fn dox() { - /// // Create the runtime - /// let rt = Runtime::new_multi_thread().unwrap(); + /// Shutting down the runtime is done by dropping the value. The current thread + /// will block until the shut down operation has completed. /// - /// // Spawn a future onto the runtime - /// rt.spawn(async { - /// println!("now running on a worker thread"); - /// }); - /// # } - /// ``` + /// * Drain any scheduled work queues. + /// * Drop any futures that have not yet completed. + /// * Drop the reactor. /// - /// # Panics + /// Once the reactor has dropped, any outstanding I/O resources bound to + /// that reactor will no longer function. Calling any method on them will + /// result in an error. /// - /// This function will panic if `rt-core` or `rt-threaded` features - /// are not enabled. - #[cfg(feature = "rt-core")] - pub fn spawn(&self, future: F) -> JoinHandle - where - F: Future + Send + 'static, - F::Output: Send + 'static, - { - match &self.kind { - #[cfg(feature = "rt-threaded")] - Kind::ThreadPool(exec) => exec.spawn(future), - Kind::CurrentThread(exec) => exec.spawn(future), - Kind::SingleThread(exec) => exec.spawn(future), - } + /// [timer]: crate::time + /// [mod]: index.html + /// [`new`]: method@Self::new + /// [`Builder`]: struct@Builder + /// [`tokio::run`]: fn@run + #[derive(Debug)] + pub struct Runtime { + /// Task executor + kind: Kind, + + /// Handle to runtime, also contains driver handles + handle: Handle, + + /// Blocking pool handle, used to signal shutdown + blocking_pool: BlockingPool, } - /// Run a future to completion on the Tokio runtime. This is the runtime's - /// entry point. - /// - /// This runs the given future on the runtime, blocking until it is - /// complete, and yielding its resolved result. Any tasks or timers which - /// the future spawns internally will be executed on the runtime. - /// - /// When this runtime is configured with `core_threads = 0`, only the first call - /// to `block_on` will run the IO and timer drivers. Calls to other methods _before_ the first - /// `block_on` completes will just hook into the driver running on the thread - /// that first called `block_on`. This means that the driver may be passed - /// from thread to thread by the user between calls to `block_on`. - /// - /// This method may not be called from an asynchronous context. - /// - /// # Panics - /// - /// This function panics if the provided future panics, or if called within an - /// asynchronous execution context. - /// - /// # Examples - /// - /// ```no_run - /// use tokio::runtime::Runtime; - /// - /// // Create the runtime - /// let rt = Runtime::new_multi_thread().unwrap(); - /// - /// // Execute the future, blocking the current thread until completion - /// rt.block_on(async { - /// println!("hello"); - /// }); - /// ``` - /// - /// [handle]: fn@Handle::block_on - pub fn block_on(&self, future: F) -> F::Output { - self.handle.enter(|| match &self.kind { - #[cfg(feature = "rt-core")] - Kind::CurrentThread(exec) => exec.block_on(future), - #[cfg(feature = "rt-core")] - Kind::SingleThread(exec) => exec.block_on(future), - #[cfg(feature = "rt-threaded")] - Kind::ThreadPool(exec) => exec.block_on(future), - }) - } + /// The runtime executor is either a thread-pool or a current-thread executor. + #[derive(Debug)] + enum Kind { + /// Execute all tasks on the current-thread. + #[cfg(feature = "rt-core")] + CurrentThread(BasicScheduler), - /// Enter the runtime context. This allows you to construct types that must - /// have an executor available on creation such as [`Sleep`] or [`TcpStream`]. - /// It will also allow you to call methods such as [`tokio::spawn`]. - /// - /// [`Sleep`]: struct@crate::time::Sleep - /// [`TcpStream`]: struct@crate::net::TcpStream - /// [`tokio::spawn`]: fn@crate::spawn - /// - /// # Example - /// - /// ``` - /// use tokio::runtime::Runtime; - /// - /// fn function_that_spawns(msg: String) { - /// // Had we not used `rt.enter` below, this would panic. - /// tokio::spawn(async move { - /// println!("{}", msg); - /// }); - /// } - /// - /// fn main() { - /// let rt = Runtime::new_multi_thread().unwrap(); - /// - /// let s = "Hello World!".to_string(); - /// - /// // By entering the context, we tie `tokio::spawn` to this executor. - /// rt.enter(|| function_that_spawns(s)); - /// } - /// ``` - pub fn enter(&self, f: F) -> R - where - F: FnOnce() -> R, - { - self.handle.enter(f) - } + #[cfg(feature = "rt-core")] + SingleThread(Arc>), - /// Shutdown the runtime, waiting for at most `duration` for all spawned - /// task to shutdown. - /// - /// Usually, dropping a `Runtime` handle is sufficient as tasks are able to - /// shutdown in a timely fashion. However, dropping a `Runtime` will wait - /// indefinitely for all tasks to terminate, and there are cases where a long - /// blocking task has been spawned, which can block dropping `Runtime`. - /// - /// In this case, calling `shutdown_timeout` with an explicit wait timeout - /// can work. The `shutdown_timeout` will signal all tasks to shutdown and - /// will wait for at most `duration` for all spawned tasks to terminate. If - /// `timeout` elapses before all tasks are dropped, the function returns and - /// outstanding tasks are potentially leaked. - /// - /// # Examples - /// - /// ``` - /// use tokio::runtime::Runtime; - /// use tokio::task; - /// - /// use std::thread; - /// use std::time::Duration; - /// - /// fn main() { - /// let runtime = Runtime::new_multi_thread().unwrap(); - /// - /// runtime.block_on(async move { - /// task::spawn_blocking(move || { - /// thread::sleep(Duration::from_secs(10_000)); - /// }); - /// }); - /// - /// runtime.shutdown_timeout(Duration::from_millis(100)); - /// } - /// ``` - pub fn shutdown_timeout(mut self, duration: Duration) { - // Wakeup and shutdown all the worker threads - self.handle.spawner.shutdown(); - self.blocking_pool.shutdown(Some(duration)); + /// Execute tasks across multiple threads. + #[cfg(feature = "rt-threaded")] + ThreadPool(ThreadPool), } - /// Shutdown the runtime, without waiting for any spawned tasks to shutdown. - /// - /// This can be useful if you want to drop a runtime from within another runtime. - /// Normally, dropping a runtime will block indefinitely for spawned blocking tasks - /// to complete, which would normally not be permitted within an asynchronous context. - /// By calling `shutdown_background()`, you can drop the runtime from such a context. - /// - /// Note however, that because we do not wait for any blocking tasks to complete, this - /// may result in a resource leak (in that any blocking tasks are still running until they - /// return. - /// - /// This function is equivalent to calling `shutdown_timeout(Duration::of_nanos(0))`. - /// - /// ``` - /// use tokio::runtime::Runtime; - /// - /// fn main() { - /// let runtime = Runtime::new_multi_thread().unwrap(); - /// - /// runtime.block_on(async move { - /// let inner_runtime = Runtime::new_multi_thread().unwrap(); - /// // ... - /// inner_runtime.shutdown_background(); - /// }); - /// } - /// ``` - pub fn shutdown_background(self) { - self.shutdown_timeout(Duration::from_nanos(0)) + /// After thread starts / before thread stops + type Callback = std::sync::Arc; + + impl Runtime { + /// Spawn a future onto the Tokio runtime. + /// + /// This spawns the given future onto the runtime's executor, usually a + /// thread pool. The thread pool is then responsible for polling the future + /// until it completes. + /// + /// See [module level][mod] documentation for more details. + /// + /// [mod]: index.html + /// + /// # Examples + /// + /// ``` + /// use tokio::runtime::Runtime; + /// + /// # fn dox() { + /// // Create the runtime + /// let rt = Runtime::new_multi_thread().unwrap(); + /// + /// // Spawn a future onto the runtime + /// rt.spawn(async { + /// println!("now running on a worker thread"); + /// }); + /// # } + /// ``` + /// + /// # Panics + /// + /// This function will panic if `rt-core` or `rt-threaded` features + /// are not enabled. + #[cfg(feature = "rt-core")] + pub fn spawn(&self, future: F) -> JoinHandle + where + F: Future + Send + 'static, + F::Output: Send + 'static, + { + match &self.kind { + #[cfg(feature = "rt-threaded")] + Kind::ThreadPool(exec) => exec.spawn(future), + Kind::CurrentThread(exec) => exec.spawn(future), + Kind::SingleThread(exec) => exec.spawn(future), + } + } + + /// Run a future to completion on the Tokio runtime. This is the runtime's + /// entry point. + /// + /// This runs the given future on the runtime, blocking until it is + /// complete, and yielding its resolved result. Any tasks or timers which + /// the future spawns internally will be executed on the runtime. + /// + /// When this runtime is configured with `core_threads = 0`, only the first call + /// to `block_on` will run the IO and timer drivers. Calls to other methods _before_ the first + /// `block_on` completes will just hook into the driver running on the thread + /// that first called `block_on`. This means that the driver may be passed + /// from thread to thread by the user between calls to `block_on`. + /// + /// This method may not be called from an asynchronous context. + /// + /// # Panics + /// + /// This function panics if the provided future panics, or if called within an + /// asynchronous execution context. + /// + /// # Examples + /// + /// ```no_run + /// use tokio::runtime::Runtime; + /// + /// // Create the runtime + /// let rt = Runtime::new_multi_thread().unwrap(); + /// + /// // Execute the future, blocking the current thread until completion + /// rt.block_on(async { + /// println!("hello"); + /// }); + /// ``` + /// + /// [handle]: fn@Handle::block_on + pub fn block_on(&self, future: F) -> F::Output { + self.handle.enter(|| match &self.kind { + #[cfg(feature = "rt-core")] + Kind::CurrentThread(exec) => exec.block_on(future), + #[cfg(feature = "rt-core")] + Kind::SingleThread(exec) => exec.block_on(future), + #[cfg(feature = "rt-threaded")] + Kind::ThreadPool(exec) => exec.block_on(future), + }) + } + + /// Enter the runtime context. This allows you to construct types that must + /// have an executor available on creation such as [`Sleep`] or [`TcpStream`]. + /// It will also allow you to call methods such as [`tokio::spawn`]. + /// + /// [`Sleep`]: struct@crate::time::Sleep + /// [`TcpStream`]: struct@crate::net::TcpStream + /// [`tokio::spawn`]: fn@crate::spawn + /// + /// # Example + /// + /// ``` + /// use tokio::runtime::Runtime; + /// + /// fn function_that_spawns(msg: String) { + /// // Had we not used `rt.enter` below, this would panic. + /// tokio::spawn(async move { + /// println!("{}", msg); + /// }); + /// } + /// + /// fn main() { + /// let rt = Runtime::new_multi_thread().unwrap(); + /// + /// let s = "Hello World!".to_string(); + /// + /// // By entering the context, we tie `tokio::spawn` to this executor. + /// rt.enter(|| function_that_spawns(s)); + /// } + /// ``` + pub fn enter(&self, f: F) -> R + where + F: FnOnce() -> R, + { + self.handle.enter(f) + } + + /// Shutdown the runtime, waiting for at most `duration` for all spawned + /// task to shutdown. + /// + /// Usually, dropping a `Runtime` handle is sufficient as tasks are able to + /// shutdown in a timely fashion. However, dropping a `Runtime` will wait + /// indefinitely for all tasks to terminate, and there are cases where a long + /// blocking task has been spawned, which can block dropping `Runtime`. + /// + /// In this case, calling `shutdown_timeout` with an explicit wait timeout + /// can work. The `shutdown_timeout` will signal all tasks to shutdown and + /// will wait for at most `duration` for all spawned tasks to terminate. If + /// `timeout` elapses before all tasks are dropped, the function returns and + /// outstanding tasks are potentially leaked. + /// + /// # Examples + /// + /// ``` + /// use tokio::runtime::Runtime; + /// use tokio::task; + /// + /// use std::thread; + /// use std::time::Duration; + /// + /// fn main() { + /// let runtime = Runtime::new_multi_thread().unwrap(); + /// + /// runtime.block_on(async move { + /// task::spawn_blocking(move || { + /// thread::sleep(Duration::from_secs(10_000)); + /// }); + /// }); + /// + /// runtime.shutdown_timeout(Duration::from_millis(100)); + /// } + /// ``` + pub fn shutdown_timeout(mut self, duration: Duration) { + // Wakeup and shutdown all the worker threads + self.handle.spawner.shutdown(); + self.blocking_pool.shutdown(Some(duration)); + } + + /// Shutdown the runtime, without waiting for any spawned tasks to shutdown. + /// + /// This can be useful if you want to drop a runtime from within another runtime. + /// Normally, dropping a runtime will block indefinitely for spawned blocking tasks + /// to complete, which would normally not be permitted within an asynchronous context. + /// By calling `shutdown_background()`, you can drop the runtime from such a context. + /// + /// Note however, that because we do not wait for any blocking tasks to complete, this + /// may result in a resource leak (in that any blocking tasks are still running until they + /// return. + /// + /// This function is equivalent to calling `shutdown_timeout(Duration::of_nanos(0))`. + /// + /// ``` + /// use tokio::runtime::Runtime; + /// + /// fn main() { + /// let runtime = Runtime::new_multi_thread().unwrap(); + /// + /// runtime.block_on(async move { + /// let inner_runtime = Runtime::new_multi_thread().unwrap(); + /// // ... + /// inner_runtime.shutdown_background(); + /// }); + /// } + /// ``` + pub fn shutdown_background(self) { + self.shutdown_timeout(Duration::from_nanos(0)) + } } } diff --git a/tokio/src/runtime/task/error.rs b/tokio/src/runtime/task/error.rs index 509642d4e86..4197ba605a4 100644 --- a/tokio/src/runtime/task/error.rs +++ b/tokio/src/runtime/task/error.rs @@ -3,7 +3,7 @@ use std::fmt; use std::io; use std::sync::Mutex; -doc_rt_core! { +cfg_task! { /// Task failed to execute to completion. pub struct JoinError { repr: Repr, diff --git a/tokio/src/runtime/task/join.rs b/tokio/src/runtime/task/join.rs index 9b73353d9c0..a63f5740556 100644 --- a/tokio/src/runtime/task/join.rs +++ b/tokio/src/runtime/task/join.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; -doc_rt_core! { +cfg_task! { /// An owned permission to join on a task (await its termination). /// /// This can be thought of as the equivalent of [`std::thread::JoinHandle`] for diff --git a/tokio/src/runtime/task/mod.rs b/tokio/src/runtime/task/mod.rs index 17b5157e848..d30a467f5bb 100644 --- a/tokio/src/runtime/task/mod.rs +++ b/tokio/src/runtime/task/mod.rs @@ -79,22 +79,24 @@ pub(crate) trait Schedule: Sync + Sized + 'static { } } -/// Create a new task with an associated join handle -pub(crate) fn joinable(task: T) -> (Notified, JoinHandle) -where - T: Future + Send + 'static, - S: Schedule, -{ - let raw = RawTask::new::<_, S>(task); - - let task = Task { - raw, - _p: PhantomData, - }; - - let join = JoinHandle::new(raw); - - (Notified(task), join) +cfg_rt_core! { + /// Create a new task with an associated join handle + pub(crate) fn joinable(task: T) -> (Notified, JoinHandle) + where + T: Future + Send + 'static, + S: Schedule, + { + let raw = RawTask::new::<_, S>(task); + + let task = Task { + raw, + _p: PhantomData, + }; + + let join = JoinHandle::new(raw); + + (Notified(task), join) + } } cfg_rt_util! { diff --git a/tokio/src/runtime/thread_pool/atomic_cell.rs b/tokio/src/runtime/thread_pool/atomic_cell.rs index 2bda0fc7387..98847e6ffa1 100644 --- a/tokio/src/runtime/thread_pool/atomic_cell.rs +++ b/tokio/src/runtime/thread_pool/atomic_cell.rs @@ -22,7 +22,6 @@ impl AtomicCell { from_raw(old) } - #[cfg(feature = "blocking")] pub(super) fn set(&self, val: Box) { let _ = self.swap(Some(val)); } diff --git a/tokio/src/runtime/thread_pool/mod.rs b/tokio/src/runtime/thread_pool/mod.rs index d30e8d456ca..e39695a97a6 100644 --- a/tokio/src/runtime/thread_pool/mod.rs +++ b/tokio/src/runtime/thread_pool/mod.rs @@ -9,9 +9,7 @@ use self::idle::Idle; mod worker; pub(crate) use worker::Launch; -cfg_blocking! { - pub(crate) use worker::block_in_place; -} +pub(crate) use worker::block_in_place; use crate::loom::sync::Arc; use crate::runtime::task::{self, JoinHandle}; diff --git a/tokio/src/runtime/thread_pool/worker.rs b/tokio/src/runtime/thread_pool/worker.rs index c88f995418c..bc544c9b4f2 100644 --- a/tokio/src/runtime/thread_pool/worker.rs +++ b/tokio/src/runtime/thread_pool/worker.rs @@ -9,6 +9,7 @@ use crate::loom::rand::seed; use crate::loom::sync::{Arc, Mutex}; use crate::park::{Park, Unpark}; use crate::runtime; +use crate::runtime::enter::EnterContext; use crate::runtime::park::{Parker, Unparker}; use crate::runtime::thread_pool::{AtomicCell, Idle}; use crate::runtime::{queue, task}; @@ -172,100 +173,96 @@ pub(super) fn create(size: usize, park: Parker) -> (Arc, Launch) { (shared, launch) } -cfg_blocking! { - use crate::runtime::enter::EnterContext; - - pub(crate) fn block_in_place(f: F) -> R - where - F: FnOnce() -> R, - { - // Try to steal the worker core back - struct Reset(coop::Budget); - - impl Drop for Reset { - fn drop(&mut self) { - CURRENT.with(|maybe_cx| { - if let Some(cx) = maybe_cx { - let core = cx.worker.core.take(); - let mut cx_core = cx.core.borrow_mut(); - assert!(cx_core.is_none()); - *cx_core = core; - - // Reset the task budget as we are re-entering the - // runtime. - coop::set(self.0); - } - }); - } +pub(crate) fn block_in_place(f: F) -> R +where + F: FnOnce() -> R, +{ + // Try to steal the worker core back + struct Reset(coop::Budget); + + impl Drop for Reset { + fn drop(&mut self) { + CURRENT.with(|maybe_cx| { + if let Some(cx) = maybe_cx { + let core = cx.worker.core.take(); + let mut cx_core = cx.core.borrow_mut(); + assert!(cx_core.is_none()); + *cx_core = core; + + // Reset the task budget as we are re-entering the + // runtime. + coop::set(self.0); + } + }); } + } - let mut had_entered = false; + let mut had_entered = false; - CURRENT.with(|maybe_cx| { - match (crate::runtime::enter::context(), maybe_cx.is_some()) { - (EnterContext::Entered { .. }, true) => { - // We are on a thread pool runtime thread, so we just need to set up blocking. + CURRENT.with(|maybe_cx| { + match (crate::runtime::enter::context(), maybe_cx.is_some()) { + (EnterContext::Entered { .. }, true) => { + // We are on a thread pool runtime thread, so we just need to set up blocking. + had_entered = true; + } + (EnterContext::Entered { allow_blocking }, false) => { + // We are on an executor, but _not_ on the thread pool. + // That is _only_ okay if we are in a thread pool runtime's block_on method: + if allow_blocking { had_entered = true; - } - (EnterContext::Entered { allow_blocking }, false) => { - // We are on an executor, but _not_ on the thread pool. - // That is _only_ okay if we are in a thread pool runtime's block_on method: - if allow_blocking { - had_entered = true; - return; - } else { - // This probably means we are on the basic_scheduler or in a LocalSet, - // where it is _not_ okay to block. - panic!("can call blocking only when running on the multi-threaded runtime"); - } - } - (EnterContext::NotEntered, true) => { - // This is a nested call to block_in_place (we already exited). - // All the necessary setup has already been done. - return; - } - (EnterContext::NotEntered, false) => { - // We are outside of the tokio runtime, so blocking is fine. - // We can also skip all of the thread pool blocking setup steps. return; + } else { + // This probably means we are on the basic_scheduler or in a LocalSet, + // where it is _not_ okay to block. + panic!("can call blocking only when running on the multi-threaded runtime"); } } + (EnterContext::NotEntered, true) => { + // This is a nested call to block_in_place (we already exited). + // All the necessary setup has already been done. + return; + } + (EnterContext::NotEntered, false) => { + // We are outside of the tokio runtime, so blocking is fine. + // We can also skip all of the thread pool blocking setup steps. + return; + } + } - let cx = maybe_cx.expect("no .is_some() == false cases above should lead here"); - - // Get the worker core. If none is set, then blocking is fine! - let core = match cx.core.borrow_mut().take() { - Some(core) => core, - None => return, - }; - - // The parker should be set here - assert!(core.park.is_some()); + let cx = maybe_cx.expect("no .is_some() == false cases above should lead here"); - // In order to block, the core must be sent to another thread for - // execution. - // - // First, move the core back into the worker's shared core slot. - cx.worker.core.set(core); + // Get the worker core. If none is set, then blocking is fine! + let core = match cx.core.borrow_mut().take() { + Some(core) => core, + None => return, + }; - // Next, clone the worker handle and send it to a new thread for - // processing. - // - // Once the blocking task is done executing, we will attempt to - // steal the core back. - let worker = cx.worker.clone(); - runtime::spawn_blocking(move || run(worker)); - }); + // The parker should be set here + assert!(core.park.is_some()); + + // In order to block, the core must be sent to another thread for + // execution. + // + // First, move the core back into the worker's shared core slot. + cx.worker.core.set(core); + + // Next, clone the worker handle and send it to a new thread for + // processing. + // + // Once the blocking task is done executing, we will attempt to + // steal the core back. + let worker = cx.worker.clone(); + runtime::spawn_blocking(move || run(worker)); + }); - if had_entered { - // Unset the current task's budget. Blocking sections are not - // constrained by task budgets. - let _reset = Reset(coop::stop()); + if had_entered { + // Unset the current task's budget. Blocking sections are not + // constrained by task budgets. + let _reset = Reset(coop::stop()); - crate::runtime::enter::exit(f) - } else { - f() - } + crate::runtime::enter::exit(f) + } else { + f() } } diff --git a/tokio/src/signal/unix/driver.rs b/tokio/src/signal/unix/driver.rs index 86d40a60ece..d4a497835d4 100644 --- a/tokio/src/signal/unix/driver.rs +++ b/tokio/src/signal/unix/driver.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "rt-core"), allow(dead_code))] + //! Signal driver use crate::io::driver::Driver as IoDriver; diff --git a/tokio/src/sync/mod.rs b/tokio/src/sync/mod.rs index ed9f07a0e76..f2d8dba2acd 100644 --- a/tokio/src/sync/mod.rs +++ b/tokio/src/sync/mod.rs @@ -437,7 +437,7 @@ cfg_sync! { mod mutex; pub use mutex::{Mutex, MutexGuard, TryLockError, OwnedMutexGuard}; - mod notify; + pub(crate) mod notify; pub use notify::Notify; pub mod oneshot; @@ -464,8 +464,8 @@ cfg_not_sync! { pub(crate) use mutex::Mutex; } - mod notify; - pub(crate) use notify::Notify; + #[cfg(any(feature = "process", feature = "rt-core", feature = "signal"))] + pub(crate) mod notify; cfg_atomic_waker_impl! { mod task; diff --git a/tokio/src/sync/mpsc/bounded.rs b/tokio/src/sync/mpsc/bounded.rs index 38fb753e5ae..3e3d81defb9 100644 --- a/tokio/src/sync/mpsc/bounded.rs +++ b/tokio/src/sync/mpsc/bounded.rs @@ -178,9 +178,9 @@ impl Receiver { /// sync_code.join().unwrap() /// } /// ``` + #[cfg(feature = "sync")] pub fn blocking_recv(&mut self) -> Option { - let mut enter_handle = crate::runtime::enter::enter(false); - enter_handle.block_on(self.recv()).unwrap() + crate::future::block_on(self.recv()) } /// Attempts to return a pending value on this receiver without blocking. @@ -518,9 +518,9 @@ impl Sender { /// sync_code.join().unwrap() /// } /// ``` + #[cfg(feature = "sync")] pub fn blocking_send(&self, value: T) -> Result<(), SendError> { - let mut enter_handle = crate::runtime::enter::enter(false); - enter_handle.block_on(self.send(value)).unwrap() + crate::future::block_on(self.send(value)) } /// Checks if the channel has been closed. This happens when the diff --git a/tokio/src/sync/mpsc/chan.rs b/tokio/src/sync/mpsc/chan.rs index 6fedb5c5f00..d8a02438815 100644 --- a/tokio/src/sync/mpsc/chan.rs +++ b/tokio/src/sync/mpsc/chan.rs @@ -4,7 +4,7 @@ use crate::loom::sync::atomic::AtomicUsize; use crate::loom::sync::Arc; use crate::sync::mpsc::error::TryRecvError; use crate::sync::mpsc::list; -use crate::sync::Notify; +use crate::sync::notify::Notify; use std::fmt; use std::process; diff --git a/tokio/src/task/blocking.rs b/tokio/src/task/blocking.rs index 362c1c01dcb..e264286f9dc 100644 --- a/tokio/src/task/blocking.rs +++ b/tokio/src/task/blocking.rs @@ -52,79 +52,77 @@ cfg_rt_threaded! { } } -cfg_blocking! { - /// Runs the provided closure on a thread where blocking is acceptable. - /// - /// In general, issuing a blocking call or performing a lot of compute in a - /// future without yielding is not okay, as it may prevent the executor from - /// driving other futures forward. This function runs the provided closure - /// on a thread dedicated to blocking operations. See the [CPU-bound tasks - /// and blocking code][blocking] section for more information. - /// - /// Tokio will spawn more blocking threads when they are requested through - /// this function until the upper limit configured on the [`Builder`] is - /// reached. This limit is very large by default, because `spawn_blocking` is - /// often used for various kinds of IO operations that cannot be performed - /// asynchronously. When you run CPU-bound code using `spawn_blocking`, you - /// should keep this large upper limit in mind; to run your CPU-bound - /// computations on only a few threads, you should use a separate thread - /// pool such as [rayon] rather than configuring the number of blocking - /// threads. - /// - /// This function is intended for non-async operations that eventually - /// finish on their own. If you want to spawn an ordinary thread, you should - /// use [`thread::spawn`] instead. - /// - /// Closures spawned using `spawn_blocking` cannot be cancelled. When you - /// shut down the executor, it will wait indefinitely for all blocking - /// operations to finish. You can use [`shutdown_timeout`] to stop waiting - /// for them after a certain timeout. Be aware that this will still not - /// cancel the tasks — they are simply allowed to keep running after the - /// method returns. - /// - /// Note that if you are using the single threaded runtime, this function will - /// still spawn additional threads for blocking operations. The basic - /// scheduler's single thread is only used for asynchronous code. - /// - /// [`Builder`]: struct@crate::runtime::Builder - /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code - /// [rayon]: https://docs.rs/rayon - /// [`thread::spawn`]: fn@std::thread::spawn - /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout - /// - /// # Examples - /// - /// ``` - /// use tokio::task; - /// - /// # async fn docs() -> Result<(), Box>{ - /// let res = task::spawn_blocking(move || { - /// // do some compute-heavy work or call synchronous code - /// "done computing" - /// }).await?; - /// - /// assert_eq!(res, "done computing"); - /// # Ok(()) - /// # } - /// ``` - pub fn spawn_blocking(f: F) -> JoinHandle - where - F: FnOnce() -> R + Send + 'static, - R: Send + 'static, - { - #[cfg(feature = "tracing")] - let f = { - let span = tracing::trace_span!( - target: "tokio::task", - "task", - kind = %"blocking", - function = %std::any::type_name::(), - ); - move || { - let _g = span.enter(); - f() - } - }; - crate::runtime::spawn_blocking(f) - } +/// Runs the provided closure on a thread where blocking is acceptable. +/// +/// In general, issuing a blocking call or performing a lot of compute in a +/// future without yielding is not okay, as it may prevent the executor from +/// driving other futures forward. This function runs the provided closure +/// on a thread dedicated to blocking operations. See the [CPU-bound tasks +/// and blocking code][blocking] section for more information. +/// +/// Tokio will spawn more blocking threads when they are requested through +/// this function until the upper limit configured on the [`Builder`] is +/// reached. This limit is very large by default, because `spawn_blocking` is +/// often used for various kinds of IO operations that cannot be performed +/// asynchronously. When you run CPU-bound code using `spawn_blocking`, you +/// should keep this large upper limit in mind; to run your CPU-bound +/// computations on only a few threads, you should use a separate thread +/// pool such as [rayon] rather than configuring the number of blocking +/// threads. +/// +/// This function is intended for non-async operations that eventually +/// finish on their own. If you want to spawn an ordinary thread, you should +/// use [`thread::spawn`] instead. +/// +/// Closures spawned using `spawn_blocking` cannot be cancelled. When you +/// shut down the executor, it will wait indefinitely for all blocking +/// operations to finish. You can use [`shutdown_timeout`] to stop waiting +/// for them after a certain timeout. Be aware that this will still not +/// cancel the tasks — they are simply allowed to keep running after the +/// method returns. +/// +/// Note that if you are using the single threaded runtime, this function will +/// still spawn additional threads for blocking operations. The basic +/// scheduler's single thread is only used for asynchronous code. +/// +/// [`Builder`]: struct@crate::runtime::Builder +/// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code +/// [rayon]: https://docs.rs/rayon +/// [`thread::spawn`]: fn@std::thread::spawn +/// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout +/// +/// # Examples +/// +/// ``` +/// use tokio::task; +/// +/// # async fn docs() -> Result<(), Box>{ +/// let res = task::spawn_blocking(move || { +/// // do some compute-heavy work or call synchronous code +/// "done computing" +/// }).await?; +/// +/// assert_eq!(res, "done computing"); +/// # Ok(()) +/// # } +/// ``` +pub fn spawn_blocking(f: F) -> JoinHandle +where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, +{ + #[cfg(feature = "tracing")] + let f = { + let span = tracing::trace_span!( + target: "tokio::task", + "task", + kind = %"blocking", + function = %std::any::type_name::(), + ); + move || { + let _g = span.enter(); + f() + } + }; + crate::runtime::spawn_blocking(f) } diff --git a/tokio/src/task/local.rs b/tokio/src/task/local.rs index 54280fabbc4..920c56b6e21 100644 --- a/tokio/src/task/local.rs +++ b/tokio/src/task/local.rs @@ -346,6 +346,8 @@ impl LocalSet { /// [`Runtime::block_on`]: method@crate::runtime::Runtime::block_on /// [in-place blocking]: fn@crate::task::block_in_place /// [`spawn_blocking`]: fn@crate::task::spawn_blocking + #[cfg(feature = "rt-core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rt-core")))] pub fn block_on(&self, rt: &crate::runtime::Runtime, future: F) -> F::Output where F: Future, diff --git a/tokio/src/task/mod.rs b/tokio/src/task/mod.rs index 5c89393a5e2..860c8929e28 100644 --- a/tokio/src/task/mod.rs +++ b/tokio/src/task/mod.rs @@ -214,26 +214,27 @@ //! [rt-threaded]: ../runtime/index.html#threaded-scheduler //! [`task::yield_now`]: crate::task::yield_now() //! [`thread::yield_now`]: std::thread::yield_now -cfg_blocking! { - mod blocking; - pub use blocking::spawn_blocking; - cfg_rt_threaded! { - pub use blocking::block_in_place; - } +cfg_task! { + pub use crate::runtime::task::{JoinError, JoinHandle}; } cfg_rt_core! { - pub use crate::runtime::task::{JoinError, JoinHandle}; + mod blocking; + pub use blocking::spawn_blocking; mod spawn; pub use spawn::spawn; - mod yield_now; - pub use yield_now::yield_now; + cfg_rt_threaded! { + pub use blocking::block_in_place; + } } cfg_rt_util! { + mod yield_now; + pub use yield_now::yield_now; + mod local; pub use local::{spawn_local, LocalSet}; diff --git a/tokio/src/task/yield_now.rs b/tokio/src/task/yield_now.rs index e0e20841c96..97e2db2c0e6 100644 --- a/tokio/src/task/yield_now.rs +++ b/tokio/src/task/yield_now.rs @@ -2,7 +2,7 @@ use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; -doc_rt_core! { +cfg_rt_util! { /// Yields execution back to the Tokio runtime. /// /// A task yields by awaiting on `yield_now()`, and may resume when that diff --git a/tokio/src/time/clock.rs b/tokio/src/time/clock.rs index 80682d59a8a..a562ed33898 100644 --- a/tokio/src/time/clock.rs +++ b/tokio/src/time/clock.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "rt-core"), allow(dead_code))] + //! Source of time abstraction. //! //! By default, `std::time::Instant::now()` is used. However, when the diff --git a/tokio/src/time/driver/mod.rs b/tokio/src/time/driver/mod.rs index 94e905b4e87..d3d65f04e77 100644 --- a/tokio/src/time/driver/mod.rs +++ b/tokio/src/time/driver/mod.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "rt-core"), allow(dead_code))] + //! Time driver mod atomic_stack; diff --git a/tokio/src/util/linked_list.rs b/tokio/src/util/linked_list.rs index 5692743f4e5..b13fc6b7df4 100644 --- a/tokio/src/util/linked_list.rs +++ b/tokio/src/util/linked_list.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "full"), allow(dead_code))] + //! An intrusive double linked list of data //! //! The data structure supports tracking pinned nodes. Most of the data diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index 8c1342c4ecf..e1bcb4b89eb 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -3,7 +3,17 @@ cfg_io_driver! { pub(crate) mod slab; } -#[cfg(any(feature = "sync", feature = "rt-core", feature = "io-driver"))] +#[cfg(any( + feature = "fs", + feature = "process", + feature = "rt-core", + feature = "rt-util", + feature = "sync", + feature = "signal", + feature = "tcp", + feature = "udp", + feature = "uds", +))] pub(crate) mod linked_list; #[cfg(any(feature = "rt-threaded", feature = "macros", feature = "stream"))] diff --git a/tokio/src/util/slab.rs b/tokio/src/util/slab.rs index aa1e2362052..d5af2658431 100644 --- a/tokio/src/util/slab.rs +++ b/tokio/src/util/slab.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "rt-core"), allow(dead_code))] + use crate::loom::cell::UnsafeCell; use crate::loom::sync::atomic::{AtomicBool, AtomicUsize}; use crate::loom::sync::{Arc, Mutex}; diff --git a/tokio/src/util/trace.rs b/tokio/src/util/trace.rs index d8c6120d97c..adec55024c3 100644 --- a/tokio/src/util/trace.rs +++ b/tokio/src/util/trace.rs @@ -1,5 +1,5 @@ cfg_trace! { - cfg_rt_core! { + cfg_task! { use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; @@ -47,7 +47,7 @@ cfg_trace! { } cfg_not_trace! { - cfg_rt_core! { + cfg_task! { #[inline] pub(crate) fn task(task: F, _: &'static str) -> F { // nop From 53f28e2a2af97f5e5fd231464e3505c1f4967e09 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 16:06:37 -0700 Subject: [PATCH 18/39] remove stray blocking cfgs --- tokio/src/runtime/blocking/pool.rs | 3 --- tokio/src/runtime/builder.rs | 6 ------ tokio/src/task/blocking.rs | 1 - 3 files changed, 10 deletions(-) diff --git a/tokio/src/runtime/blocking/pool.rs b/tokio/src/runtime/blocking/pool.rs index df0175b154b..2d44f896c1b 100644 --- a/tokio/src/runtime/blocking/pool.rs +++ b/tokio/src/runtime/blocking/pool.rs @@ -94,10 +94,7 @@ where impl BlockingPool { pub(crate) fn new(builder: &Builder, thread_cap: usize) -> BlockingPool { let (shutdown_tx, shutdown_rx) = shutdown::channel(); - #[cfg(feature = "blocking")] let keep_alive = builder.keep_alive.unwrap_or(KEEP_ALIVE); - #[cfg(not(feature = "blocking"))] - let keep_alive = KEEP_ALIVE; BlockingPool { spawner: Spawner { diff --git a/tokio/src/runtime/builder.rs b/tokio/src/runtime/builder.rs index 6de1439b40b..7e41d5630e8 100644 --- a/tokio/src/runtime/builder.rs +++ b/tokio/src/runtime/builder.rs @@ -3,7 +3,6 @@ use crate::runtime::{blocking, driver, Callback, Runtime, Spawner}; use std::fmt; use std::io; -#[cfg(feature = "blocking")] use std::time::Duration; /// Builds Tokio Runtime with custom configuration values. @@ -66,8 +65,6 @@ pub struct Builder { /// To run before each worker thread stops pub(super) before_stop: Option, - #[cfg(feature = "blocking")] - #[cfg_attr(docsrs, doc(cfg(feature = "blocking")))] /// Customizable keep alive timeout for BlockingPool pub(super) keep_alive: Option, } @@ -127,7 +124,6 @@ impl Builder { after_start: None, before_stop: None, - #[cfg(feature = "blocking")] keep_alive: None, } } @@ -403,8 +399,6 @@ impl Builder { } } - #[cfg(feature = "blocking")] - #[cfg_attr(docsrs, doc(cfg(feature = "blocking")))] /// Sets a custom timeout for a thread in the blocking pool. /// /// By default, the timeout for a thread is set to 10 seconds. This can diff --git a/tokio/src/task/blocking.rs b/tokio/src/task/blocking.rs index e264286f9dc..1a79834cddb 100644 --- a/tokio/src/task/blocking.rs +++ b/tokio/src/task/blocking.rs @@ -43,7 +43,6 @@ cfg_rt_threaded! { /// }); /// # } /// ``` - #[cfg_attr(docsrs, doc(cfg(feature = "blocking")))] pub fn block_in_place(f: F) -> R where F: FnOnce() -> R, From 456af82195827be2b4afe36789986ff0b1c874c6 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 16:29:12 -0700 Subject: [PATCH 19/39] fix tests --- tokio-macros/src/entry.rs | 4 +- tokio/src/io/stdio_common.rs | 3 +- tokio/src/park/thread.rs | 8 +-- tokio/src/runtime/builder.rs | 107 +++++++++------------------------- tokio/src/runtime/enter.rs | 2 +- tokio/src/runtime/mod.rs | 48 ++++++++++++--- tokio/src/signal/registry.rs | 2 +- tokio/tests/rt_common.rs | 12 ---- tokio/tests/rt_threaded.rs | 2 +- tokio/tests/sync_mpsc.rs | 4 +- tokio/tests/task_blocking.rs | 12 ++-- tokio/tests/task_local_set.rs | 2 +- tokio/tests/time_rt.rs | 2 +- 13 files changed, 88 insertions(+), 120 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index fd7b021d136..7634c9688c7 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -272,7 +272,7 @@ pub(crate) mod old { Runtime::Threaded | Runtime::Auto => quote! { #(#attrs)* #vis #sig { - tokio::runtime::Runtime::new_multi_thread().unwrap().block_on(async { #body }) + tokio::runtime::Runtime::new().unwrap().block_on(async { #body }) } }, Runtime::Basic => quote! { @@ -346,7 +346,7 @@ pub(crate) mod old { #[::core::prelude::v1::test] #(#attrs)* #vis fn #name() #ret { - tokio::runtime::Runtime::new_multi_thread().unwrap().block_on(async { #body }) + tokio::runtime::Runtime::new().unwrap().block_on(async { #body }) } }, Runtime::Basic | Runtime::Auto => quote! { diff --git a/tokio/src/io/stdio_common.rs b/tokio/src/io/stdio_common.rs index 9bda64e10a7..d21c842f543 100644 --- a/tokio/src/io/stdio_common.rs +++ b/tokio/src/io/stdio_common.rs @@ -199,8 +199,7 @@ mod tests { data.extend(std::iter::repeat(0b1010_1010).take(MAX_BUF - checked_count + 1)); let mut writer = LoggingMockWriter::new(); let mut splitter = super::SplitByUtf8BoundaryIfWindows::new(&mut writer); - crate::runtime::Builder::new() - .basic_scheduler() + crate::runtime::Builder::new_current_thread() .build() .unwrap() .block_on(async { diff --git a/tokio/src/park/thread.rs b/tokio/src/park/thread.rs index 054da0a51bb..2725e4563e9 100644 --- a/tokio/src/park/thread.rs +++ b/tokio/src/park/thread.rs @@ -249,22 +249,22 @@ impl CachedParkThread { CURRENT_PARKER.try_with(|inner| f(inner)).map_err(|_| ()) } - pub(crate) fn block_on(&mut self, f: F) -> F::Output { + pub(crate) fn block_on(&mut self, f: F) -> Result { use std::task::Context; use std::task::Poll::Ready; // `get_unpark()` should not return a Result - let waker = self.get_unpark().unwrap().into_waker(); + let waker = self.get_unpark()?.into_waker(); let mut cx = Context::from_waker(&waker); pin!(f); loop { if let Ready(v) = crate::coop::budget(|| f.as_mut().poll(&mut cx)) { - return v; + return Ok(v); } - self.park().unwrap(); + self.park()?; } } } diff --git a/tokio/src/runtime/builder.rs b/tokio/src/runtime/builder.rs index 7e41d5630e8..8e76f52b966 100644 --- a/tokio/src/runtime/builder.rs +++ b/tokio/src/runtime/builder.rs @@ -73,7 +73,6 @@ pub(crate) type ThreadNameFn = std::sync::Arc String + Send + Sync + pub(crate) enum Kind { CurrentThread, - SingleThread, #[cfg(feature = "rt-threaded")] MultiThread, } @@ -84,11 +83,6 @@ impl Builder { Builder::new(Kind::CurrentThread) } - /// TODO - pub fn new_single_thread() -> Builder { - Builder::new(Kind::SingleThread) - } - /// TODO #[cfg(feature = "rt-threaded")] pub fn new_multi_thread() -> Builder { @@ -161,8 +155,8 @@ impl Builder { /// Sets the number of worker threads the `Runtime` will use. /// - /// This should be a number between 0 and 32,768 though it is advised to keep - /// this value on the smaller side. + /// This should be a number between 0 and 32,768 though it is advised to + /// keep this value on the smaller side. /// /// # Default /// @@ -170,8 +164,8 @@ impl Builder { /// /// # Panic /// - /// When using the `current_thread` or `single_thread` runtime's this method will - /// panic, since those variants do not allow setting worker thread counts. + /// When using the `current_thread` runtime this method will panic, since + /// those variants do not allow setting worker thread counts. /// /// /// # Examples @@ -204,20 +198,6 @@ impl Builder { /// // This will run the runtime and future on the current thread /// rt.block_on(async move {}); /// ``` - /// - /// ## Single threaded runtime - /// - /// ``` - /// use tokio::runtime; - /// - /// // Spawn a single threaded runtime on a background thread. - /// let rt = runtime::Builder::new_single_thread() - /// .build() - /// .unwrap(); - /// - /// // This will run the future on the single worker thread. - /// rt.spawn(async move {}); - /// ``` pub fn worker_threads(&mut self, val: usize) -> &mut Self { self.worker_threads = Some(val); self @@ -385,8 +365,7 @@ impl Builder { /// ``` pub fn build(&mut self) -> io::Result { match &self.kind { - Kind::CurrentThread => self.build_basic_runtime(true), - Kind::SingleThread => self.build_basic_runtime(false), + Kind::CurrentThread => self.build_basic_runtime(), #[cfg(feature = "rt-threaded")] Kind::MultiThread => self.build_threaded_runtime(), } @@ -421,66 +400,34 @@ impl Builder { self } - fn build_basic_runtime(&mut self, current_thread: bool) -> io::Result { + fn build_basic_runtime(&mut self) -> io::Result { use crate::runtime::{BasicScheduler, Kind}; let (driver, resources) = driver::Driver::new(self.get_cfg())?; - if current_thread { - // And now put a single-threaded scheduler on top of the timer. When - // there are no futures ready to do something, it'll let the timer or - // the reactor to generate some new stimuli for the futures to continue - // in their life. - let scheduler = BasicScheduler::new(driver); - let spawner = Spawner::Basic(scheduler.spawner().clone()); - - // Blocking pool - let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); - let blocking_spawner = blocking_pool.spawner().clone(); - - Ok(Runtime { - kind: Kind::CurrentThread(scheduler), - handle: Handle { - spawner, - io_handle: resources.io_handle, - time_handle: resources.time_handle, - signal_handle: resources.signal_handle, - clock: resources.clock, - blocking_spawner, - }, - blocking_pool, - }) - } else { - use crate::loom::sync::Arc; - // use crate::future::poll_fn; - // use std::task::Poll; + // And now put a single-threaded scheduler on top of the timer. When + // there are no futures ready to do something, it'll let the timer or + // the reactor to generate some new stimuli for the futures to continue + // in their life. + let scheduler = BasicScheduler::new(driver); + let spawner = Spawner::Basic(scheduler.spawner().clone()); - let scheduler = Arc::new(BasicScheduler::new(driver)); - let spawner = Spawner::Basic(scheduler.spawner().clone()); + // Blocking pool + let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); + let blocking_spawner = blocking_pool.spawner().clone(); - // Blocking pool - let blocking_pool = blocking::create_blocking_pool(self, self.max_threads); - let blocking_spawner = blocking_pool.spawner().clone(); - - // TODO(lucio): fix this in the basic scheduler - // let scheduler2 = scheduler.clone(); - // std::thread::spawn(move || { - // scheduler2.block_on(poll_fn::<(), _>(|_| Poll::Pending)); - // }); - - Ok(Runtime { - kind: Kind::SingleThread(scheduler), - handle: Handle { - spawner, - io_handle: resources.io_handle, - time_handle: resources.time_handle, - signal_handle: resources.signal_handle, - clock: resources.clock, - blocking_spawner, - }, - blocking_pool, - }) - } + Ok(Runtime { + kind: Kind::CurrentThread(scheduler), + handle: Handle { + spawner, + io_handle: resources.io_handle, + time_handle: resources.time_handle, + signal_handle: resources.signal_handle, + clock: resources.clock, + blocking_spawner, + }, + blocking_pool, + }) } } diff --git a/tokio/src/runtime/enter.rs b/tokio/src/runtime/enter.rs index 7bf046f75fd..79ed4d17f08 100644 --- a/tokio/src/runtime/enter.rs +++ b/tokio/src/runtime/enter.rs @@ -148,7 +148,7 @@ cfg_rt_core! { use crate::park::thread::CachedParkThread; let mut park = CachedParkThread::new(); - Ok(park.block_on(f)) + park.block_on(f) } /// Blocks the thread on the specified future for **at most** `timeout` diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 66dda988a12..fd9951ec617 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -226,10 +226,10 @@ cfg_rt_threaded! { } cfg_rt_core! { - use crate::loom::sync::Arc; use crate::task::JoinHandle; use std::future::Future; + use std::io; use std::time::Duration; /// The Tokio runtime. @@ -280,9 +280,6 @@ cfg_rt_core! { #[cfg(feature = "rt-core")] CurrentThread(BasicScheduler), - #[cfg(feature = "rt-core")] - SingleThread(Arc>), - /// Execute tasks across multiple threads. #[cfg(feature = "rt-threaded")] ThreadPool(ThreadPool), @@ -292,6 +289,46 @@ cfg_rt_core! { type Callback = std::sync::Arc; impl Runtime { + /// Create a new runtime instance with default configuration values. + /// + /// This results in a scheduler, I/O driver, and time driver being + /// initialized. The type of scheduler used depends on what feature flags + /// are enabled: if the `rt-threaded` feature is enabled, the [threaded + /// scheduler] is used, while if only the `rt-core` feature is enabled, the + /// [basic scheduler] is used instead. + /// + /// If the threaded scheduler is selected, it will not spawn + /// any worker threads until it needs to, i.e. tasks are scheduled to run. + /// + /// Most applications will not need to call this function directly. Instead, + /// they will use the [`#[tokio::main]` attribute][main]. When more complex + /// configuration is necessary, the [runtime builder] may be used. + /// + /// See [module level][mod] documentation for more details. + /// + /// # Examples + /// + /// Creating a new `Runtime` with default configuration values. + /// + /// ``` + /// use tokio::runtime::Runtime; + /// + /// let rt = Runtime::new() + /// .unwrap(); + /// + /// // Use the runtime... + /// ``` + /// + /// [mod]: index.html + /// [main]: ../attr.main.html + /// [threaded scheduler]: index.html#threaded-scheduler + /// [basic scheduler]: index.html#basic-scheduler + /// [runtime builder]: crate::runtime::Builder + #[cfg(feature = "rt-threaded")] + pub fn new() -> io::Result { + Builder::new_multi_thread().enable_all().build() + } + /// Spawn a future onto the Tokio runtime. /// /// This spawns the given future onto the runtime's executor, usually a @@ -332,7 +369,6 @@ cfg_rt_core! { #[cfg(feature = "rt-threaded")] Kind::ThreadPool(exec) => exec.spawn(future), Kind::CurrentThread(exec) => exec.spawn(future), - Kind::SingleThread(exec) => exec.spawn(future), } } @@ -375,8 +411,6 @@ cfg_rt_core! { self.handle.enter(|| match &self.kind { #[cfg(feature = "rt-core")] Kind::CurrentThread(exec) => exec.block_on(future), - #[cfg(feature = "rt-core")] - Kind::SingleThread(exec) => exec.block_on(future), #[cfg(feature = "rt-threaded")] Kind::ThreadPool(exec) => exec.block_on(future), }) diff --git a/tokio/src/signal/registry.rs b/tokio/src/signal/registry.rs index bc8473040d1..5d6f608c607 100644 --- a/tokio/src/signal/registry.rs +++ b/tokio/src/signal/registry.rs @@ -247,7 +247,7 @@ mod tests { #[test] fn broadcast_cleans_up_disconnected_listeners() { - let rt = Runtime::new_multi_thread().unwrap(); + let rt = Runtime::new().unwrap(); rt.block_on(async { let registry = Registry::new(vec![EventInfo::default()]); diff --git a/tokio/tests/rt_common.rs b/tokio/tests/rt_common.rs index 852bb3fa17e..a4091616ecf 100644 --- a/tokio/tests/rt_common.rs +++ b/tokio/tests/rt_common.rs @@ -18,18 +18,6 @@ macro_rules! rt_test { } } - mod single_thread_scheduler { - $($t)* - - fn rt() -> Arc { - tokio::runtime::Builder::new_single_thread() - .enable_all() - .build() - .unwrap() - .into() - } - } - mod threaded_scheduler_4_threads { $($t)* diff --git a/tokio/tests/rt_threaded.rs b/tokio/tests/rt_threaded.rs index f1504c3db04..90ebf6a63c9 100644 --- a/tokio/tests/rt_threaded.rs +++ b/tokio/tests/rt_threaded.rs @@ -383,5 +383,5 @@ fn max_threads() { } fn rt() -> Runtime { - Runtime::new_multi_thread().unwrap() + Runtime::new().unwrap() } diff --git a/tokio/tests/sync_mpsc.rs b/tokio/tests/sync_mpsc.rs index 97776d074b6..adefcb12cb8 100644 --- a/tokio/tests/sync_mpsc.rs +++ b/tokio/tests/sync_mpsc.rs @@ -431,7 +431,7 @@ fn blocking_recv() { assert_eq!(Some(10), rx.blocking_recv()); }); - Runtime::new_multi_thread().unwrap().block_on(async move { + Runtime::new().unwrap().block_on(async move { let _ = tx.send(10).await; }); sync_code.join().unwrap() @@ -452,7 +452,7 @@ fn blocking_send() { tx.blocking_send(10).unwrap(); }); - Runtime::new_multi_thread().unwrap().block_on(async move { + Runtime::new().unwrap().block_on(async move { assert_eq!(Some(10), rx.recv().await); }); sync_code.join().unwrap() diff --git a/tokio/tests/task_blocking.rs b/tokio/tests/task_blocking.rs index 337bb703d1f..97d4c1b1cf3 100644 --- a/tokio/tests/task_blocking.rs +++ b/tokio/tests/task_blocking.rs @@ -79,7 +79,7 @@ async fn no_block_in_basic_scheduler() { #[test] fn yes_block_in_threaded_block_on() { - let rt = runtime::Runtime::new_multi_thread().unwrap(); + let rt = runtime::Runtime::new().unwrap(); rt.block_on(async { task::block_in_place(|| {}); }); @@ -96,7 +96,7 @@ fn no_block_in_basic_block_on() { #[test] fn can_enter_basic_rt_from_within_block_in_place() { - let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); outer.block_on(async { tokio::task::block_in_place(|| { @@ -113,7 +113,7 @@ fn can_enter_basic_rt_from_within_block_in_place() { fn useful_panic_message_when_dropping_rt_in_rt() { use std::panic::{catch_unwind, AssertUnwindSafe}; - let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); let result = catch_unwind(AssertUnwindSafe(|| { outer.block_on(async { @@ -136,7 +136,7 @@ fn useful_panic_message_when_dropping_rt_in_rt() { #[test] fn can_shutdown_with_zero_timeout_in_runtime() { - let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); outer.block_on(async { let rt = tokio::runtime::Builder::new_current_thread() @@ -148,7 +148,7 @@ fn can_shutdown_with_zero_timeout_in_runtime() { #[test] fn can_shutdown_now_in_runtime() { - let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); outer.block_on(async { let rt = tokio::runtime::Builder::new_current_thread() @@ -193,7 +193,7 @@ fn coop_disabled_in_block_in_place_in_block_on() { let (done_tx, done_rx) = std::sync::mpsc::channel(); let done = done_tx.clone(); thread::spawn(move || { - let outer = tokio::runtime::Runtime::new_multi_thread().unwrap(); + let outer = tokio::runtime::Runtime::new().unwrap(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); for i in 0..200 { diff --git a/tokio/tests/task_local_set.rs b/tokio/tests/task_local_set.rs index 28fb2d1190a..cb62228a712 100644 --- a/tokio/tests/task_local_set.rs +++ b/tokio/tests/task_local_set.rs @@ -245,7 +245,7 @@ fn join_local_future_elsewhere() { ON_RT_THREAD.with(|cell| cell.set(true)); - let rt = runtime::Runtime::new_multi_thread().unwrap(); + let rt = runtime::Runtime::new().unwrap(); let local = LocalSet::new(); local.block_on(&rt, async move { let (tx, rx) = oneshot::channel(); diff --git a/tokio/tests/time_rt.rs b/tokio/tests/time_rt.rs index b31f9602fcd..85db78db842 100644 --- a/tokio/tests/time_rt.rs +++ b/tokio/tests/time_rt.rs @@ -9,7 +9,7 @@ use std::sync::mpsc; fn timer_with_threaded_runtime() { use tokio::runtime::Runtime; - let rt = Runtime::new_multi_thread().unwrap(); + let rt = Runtime::new().unwrap(); let (tx, rx) = mpsc::channel(); rt.spawn(async move { From fabd58e6a8aa141ffcb34b17d6917b14bc64134b Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 16:33:16 -0700 Subject: [PATCH 20/39] fix feature combo --- tokio/src/future/block_on.rs | 2 +- tokio/src/runtime/mod.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tokio/src/future/block_on.rs b/tokio/src/future/block_on.rs index d12482bccf4..9fc7abc6c46 100644 --- a/tokio/src/future/block_on.rs +++ b/tokio/src/future/block_on.rs @@ -10,6 +10,6 @@ cfg_rt_core! { cfg_not_rt_core! { pub(crate) fn block_on(f: F) -> F::Output { let mut park = crate::park::thread::CachedParkThread::new(); - park.block_on(f) + park.block_on(f).unwrap() } } diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index fd9951ec617..5118c6e7df9 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -229,7 +229,6 @@ cfg_rt_core! { use crate::task::JoinHandle; use std::future::Future; - use std::io; use std::time::Duration; /// The Tokio runtime. @@ -325,7 +324,7 @@ cfg_rt_core! { /// [basic scheduler]: index.html#basic-scheduler /// [runtime builder]: crate::runtime::Builder #[cfg(feature = "rt-threaded")] - pub fn new() -> io::Result { + pub fn new() -> std::io::Result { Builder::new_multi_thread().enable_all().build() } From 559cf99e6463450cd4a1712081d99ef9f476c20b Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 16:51:08 -0700 Subject: [PATCH 21/39] fix windows --- tokio/src/signal/windows.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tokio/src/signal/windows.rs b/tokio/src/signal/windows.rs index 51a07ba0475..46271722515 100644 --- a/tokio/src/signal/windows.rs +++ b/tokio/src/signal/windows.rs @@ -289,8 +289,7 @@ mod tests { } fn rt() -> Runtime { - crate::runtime::Builder::new() - .core_threads(0) + crate::runtime::Builder::new_current_thread() .build() .unwrap() } From 8b780674c8b02e727f9603cfee2866dfda786cdf Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 22:04:43 -0700 Subject: [PATCH 22/39] fix build --- tokio/src/time/clock.rs | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/tokio/src/time/clock.rs b/tokio/src/time/clock.rs index a562ed33898..c35fc7b3ea1 100644 --- a/tokio/src/time/clock.rs +++ b/tokio/src/time/clock.rs @@ -38,7 +38,18 @@ cfg_not_test_util! { cfg_test_util! { use crate::time::{Duration, Instant}; use std::sync::{Arc, Mutex}; - use crate::runtime::context; + + cfg_rt_core! { + fn clock() -> Option { + crate::runtime::context::clock() + } + } + + cfg_not_rt_core! { + fn clock() -> Option { + None + } + } /// A handle to a source of time. #[derive(Debug, Clone)] @@ -67,7 +78,7 @@ cfg_test_util! { /// Panics if time is already frozen or if called from outside of the Tokio /// runtime. pub fn pause() { - let clock = context::clock().expect("time cannot be frozen from outside the Tokio runtime"); + let clock = clock().expect("time cannot be frozen from outside the Tokio runtime"); clock.pause(); } @@ -81,7 +92,7 @@ cfg_test_util! { /// Panics if time is not frozen or if called from outside of the Tokio /// runtime. pub fn resume() { - let clock = context::clock().expect("time cannot be frozen from outside the Tokio runtime"); + let clock = clock().expect("time cannot be frozen from outside the Tokio runtime"); let mut inner = clock.inner.lock().unwrap(); if inner.unfrozen.is_some() { @@ -101,14 +112,27 @@ cfg_test_util! { /// Panics if time is not frozen or if called from outside of the Tokio /// runtime. pub async fn advance(duration: Duration) { - let clock = context::clock().expect("time cannot be frozen from outside the Tokio runtime"); + use crate::future::poll_fn; + use std::task::Poll; + + let clock = clock().expect("time cannot be frozen from outside the Tokio runtime"); clock.advance(duration); - crate::task::yield_now().await; + + let mut yielded = false; + poll_fn(|cx| { + if yielded { + Poll::Ready(()) + } else { + yielded = true; + cx.waker().wake_by_ref(); + Poll::Pending + } + }).await; } /// Return the current instant, factoring in frozen time. pub(crate) fn now() -> Instant { - if let Some(clock) = context::clock() { + if let Some(clock) = clock() { clock.now() } else { Instant::from_std(std::time::Instant::now()) From b982350bd78567729b967d78f741fc4cebf33f5c Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 22:11:33 -0700 Subject: [PATCH 23/39] fix docs --- tokio-macros/src/lib.rs | 2 +- tokio/src/runtime/mod.rs | 37 +++++++++++++++++-------------------- tokio/src/task/local.rs | 4 ++-- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 05e1471ba82..77eaaf78a41 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -167,7 +167,7 @@ pub fn main_threaded(args: TokenStream, item: TokenStream) -> TokenStream { /// /// ```rust /// fn main() { -/// tokio::runtime::Runtime::new_multi_thread() +/// tokio::runtime::Runtime::new() /// .unwrap() /// .block_on(async { /// println!("Hello world"); diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 5118c6e7df9..7fe76364702 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -69,7 +69,7 @@ //! //! fn main() -> Result<(), Box> { //! // Create the runtime -//! let rt = Runtime::new_multi_thread()?; +//! let rt = Runtime::new()?; //! //! // Spawn the root task //! rt.block_on(async { @@ -144,7 +144,7 @@ //! use tokio::runtime; //! //! # fn main() -> Result<(), Box> { -//! let threaded_rt = runtime::Runtime::new_multi_thread()?; +//! let threaded_rt = runtime::Runtime::new()?; //! # Ok(()) } //! ``` //! @@ -233,19 +233,19 @@ cfg_rt_core! { /// The Tokio runtime. /// - /// The runtime provides an I/O driver, task scheduler, [timer], and blocking - /// pool, necessary for running asynchronous tasks. + /// The runtime provides an I/O driver, task scheduler, [timer], and + /// blocking pool, necessary for running asynchronous tasks. /// - /// Instances of `Runtime` can be created using [`new_multi_thread`], [`new_current_thread`], - /// [`new_single_thread`], or [`Builder`]. However, most users will use the `#[tokio::main]` - /// annotation on their entry point instead. + /// Instances of `Runtime` can be created using [`new`], or [`Builder`]. + /// However, most users will use the `#[tokio::main]` annotation on their + /// entry point instead. /// /// See [module level][mod] documentation for more details. /// /// # Shutdown /// - /// Shutting down the runtime is done by dropping the value. The current thread - /// will block until the shut down operation has completed. + /// Shutting down the runtime is done by dropping the value. The current + /// thread will block until the shut down operation has completed. /// /// * Drain any scheduled work queues. /// * Drop any futures that have not yet completed. @@ -255,11 +255,8 @@ cfg_rt_core! { /// that reactor will no longer function. Calling any method on them will /// result in an error. /// - /// [timer]: crate::time - /// [mod]: index.html - /// [`new`]: method@Self::new - /// [`Builder`]: struct@Builder - /// [`tokio::run`]: fn@run + /// [timer]: crate::time [mod]: index.html [`new`]: method@Self::new + /// [`Builder`]: struct@Builder [`tokio::run`]: fn@run #[derive(Debug)] pub struct Runtime { /// Task executor @@ -345,7 +342,7 @@ cfg_rt_core! { /// /// # fn dox() { /// // Create the runtime - /// let rt = Runtime::new_multi_thread().unwrap(); + /// let rt = Runtime::new().unwrap(); /// /// // Spawn a future onto the runtime /// rt.spawn(async { @@ -397,7 +394,7 @@ cfg_rt_core! { /// use tokio::runtime::Runtime; /// /// // Create the runtime - /// let rt = Runtime::new_multi_thread().unwrap(); + /// let rt = Runtime::new().unwrap(); /// /// // Execute the future, blocking the current thread until completion /// rt.block_on(async { @@ -436,7 +433,7 @@ cfg_rt_core! { /// } /// /// fn main() { - /// let rt = Runtime::new_multi_thread().unwrap(); + /// let rt = Runtime::new().unwrap(); /// /// let s = "Hello World!".to_string(); /// @@ -475,7 +472,7 @@ cfg_rt_core! { /// use std::time::Duration; /// /// fn main() { - /// let runtime = Runtime::new_multi_thread().unwrap(); + /// let runtime = Runtime::new().unwrap(); /// /// runtime.block_on(async move { /// task::spawn_blocking(move || { @@ -509,10 +506,10 @@ cfg_rt_core! { /// use tokio::runtime::Runtime; /// /// fn main() { - /// let runtime = Runtime::new_multi_thread().unwrap(); + /// let runtime = Runtime::new().unwrap(); /// /// runtime.block_on(async move { - /// let inner_runtime = Runtime::new_multi_thread().unwrap(); + /// let inner_runtime = Runtime::new().unwrap(); /// // ... /// inner_runtime.shutdown_background(); /// }); diff --git a/tokio/src/task/local.rs b/tokio/src/task/local.rs index 920c56b6e21..e19cbe63572 100644 --- a/tokio/src/task/local.rs +++ b/tokio/src/task/local.rs @@ -312,7 +312,7 @@ impl LocalSet { /// use tokio::runtime::Runtime; /// use tokio::task; /// - /// let rt = Runtime::new_multi_thread().unwrap(); + /// let rt = Runtime::new().unwrap(); /// let local = task::LocalSet::new(); /// local.block_on(&rt, async { /// let join = task::spawn_local(async { @@ -329,7 +329,7 @@ impl LocalSet { /// use tokio::runtime::Runtime; /// use tokio::task; /// - /// let rt = Runtime::new_multi_thread().unwrap(); + /// let rt = Runtime::new().unwrap(); /// let local = task::LocalSet::new(); /// local.block_on(&rt, async { /// let join = task::spawn_local(async { From 112cf71d147f6550f5411479431546ac114cb3e6 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 22:15:16 -0700 Subject: [PATCH 24/39] fix docs hopefully --- tokio/src/runtime/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 7fe76364702..83ae099782a 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -115,8 +115,7 @@ //! //! The basic scheduler provides a _single-threaded_ future executor. All tasks //! will be created and executed on the current thread. The basic scheduler -//! requires the `rt-core` feature flag, and can be selected by setting -//! [`Builder::core_threads`] to `0` or `1`. +//! requires the `rt-core` feature flag. //! ``` //! use tokio::runtime; //! @@ -255,8 +254,10 @@ cfg_rt_core! { /// that reactor will no longer function. Calling any method on them will /// result in an error. /// - /// [timer]: crate::time [mod]: index.html [`new`]: method@Self::new - /// [`Builder`]: struct@Builder [`tokio::run`]: fn@run + /// [timer]: crate::time + /// [mod]: index.html + /// [`new`]: method@Self::new + /// [`Builder`]: struct@Builder #[derive(Debug)] pub struct Runtime { /// Task executor From f9a22e62dd2e838f5dc9c5f5df4f7f83936be569 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 9 Oct 2020 22:21:09 -0700 Subject: [PATCH 25/39] fix loom build --- tokio/src/future/mod.rs | 6 ++++-- tokio/src/runtime/tests/loom_blocking.rs | 4 ++-- tokio/src/runtime/tests/loom_pool.rs | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tokio/src/future/mod.rs b/tokio/src/future/mod.rs index 02e66338985..9ad9bfe1bba 100644 --- a/tokio/src/future/mod.rs +++ b/tokio/src/future/mod.rs @@ -9,8 +9,10 @@ pub(crate) mod maybe_done; mod poll_fn; pub use poll_fn::poll_fn; -mod ready; -pub(crate) use ready::{ok, Ready}; +cfg_not_loom! { + mod ready; + pub(crate) use ready::{ok, Ready}; +} cfg_process! { mod try_join; diff --git a/tokio/src/runtime/tests/loom_blocking.rs b/tokio/src/runtime/tests/loom_blocking.rs index b8c3a10813f..8f0b901493b 100644 --- a/tokio/src/runtime/tests/loom_blocking.rs +++ b/tokio/src/runtime/tests/loom_blocking.rs @@ -23,8 +23,8 @@ fn blocking_shutdown() { } fn mk_runtime(num_threads: usize) -> Runtime { - runtime::Builder::new() - .core_threads(num_threads) + runtime::Builder::new_multi_thread() + .worker_threads(num_threads) .build() .unwrap() } diff --git a/tokio/src/runtime/tests/loom_pool.rs b/tokio/src/runtime/tests/loom_pool.rs index 55b61cd8ed8..06ad6412fd0 100644 --- a/tokio/src/runtime/tests/loom_pool.rs +++ b/tokio/src/runtime/tests/loom_pool.rs @@ -296,8 +296,8 @@ mod group_d { } fn mk_pool(num_threads: usize) -> Runtime { - runtime::Builder::new() - .core_threads(num_threads) + runtime::Builder::new_multi_thread() + .worker_threads(num_threads) .build() .unwrap() } From 3270ce5f184d972eff6ebb673c1d6b44dfed2509 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sat, 10 Oct 2020 08:35:59 -0700 Subject: [PATCH 26/39] fix tokio-util --- tokio-util/src/context.rs | 4 ++-- tokio-util/tests/context.rs | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tokio-util/src/context.rs b/tokio-util/src/context.rs index 14337733ffd..ae954d85c4a 100644 --- a/tokio-util/src/context.rs +++ b/tokio-util/src/context.rs @@ -48,12 +48,12 @@ pub trait RuntimeExt { /// use tokio_util::context::RuntimeExt; /// use tokio::time::{sleep, Duration}; /// - /// let rt = tokio::runtime::Builder::new() + /// let rt = tokio::runtime::Builder::new_multi_thread() /// .enable_all() /// .build() /// .unwrap(); /// - /// let rt2 = tokio::runtime::Builder::new() + /// let rt2 = tokio::runtime::Builder::new_multi_thread() /// .build() /// .unwrap(); /// diff --git a/tokio-util/tests/context.rs b/tokio-util/tests/context.rs index 729076edd94..852dcd0b939 100644 --- a/tokio-util/tests/context.rs +++ b/tokio-util/tests/context.rs @@ -7,11 +7,16 @@ use tokio_util::context::RuntimeExt; #[test] fn tokio_context_with_another_runtime() { - let rt1 = Builder::new_single_thread() + let rt1 = Builder::new_multi_thread() + .worker_threads(1) // no timer! .build() .unwrap(); - let rt2 = Builder::new_single_thread().enable_all().build().unwrap(); + let rt2 = Builder::new_multi_thread() + .worker_threads(1) + .enable_all() + .build() + .unwrap(); // Without the `HandleExt.wrap()` there would be a panic because there is // no timer running, since it would be referencing runtime r1. From 61421e7900ffd504ff36da20a21659b46b807cfe Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 20:37:37 -0700 Subject: [PATCH 27/39] fix macro doc examples --- tokio-macros/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 46def4ee628..f540a82bff7 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -70,7 +70,7 @@ use proc_macro::TokenStream; /// /// ```rust /// fn main() { -/// tokio::runtime::Builder::new() +/// tokio::runtime::Builder::new_multi_thread() /// .enable_all() /// .build() /// .unwrap() @@ -95,8 +95,7 @@ use proc_macro::TokenStream; /// /// ```rust /// fn main() { -/// tokio::runtime::Builder::new() -/// .core_threads(0) +/// tokio::runtime::Builder::new_current_thread() /// .enable_all() /// .build() /// .unwrap() @@ -119,8 +118,8 @@ use proc_macro::TokenStream; /// /// ```rust /// fn main() { -/// tokio::runtime::Builder::new() -/// .core_threads(2) +/// tokio::runtime::Builder::new_multi_thread() +/// .worker_threads(2) /// .enable_all() /// .build() /// .unwrap() @@ -156,7 +155,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { /// ### Using default /// /// ```rust -/// #[tokio::main] +/// #[tokio::main(flavor = "current_thread")] /// async fn main() { /// println!("Hello world"); /// } @@ -166,8 +165,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { /// /// ```rust /// fn main() { -/// tokio::runtime::Builder::new() -/// .core_threads(0) +/// tokio::runtime::Builder::new_current_thread() /// .enable_all() /// .build() /// .unwrap() From 130beedd78bc71614cd5b2fc36164826f857c37e Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 20:54:50 -0700 Subject: [PATCH 28/39] fix bad type --- tokio/src/blocking.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tokio/src/blocking.rs b/tokio/src/blocking.rs index 64cdf2c76c3..d6ef591592f 100644 --- a/tokio/src/blocking.rs +++ b/tokio/src/blocking.rs @@ -14,6 +14,7 @@ cfg_not_rt_core! { F: FnOnce() -> R + Send + 'static, R: Send + 'static, { + assert_send_sync::>>(); panic!("requires the `rt-core` Tokio feature flag") } @@ -22,6 +23,9 @@ cfg_not_rt_core! { _p: std::marker::PhantomData, } + unsafe impl Send for JoinHandle {} + unsafe impl Sync for JoinHandle {} + impl Future for JoinHandle { type Output = Result; @@ -38,4 +42,7 @@ cfg_not_rt_core! { fmt.debug_struct("JoinHandle").finish() } } + + fn assert_send_sync() { + } } From 2c9acd1ae2f876d1b0111a9366b80038c4bdfa45 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 21:07:05 -0700 Subject: [PATCH 29/39] Update tokio/src/io/driver/mod.rs Co-authored-by: Alice Ryhl --- tokio/src/io/driver/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio/src/io/driver/mod.rs b/tokio/src/io/driver/mod.rs index f51d206b126..0d4133a5f89 100644 --- a/tokio/src/io/driver/mod.rs +++ b/tokio/src/io/driver/mod.rs @@ -240,8 +240,8 @@ cfg_not_rt_core! { /// /// # Panics /// - /// This function panics if there is no current reactor set and `rt-core` feature - /// flag is not enabled. + /// This function panics if there is no current reactor set, or if the `rt-core` + /// 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-core` enabled.") } From bc77b12d0b6593eb4f3ee4723881e01f74b13155 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 21:39:21 -0700 Subject: [PATCH 30/39] tests + rename num_workers --- tests-build/Cargo.toml | 1 + .../tests/fail/macros_core_no_default.rs | 6 ++ .../tests/fail/macros_core_no_default.stderr | 7 +++ .../tests/fail/macros_invalid_input.stderr | 4 +- tests-build/tests/macros.rs | 5 +- tokio-macros/src/entry.rs | 55 ++++++++++-------- tokio-macros/src/lib.rs | 45 ++++++++------- tokio/src/future/mod.rs | 1 - tokio/src/runtime/mod.rs | 56 +++++++------------ 9 files changed, 96 insertions(+), 84 deletions(-) create mode 100644 tests-build/tests/fail/macros_core_no_default.rs create mode 100644 tests-build/tests/fail/macros_core_no_default.stderr diff --git a/tests-build/Cargo.toml b/tests-build/Cargo.toml index 68231d714e0..e76621b496d 100644 --- a/tests-build/Cargo.toml +++ b/tests-build/Cargo.toml @@ -7,6 +7,7 @@ publish = false [features] full = ["tokio/full"] +rt-core = ["tokio/rt-core", "tokio/macros"] [dependencies] tokio = { path = "../tokio", optional = true } diff --git a/tests-build/tests/fail/macros_core_no_default.rs b/tests-build/tests/fail/macros_core_no_default.rs new file mode 100644 index 00000000000..23f8847df7d --- /dev/null +++ b/tests-build/tests/fail/macros_core_no_default.rs @@ -0,0 +1,6 @@ +use tests_build::tokio; + +#[tokio::main] +async fn my_fn() {} + +fn main() {} diff --git a/tests-build/tests/fail/macros_core_no_default.stderr b/tests-build/tests/fail/macros_core_no_default.stderr new file mode 100644 index 00000000000..afa0e330fee --- /dev/null +++ b/tests-build/tests/fail/macros_core_no_default.stderr @@ -0,0 +1,7 @@ +error: The default runtime flavor is `threaded`, but the `rt-threaded` feature is disabled. + --> $DIR/macros_core_no_default.rs:3:1 + | +3 | #[tokio::main] + | ^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests-build/tests/fail/macros_invalid_input.stderr b/tests-build/tests/fail/macros_invalid_input.stderr index 1b343c778b9..4c68bd93f6c 100644 --- a/tests-build/tests/fail/macros_invalid_input.stderr +++ b/tests-build/tests/fail/macros_invalid_input.stderr @@ -4,7 +4,7 @@ error: the async keyword is missing from the function declaration 4 | fn main_is_not_async() {} | ^^ -error: Unknown attribute foo is specified; expected one of: `flavor`, `num_workers` +error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads` --> $DIR/macros_invalid_input.rs:6:15 | 6 | #[tokio::main(foo)] @@ -28,7 +28,7 @@ error: the test function cannot accept arguments 16 | async fn test_fn_has_args(_x: u8) {} | ^^^^^^ -error: Unknown attribute foo is specified; expected one of: `flavor`, `num_workers` +error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads` --> $DIR/macros_invalid_input.rs:18:15 | 18 | #[tokio::test(foo)] diff --git a/tests-build/tests/macros.rs b/tests-build/tests/macros.rs index 170db227735..d59b67485f4 100644 --- a/tests-build/tests/macros.rs +++ b/tests-build/tests/macros.rs @@ -1,9 +1,12 @@ #[test] -fn compile_fail() { +fn compile_fail_full() { let t = trybuild::TestCases::new(); #[cfg(feature = "full")] t.compile_fail("tests/fail/macros_invalid_input.rs"); + #[cfg(feature = "rt-core")] + t.compile_fail("tests/fail/macros_core_no_default.rs"); + drop(t); } diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 97eb7348682..6b94a617b51 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -24,14 +24,14 @@ impl RuntimeFlavor { struct FinalConfig { flavor: RuntimeFlavor, - num_workers: Option, + worker_threads: Option, } struct Configuration { rt_threaded_available: bool, default_flavor: RuntimeFlavor, flavor: Option, - num_workers: Option<(usize, Span)>, + worker_threads: Option<(usize, Span)>, } impl Configuration { @@ -43,7 +43,7 @@ impl Configuration { false => RuntimeFlavor::Threaded, }, flavor: None, - num_workers: None, + worker_threads: None, } } @@ -59,34 +59,41 @@ impl Configuration { Ok(()) } - fn set_num_workers(&mut self, num_workers: syn::Lit, span: Span) -> Result<(), syn::Error> { - if self.num_workers.is_some() { - return Err(syn::Error::new(span, "`num_workers` set multiple times.")); + fn set_worker_threads( + &mut self, + worker_threads: syn::Lit, + span: Span, + ) -> Result<(), syn::Error> { + if self.worker_threads.is_some() { + return Err(syn::Error::new( + span, + "`worker_threads` set multiple times.", + )); } - let num_workers = parse_int(num_workers, span, "num_workers")?; - if num_workers == 0 { - return Err(syn::Error::new(span, "`num_workers` may not be 0.")); + let worker_threads = parse_int(worker_threads, span, "worker_threads")?; + if worker_threads == 0 { + return Err(syn::Error::new(span, "`worker_threads` may not be 0.")); } - self.num_workers = Some((num_workers, span)); + self.worker_threads = Some((worker_threads, span)); Ok(()) } fn build(&self) -> Result { let flavor = self.flavor.unwrap_or(self.default_flavor); use RuntimeFlavor::*; - match (flavor, self.num_workers) { - (CurrentThread, Some((_, num_workers_span))) => Err(syn::Error::new( - num_workers_span, - "The `num_workers` option requires the `threaded` runtime flavor.", + match (flavor, self.worker_threads) { + (CurrentThread, Some((_, worker_threads_span))) => Err(syn::Error::new( + worker_threads_span, + "The `worker_threads` option requires the `threaded` runtime flavor.", )), (CurrentThread, None) => Ok(FinalConfig { flavor, - num_workers: None, + worker_threads: None, }), - (Threaded, num_workers) if self.rt_threaded_available => Ok(FinalConfig { + (Threaded, worker_threads) if self.rt_threaded_available => Ok(FinalConfig { flavor, - num_workers: num_workers.map(|(val, _span)| val), + worker_threads: worker_threads.map(|(val, _span)| val), }), (Threaded, _) => { let msg = if self.flavor.is_none() { @@ -161,18 +168,18 @@ fn parse_knobs( return Err(syn::Error::new_spanned(namevalue, msg)); } match ident.unwrap().to_string().to_lowercase().as_str() { - "num_workers" => { - config.set_num_workers(namevalue.lit.clone(), namevalue.span())?; + "worker_threads" => { + config.set_worker_threads(namevalue.lit.clone(), namevalue.span())?; } "flavor" => { config.set_flavor(namevalue.lit.clone(), namevalue.span())?; } "core_threads" => { - let msg = "Attribute `core_threads` is renamed to `num_workers`"; + let msg = "Attribute `core_threads` is renamed to `worker_threads`"; return Err(syn::Error::new_spanned(namevalue, msg)); } name => { - let msg = format!("Unknown attribute {} is specified; expected one of: `flavor`, `num_workers`, `max_threads`", name); + let msg = format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `max_threads`", name); return Err(syn::Error::new_spanned(namevalue, msg)); } } @@ -191,11 +198,11 @@ fn parse_knobs( "basic_scheduler" | "current_thread" | "single_threaded" => { format!("Set the runtime flavor with #[{}(flavor = \"current_thread\")].", macro_name) }, - "flavor" | "num_workers" => { + "flavor" | "worker_threads" => { format!("The `{}` attribute requires an argument.", name) }, name => { - format!("Unknown attribute {} is specified; expected one of: `flavor`, `num_workers`", name) + format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`", name) }, }; return Err(syn::Error::new_spanned(path, msg)); @@ -219,7 +226,7 @@ fn parse_knobs( tokio::runtime::Builder::new_multi_thread() }, }; - if let Some(v) = config.num_workers { + if let Some(v) = config.worker_threads { rt = quote! { #rt.worker_threads(#v) }; } diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index f540a82bff7..867abd6879f 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -24,28 +24,34 @@ mod select; use proc_macro::TokenStream; -/// Marks async function to be executed by selected runtime. This macro helps set up a `Runtime` -/// without requiring the user to use [Runtime](../tokio/runtime/struct.Runtime.html) or +/// Marks async function to be executed by selected runtime. This macro helps +/// set up a `Runtime` without requiring the user to use +/// [Runtime](../tokio/runtime/struct.Runtime.html) or /// [Builder](../tokio/runtime/struct.Builder.html) directly. /// -/// Note: This macro is designed to be simplistic and targets applications that do not require -/// a complex setup. If the provided functionality is not sufficient, you may be interested in -/// using [Builder](../tokio/runtime/struct.Builder.html), which provides a more powerful -/// interface. +/// Note: This macro is designed to be simplistic and targets applications that +/// do not require a complex setup. If the provided functionality is not +/// sufficient, you may be interested in using +/// [Builder](../tokio/runtime/struct.Builder.html), which provides a more +/// powerful interface. /// /// # Multi-threaded runtime +/// /// To use the multi-threaded runtime, the macro can be configured using +/// /// ``` -/// #[tokio::main(flavor = "threaded", num_workers = 10)] +/// #[tokio::main(flavor = "multi_thread", worker_threads = 10)] /// # async fn main() {} /// ``` -/// The `num_workers` option configures the number of worker threads, and defaults to the number of -/// cpus on the system. This is the default flavor. +/// +/// The `worker_threads` option configures the number of worker threads, and +/// defaults to the number of cpus on the system. This is the default flavor. /// /// # Current thread runtime /// -/// To use the single-threaded runtime known as the `current_thread` runtime, the macro can be -/// configured using +/// To use the single-threaded runtime known as the `current_thread` runtime, +/// the macro can be configured using +/// /// ``` /// #[tokio::main(flavor = "current_thread")] /// # async fn main() {} @@ -57,7 +63,7 @@ use proc_macro::TokenStream; /// /// ## Usage /// -/// ### Using threaded runtime +/// ### Using the multi-thread runtime /// /// ```rust /// #[tokio::main] @@ -131,11 +137,10 @@ use proc_macro::TokenStream; /// /// ### NOTE: /// -/// If you rename the tokio crate in your dependencies this macro -/// will not work. If you must rename the 0.2 version of tokio because -/// you're also using the 0.1 version of tokio, you _must_ make the -/// tokio 0.2 crate available as `tokio` in the module where this -/// macro is expanded. +/// If you rename the tokio crate in your dependencies this macro will not work. +/// If you must rename the 0.2 version of tokio because you're also using the +/// 0.1 version of tokio, you _must_ make the tokio 0.2 crate available as +/// `tokio` in the module where this macro is expanded. #[proc_macro_attribute] #[cfg(not(test))] // Work around for rust-lang/rust#62127 pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { @@ -192,10 +197,10 @@ pub fn main_rt_core(args: TokenStream, item: TokenStream) -> TokenStream { /// /// ## Usage /// -/// ### Threaded runtime +/// ### Multi-thread runtime /// /// ```no_run -/// #[tokio::test(flavor = "threaded", num_workers = 1)] +/// #[tokio::test(flavor = "multi_thread", worker_threads = 1)] /// async fn my_test() { /// assert!(true); /// } @@ -203,7 +208,7 @@ pub fn main_rt_core(args: TokenStream, item: TokenStream) -> TokenStream { /// /// ### Using default /// -/// The default test runtime is single-threaded. +/// The default test runtime is multi-threaded. /// /// ```no_run /// #[tokio::test] diff --git a/tokio/src/future/mod.rs b/tokio/src/future/mod.rs index 9ad9bfe1bba..f7d93c9868c 100644 --- a/tokio/src/future/mod.rs +++ b/tokio/src/future/mod.rs @@ -1,4 +1,3 @@ -// #![allow(unused_imports, dead_code)] #![cfg_attr(not(feature = "macros"), allow(unreachable_pub))] //! Asynchronous values. diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 83ae099782a..aa4ecc5c2e2 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -1,8 +1,7 @@ //! The Tokio runtime. //! -//! Unlike other Rust programs, asynchronous applications require -//! runtime support. In particular, the following runtime services are -//! necessary: +//! Unlike other Rust programs, asynchronous applications require runtime +//! support. In particular, the following runtime services are necessary: //! //! * An **I/O event loop**, called the driver, which drives I/O resources and //! dispatches I/O events to tasks that depend on them. @@ -10,14 +9,14 @@ //! * A **timer** for scheduling work to run after a set period of time. //! //! Tokio's [`Runtime`] bundles all of these services as a single type, allowing -//! them to be started, shut down, and configured together. However, often -//! it is not required to configure a [`Runtime`] manually, and user may just -//! use the [`tokio::main`] attribute macro, which creates a [`Runtime`] under -//! the hood. +//! them to be started, shut down, and configured together. However, often it is +//! not required to configure a [`Runtime`] manually, and user may just use the +//! [`tokio::main`] attribute macro, which creates a [`Runtime`] under the hood. //! //! # Usage //! -//! When no fine tuning is required, the [`tokio::main`] attribute macro can be used. +//! When no fine tuning is required, the [`tokio::main`] attribute macro can be +//! used. //! //! ```no_run //! use tokio::net::TcpListener; @@ -111,11 +110,11 @@ //! applications. The [runtime builder] or `#[tokio::main]` attribute may be //! used to select which scheduler to use. //! -//! #### Basic Scheduler +//! #### Current-Thread Scheduler //! -//! The basic scheduler provides a _single-threaded_ future executor. All tasks -//! will be created and executed on the current thread. The basic scheduler -//! requires the `rt-core` feature flag. +//! The current-thread scheduler provides a _single-threaded_ future executor. +//! All tasks will be created and executed on the current thread. This requires +//! the `rt-core` feature flag. //! ``` //! use tokio::runtime; //! @@ -125,20 +124,13 @@ //! # Ok(()) } //! ``` //! -//! Setting `core_threads(0)` will allow you to run the scheduler on the current -//! thread. When setting `core_threads(1)`, the runtime will spawn one background -//! thread that will run the runtime. +//! #### Multi-Thread Scheduler //! -//! If the `rt-core` feature is enabled and `rt-threaded` is not, -//! [`Runtime::new`] will return a basic scheduler runtime by default. -//! -//! #### Threaded Scheduler -//! -//! The threaded scheduler executes futures on a _thread pool_, using a +//! The multi-thread scheduler executes futures on a _thread pool_, using a //! work-stealing strategy. By default, it will start a worker thread for each //! CPU core available on the system. This tends to be the ideal configurations -//! for most applications. The threaded scheduler requires the `rt-threaded` feature -//! flag, and is selected by default: +//! for most applications. The multi-thread scheduler requires the `rt-threaded` +//! feature flag, and is selected by default: //! ``` //! use tokio::runtime; //! @@ -147,8 +139,8 @@ //! # Ok(()) } //! ``` //! -//! Most applications should use the threaded scheduler, except in some niche -//! use-cases, such as when running only a single thread is required. +//! Most applications should use the multi-thread scheduler, except in some +//! niche use-cases, such as when running only a single thread is required. //! //! #### Resource drivers //! @@ -168,12 +160,9 @@ //! idle. Once `Runtime` is dropped, all runtime threads are forcibly shutdown. //! Any tasks that have not yet completed will be dropped. //! -//! [tasks]: crate::task -//! [`Runtime`]: Runtime -//! [`tokio::spawn`]: crate::spawn -//! [`tokio::main`]: ../attr.main.html -//! [runtime builder]: crate::runtime::Builder -//! [`Runtime::new`]: crate::runtime::Runtime::new +//! [tasks]: crate::task [`Runtime`]: Runtime [`tokio::spawn`]: crate::spawn +//! [`tokio::main`]: ../attr.main.html [runtime builder]: +//! crate::runtime::Builder [`Runtime::new`]: crate::runtime::Runtime::new //! [`Builder::basic_scheduler`]: crate::runtime::Builder::basic_scheduler //! [`Builder::threaded_scheduler`]: crate::runtime::Builder::threaded_scheduler //! [`Builder::enable_io`]: crate::runtime::Builder::enable_io @@ -351,11 +340,6 @@ cfg_rt_core! { /// }); /// # } /// ``` - /// - /// # Panics - /// - /// This function will panic if `rt-core` or `rt-threaded` features - /// are not enabled. #[cfg(feature = "rt-core")] pub fn spawn(&self, future: F) -> JoinHandle where From 90034090470a50eac7e2bdcb53ea0798653d092b Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 21:42:41 -0700 Subject: [PATCH 31/39] tweak ff --- tokio/src/sync/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/src/sync/mod.rs b/tokio/src/sync/mod.rs index f2d8dba2acd..ddb289eb7ea 100644 --- a/tokio/src/sync/mod.rs +++ b/tokio/src/sync/mod.rs @@ -464,7 +464,7 @@ cfg_not_sync! { pub(crate) use mutex::Mutex; } - #[cfg(any(feature = "process", feature = "rt-core", feature = "signal"))] + #[cfg(any(feature = "rt-core", feature = "signal", all(unix, feature = "process")))] pub(crate) mod notify; cfg_atomic_waker_impl! { From f8bb6a0128a63a8810cdbfbc3ed2c1855a4d89b7 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 21:50:45 -0700 Subject: [PATCH 32/39] fix a test --- tokio/tests/sync_rwlock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/tests/sync_rwlock.rs b/tokio/tests/sync_rwlock.rs index 9fbf3d6fe0b..18427883e83 100644 --- a/tokio/tests/sync_rwlock.rs +++ b/tokio/tests/sync_rwlock.rs @@ -166,7 +166,7 @@ async fn write_order() { } // A single RwLock is contested by tasks in multiple threads -#[tokio::test(flavor = "threaded", num_workers = 8)] +#[tokio::test(flavor = "threaded", worker_threads = 8)] async fn multithreaded() { let barrier = Arc::new(Barrier::new(5)); let rwlock = Arc::new(RwLock::::new(0)); From f10eedf9f88f0b4b85f069ed5097e56644e385a3 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 21:55:29 -0700 Subject: [PATCH 33/39] fix doc links --- tokio/src/runtime/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index aa4ecc5c2e2..c79a942f647 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -160,9 +160,12 @@ //! idle. Once `Runtime` is dropped, all runtime threads are forcibly shutdown. //! Any tasks that have not yet completed will be dropped. //! -//! [tasks]: crate::task [`Runtime`]: Runtime [`tokio::spawn`]: crate::spawn -//! [`tokio::main`]: ../attr.main.html [runtime builder]: -//! crate::runtime::Builder [`Runtime::new`]: crate::runtime::Runtime::new +//! [tasks]: crate::task +//! [`Runtime`]: Runtime +//! [`tokio::spawn`]: crate::spawn +//! [`tokio::main`]: ../attr.main.html +//! [runtime builder]: crate::runtime::Builder +//! [`Runtime::new`]: crate::runtime::Runtime::new //! [`Builder::basic_scheduler`]: crate::runtime::Builder::basic_scheduler //! [`Builder::threaded_scheduler`]: crate::runtime::Builder::threaded_scheduler //! [`Builder::enable_io`]: crate::runtime::Builder::enable_io From 5c5f2052d6cd37045831d555df77b79137f59348 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 22:09:30 -0700 Subject: [PATCH 34/39] try to fix CI --- tests-build/tests/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-build/tests/macros.rs b/tests-build/tests/macros.rs index d59b67485f4..a12a20ef41d 100644 --- a/tests-build/tests/macros.rs +++ b/tests-build/tests/macros.rs @@ -5,7 +5,7 @@ fn compile_fail_full() { #[cfg(feature = "full")] t.compile_fail("tests/fail/macros_invalid_input.rs"); - #[cfg(feature = "rt-core")] + #[cfg(all(feature = "rt-core", not(feature = "full")))] t.compile_fail("tests/fail/macros_core_no_default.rs"); drop(t); From fb155ddd264d09f1486452876ba4d633090318d2 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 22:17:10 -0700 Subject: [PATCH 35/39] tweak multi-threaded flavor --- tokio-macros/src/entry.rs | 16 ++++++++-------- tokio/tests/sync_rwlock.rs | 2 +- tokio/tests/task_blocking.rs | 4 ++-- tokio/tests/task_local.rs | 2 +- tokio/tests/task_local_set.rs | 14 +++++++------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 6b94a617b51..694815b09bf 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -13,11 +13,11 @@ impl RuntimeFlavor { fn from_str(s: &str) -> Result { match s { "current_thread" => Ok(RuntimeFlavor::CurrentThread), - "threaded" => Ok(RuntimeFlavor::Threaded), + "multi_thread" => Ok(RuntimeFlavor::Threaded), "single_threaded" => Err("The single threaded runtime flavor is called `current_thread`.".to_string()), "basic_scheduler" => Err("The `basic_scheduler` runtime flavor has been renamed to `current_thread`.".to_string()), - "threaded_scheduler" => Err("The `threaded_scheduler` runtime flavor has been renamed to `threaded`.".to_string()), - _ => Err(format!("No such runtime flavor `{}`. The runtime flavors are `current_thread` and `threaded`.", s)), + "threaded_scheduler" => Err("The `threaded_scheduler` runtime flavor has been renamed to `multi_thread`.".to_string()), + _ => Err(format!("No such runtime flavor `{}`. The runtime flavors are `current_thread` and `multi_thread`.", s)), } } } @@ -85,7 +85,7 @@ impl Configuration { match (flavor, self.worker_threads) { (CurrentThread, Some((_, worker_threads_span))) => Err(syn::Error::new( worker_threads_span, - "The `worker_threads` option requires the `threaded` runtime flavor.", + "The `worker_threads` option requires the `multi_thread` runtime flavor.", )), (CurrentThread, None) => Ok(FinalConfig { flavor, @@ -97,9 +97,9 @@ impl Configuration { }), (Threaded, _) => { let msg = if self.flavor.is_none() { - "The default runtime flavor is `threaded`, but the `rt-threaded` feature is disabled." + "The default runtime flavor is `multi_thread`, but the `rt-threaded` feature is disabled." } else { - "The runtime flavor `threaded` requires the `rt-threaded` feature." + "The runtime flavor `multi_thread` requires the `rt-threaded` feature." }; Err(syn::Error::new(Span::call_site(), msg)) } @@ -192,8 +192,8 @@ fn parse_knobs( } let name = ident.unwrap().to_string().to_lowercase(); let msg = match name.as_str() { - "threaded_scheduler" | "threaded" => { - format!("Set the runtime flavor with #[{}(flavor = \"threaded\")].", macro_name) + "threaded_scheduler" | "multi_thread" => { + format!("Set the runtime flavor with #[{}(flavor = \"multi_thread\")].", macro_name) }, "basic_scheduler" | "current_thread" | "single_threaded" => { format!("Set the runtime flavor with #[{}(flavor = \"current_thread\")].", macro_name) diff --git a/tokio/tests/sync_rwlock.rs b/tokio/tests/sync_rwlock.rs index 18427883e83..76760351680 100644 --- a/tokio/tests/sync_rwlock.rs +++ b/tokio/tests/sync_rwlock.rs @@ -166,7 +166,7 @@ async fn write_order() { } // A single RwLock is contested by tasks in multiple threads -#[tokio::test(flavor = "threaded", worker_threads = 8)] +#[tokio::test(flavor = "multi_thread", worker_threads = 8)] async fn multithreaded() { let barrier = Arc::new(Barrier::new(5)); let rwlock = Arc::new(RwLock::::new(0)); diff --git a/tokio/tests/task_blocking.rs b/tokio/tests/task_blocking.rs index 40a5d3adc9c..eec19cc16d8 100644 --- a/tokio/tests/task_blocking.rs +++ b/tokio/tests/task_blocking.rs @@ -28,7 +28,7 @@ async fn basic_blocking() { } } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn block_in_blocking() { // Run a few times for _ in 0..100 { @@ -51,7 +51,7 @@ async fn block_in_blocking() { } } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn block_in_block() { // Run a few times for _ in 0..100 { diff --git a/tokio/tests/task_local.rs b/tokio/tests/task_local.rs index 87ced4eae00..9981532428e 100644 --- a/tokio/tests/task_local.rs +++ b/tokio/tests/task_local.rs @@ -3,7 +3,7 @@ tokio::task_local! { pub static FOO: bool; } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn local() { let j1 = tokio::spawn(REQ_ID.scope(1, async move { assert_eq!(REQ_ID.get(), 1); diff --git a/tokio/tests/task_local_set.rs b/tokio/tests/task_local_set.rs index ad0a9021c12..dda42809d68 100644 --- a/tokio/tests/task_local_set.rs +++ b/tokio/tests/task_local_set.rs @@ -20,7 +20,7 @@ async fn local_basic_scheduler() { .await; } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn local_threadpool() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); @@ -40,7 +40,7 @@ async fn local_threadpool() { .await; } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn localset_future_threadpool() { thread_local! { static ON_LOCAL_THREAD: Cell = Cell::new(false); @@ -55,7 +55,7 @@ async fn localset_future_threadpool() { local.await; } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn localset_future_timers() { static RAN1: AtomicBool = AtomicBool::new(false); static RAN2: AtomicBool = AtomicBool::new(false); @@ -99,7 +99,7 @@ async fn localset_future_drives_all_local_futs() { assert!(RAN3.load(Ordering::SeqCst)); } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn local_threadpool_timer() { // This test ensures that runtime services like the timer are properly // set for the local task set. @@ -148,7 +148,7 @@ fn local_threadpool_blocking_in_place() { }); } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn local_threadpool_blocking_run() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); @@ -176,7 +176,7 @@ async fn local_threadpool_blocking_run() { .await; } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn all_spawns_are_local() { use futures::future; thread_local! { @@ -202,7 +202,7 @@ async fn all_spawns_are_local() { .await; } -#[tokio::test(flavor = "threaded")] +#[tokio::test(flavor = "multi_thread")] async fn nested_spawn_is_local() { thread_local! { static ON_RT_THREAD: Cell = Cell::new(false); From 5a94b7e70130c96e31f521fca2b6a2b13393aa21 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 22:22:16 -0700 Subject: [PATCH 36/39] fix doc test --- tokio-macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 867abd6879f..9bc6cc211bb 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -114,7 +114,7 @@ use proc_macro::TokenStream; /// ### Set number of worker threads /// /// ```rust -/// #[tokio::main(num_workers = 2)] +/// #[tokio::main(worker_threads = 2)] /// async fn main() { /// println!("Hello world"); /// } From 22f5237fcc758ab7b9ce6794cb30ac9719b6498f Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 11 Oct 2020 22:36:51 -0700 Subject: [PATCH 37/39] update error message --- tests-build/tests/fail/macros_core_no_default.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-build/tests/fail/macros_core_no_default.stderr b/tests-build/tests/fail/macros_core_no_default.stderr index afa0e330fee..a3ae32cd752 100644 --- a/tests-build/tests/fail/macros_core_no_default.stderr +++ b/tests-build/tests/fail/macros_core_no_default.stderr @@ -1,4 +1,4 @@ -error: The default runtime flavor is `threaded`, but the `rt-threaded` feature is disabled. +error: The default runtime flavor is `multi_thread`, but the `rt-threaded` feature is disabled. --> $DIR/macros_core_no_default.rs:3:1 | 3 | #[tokio::main] From e3f2f86cbcef789eb1d8d0c9a797cc8c201eb113 Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Mon, 12 Oct 2020 12:48:59 -0400 Subject: [PATCH 38/39] Apply suggestions from code review Co-authored-by: Alice Ryhl --- tokio-macros/src/entry.rs | 2 +- tokio-macros/src/lib.rs | 2 +- tokio/src/task/blocking.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 694815b09bf..f3c7c2300c6 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -14,7 +14,7 @@ impl RuntimeFlavor { match s { "current_thread" => Ok(RuntimeFlavor::CurrentThread), "multi_thread" => Ok(RuntimeFlavor::Threaded), - "single_threaded" => Err("The single threaded runtime flavor is called `current_thread`.".to_string()), + "single_thread" => Err("The single threaded runtime flavor is called `current_thread`.".to_string()), "basic_scheduler" => Err("The `basic_scheduler` runtime flavor has been renamed to `current_thread`.".to_string()), "threaded_scheduler" => Err("The `threaded_scheduler` runtime flavor has been renamed to `multi_thread`.".to_string()), _ => Err(format!("No such runtime flavor `{}`. The runtime flavors are `current_thread` and `multi_thread`.", s)), diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 9bc6cc211bb..1d6f577a8f1 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -24,7 +24,7 @@ mod select; use proc_macro::TokenStream; -/// Marks async function to be executed by selected runtime. This macro helps +/// Marks async function to be executed by the selected runtime. This macro helps /// set up a `Runtime` without requiring the user to use /// [Runtime](../tokio/runtime/struct.Runtime.html) or /// [Builder](../tokio/runtime/struct.Builder.html) directly. diff --git a/tokio/src/task/blocking.rs b/tokio/src/task/blocking.rs index 1a79834cddb..5f9d8af7789 100644 --- a/tokio/src/task/blocking.rs +++ b/tokio/src/task/blocking.rs @@ -17,7 +17,7 @@ cfg_rt_threaded! { /// using the [`join!`] macro. To avoid this issue, use [`spawn_blocking`] /// instead. /// - /// Note that this function can only be used when `core_threads > 1`. + /// Note that this function can only be used when using the `multi_thread` runtime. /// /// Code running behind `block_in_place` cannot be cancelled. When you shut /// down the executor, it will wait indefinitely for all blocking operations From 3ad8f3bc279d52e184e31ae0fc22efbe689c2594 Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Mon, 12 Oct 2020 17:06:28 +0000 Subject: [PATCH 39/39] address comments --- tokio/src/coop.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tokio/src/coop.rs b/tokio/src/coop.rs index 0f5a4956a69..f6cca1c505c 100644 --- a/tokio/src/coop.rs +++ b/tokio/src/coop.rs @@ -62,13 +62,6 @@ thread_local! { #[derive(Debug, Copy, Clone)] pub(crate) struct Budget(Option); -impl Budget { - /// Returns an unconstrained budget. Operations will not be limited. - const fn unconstrained() -> Budget { - Budget(None) - } -} - impl Budget { /// Budget assigned to a task on each poll. /// @@ -83,6 +76,11 @@ impl Budget { const fn initial() -> Budget { Budget(Some(128)) } + + /// Returns an unconstrained budget. Operations will not be limited. + const fn unconstrained() -> Budget { + Budget(None) + } } cfg_rt_threaded! {