Skip to content
Snippets Groups Projects
Unverified Commit 894eb8b8 authored by Alice Ryhl's avatar Alice Ryhl Committed by GitHub
Browse files

runtime: improve runtime and handle doc (#2440)

Refs: #2437
parent 3572ba5a
No related branches found
No related tags found
No related merge requests found
......@@ -399,12 +399,13 @@ cfg_rt_core! {
/// 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.
/// 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
......
......@@ -31,7 +31,39 @@ pub struct Handle {
}
impl Handle {
/// Enter the runtime context.
/// Enter the runtime context. This allows you to construct types that must
/// have an executor available on creation such as [`Delay`] or [`TcpStream`].
/// It will also allow you to call methods such as [`tokio::spawn`].
///
/// This function is also available as [`Runtime::enter`].
///
/// [`Delay`]: struct@crate::time::Delay
/// [`TcpStream`]: struct@crate::net::TcpStream
/// [`Runtime::enter`]: fn@crate::runtime::Runtime::enter
/// [`tokio::spawn`]: fn@crate::spawn
///
/// # Example
///
/// ```
/// use tokio::runtime::Runtime;
///
/// fn function_that_spawns(msg: String) {
/// // Had we not used `handle.enter` below, this would panic.
/// tokio::spawn(async move {
/// println!("{}", msg);
/// });
/// }
///
/// fn main() {
/// let rt = Runtime::new().unwrap();
/// let handle = rt.handle().clone();
///
/// let s = "Hello World!".to_string();
///
/// // By entering the context, we tie `tokio::spawn` to this executor.
/// handle.enter(|| function_that_spawns(s));
/// }
/// ```
pub fn enter<F, R>(&self, f: F) -> R
where
F: FnOnce() -> R,
......@@ -110,8 +142,14 @@ cfg_rt_core! {
///
/// # Panics
///
/// This function panics if the spawn fails. Failure occurs if the executor
/// is currently at capacity and is unable to spawn a new future.
/// 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@crate::runtime::Builder
/// [`threaded_scheduler`]: fn@crate::runtime::Builder::threaded_scheduler
/// [`basic_scheduler`]: fn@crate::runtime::Builder::basic_scheduler
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
......@@ -127,26 +165,47 @@ cfg_rt_core! {
/// complete, and yielding its resolved result. Any tasks or timers which
/// the future spawns internally will be executed on the runtime.
///
/// This method should not be called from an asynchronous context.
/// If the provided executor currently has no active core thread, this
/// function might hang until a core thread is added. This is not a
/// concern when using the [threaded scheduler], as it always has active
/// core threads, but if you use the [basic scheduler], some other
/// thread must currently be inside a call to [`Runtime::block_on`].
/// See also [the module level documentation][1], which has a section on
/// scheduler types.
///
/// This method may not be called from an asynchronous context.
///
/// [threaded scheduler]: fn@crate::runtime::Builder::threaded_scheduler
/// [basic scheduler]: fn@crate::runtime::Builder::basic_scheduler
/// [`Runtime::block_on`]: fn@crate::runtime::Runtime::block_on
/// [1]: index.html#runtime-configurations
///
/// # Panics
///
/// This function panics if the executor is at capacity, if the provided
/// future panics, or if called within an asynchronous execution context.
/// This function panics if the provided future panics, or if called
/// within an asynchronous execution context.
///
/// # Examples
///
/// ```no_run
/// Using `block_on` with the [threaded scheduler].
///
/// ```
/// use tokio::runtime::Runtime;
/// use std::thread;
///
/// // Create the runtime
/// // Create the runtime.
/// //
/// // If the rt-threaded feature is enabled, this creates a threaded
/// // scheduler by default.
/// let rt = Runtime::new().unwrap();
/// let handle = rt.handle().clone();
///
/// // Use the runtime from another thread
/// // Use the runtime from another thread.
/// let th = thread::spawn(move || {
/// // Execute the future, blocking the current thread until completion
/// // Execute the future, blocking the current thread until completion.
/// //
/// // This example uses the threaded scheduler, so no concurrent call to
/// // `rt.block_on` is required.
/// handle.block_on(async {
/// println!("hello");
/// });
......@@ -154,6 +213,47 @@ cfg_rt_core! {
///
/// th.join().unwrap();
/// ```
///
/// Using the [basic scheduler] requires a concurrent call to
/// [`Runtime::block_on`]:
///
/// [threaded scheduler]: fn@crate::runtime::Builder::threaded_scheduler
/// [basic scheduler]: fn@crate::runtime::Builder::basic_scheduler
/// [`Runtime::block_on`]: fn@crate::runtime::Runtime::block_on
///
/// ```
/// use tokio::runtime::Builder;
/// use tokio::sync::oneshot;
/// use std::thread;
///
/// // Create the runtime.
/// let mut rt = Builder::new()
/// .enable_all()
/// .basic_scheduler()
/// .build()
/// .unwrap();
///
/// let handle = rt.handle().clone();
///
/// // Signal main thread when task has finished.
/// let (send, recv) = oneshot::channel();
///
/// // Use the runtime from another thread.
/// let th = thread::spawn(move || {
/// // Execute the future, blocking the current thread until completion.
/// handle.block_on(async {
/// send.send("done").unwrap();
/// });
/// });
///
/// // The basic scheduler is used, so the thread above might hang if we
/// // didn't call block_on on the rt too.
/// rt.block_on(async {
/// assert_eq!(recv.await.unwrap(), "done");
/// });
/// # th.join().unwrap();
/// ```
///
pub fn block_on<F: Future>(&self, future: F) -> F::Output {
self.enter(|| {
let mut enter = crate::runtime::enter(true);
......
......@@ -379,8 +379,14 @@ impl Runtime {
///
/// # Panics
///
/// This function panics if the spawn fails. Failure occurs if the executor
/// is currently at capacity and is unable to spawn a new future.
/// 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
#[cfg(feature = "rt-core")]
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
......@@ -407,12 +413,12 @@ impl Runtime {
/// configured. [`runtime::Handle::block_on`][handle] provides a version
/// that takes `&self`.
///
/// This method should not be called from an asynchronous context.
/// This method may not be called from an asynchronous context.
///
/// # Panics
///
/// This function panics if the executor is at capacity, if the provided
/// future panics, or if called within an asynchronous execution context.
/// This function panics if the provided future panics, or if called within an
/// asynchronous execution context.
///
/// # Examples
///
......@@ -441,7 +447,38 @@ impl Runtime {
})
}
/// Enter the runtime context.
/// Enter the runtime context. This allows you to construct types that must
/// have an executor available on creation such as [`Delay`] or [`TcpStream`].
/// It will also allow you to call methods such as [`tokio::spawn`].
///
/// This function is also available as [`Handle::enter`].
///
/// [`Delay`]: struct@crate::time::Delay
/// [`TcpStream`]: struct@crate::net::TcpStream
/// [`Handle::enter`]: fn@crate::runtime::Handle::enter
/// [`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().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<F, R>(&self, f: F) -> R
where
F: FnOnce() -> R,
......@@ -476,7 +513,7 @@ impl Runtime {
/// 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`.
/// 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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment