Skip to main content

tokio/runtime/
runtime.rs

1use super::AutoBox;
2use crate::runtime::blocking::BlockingPool;
3use crate::runtime::scheduler::CurrentThread;
4use crate::runtime::{context, EnterGuard, Handle};
5use crate::task::JoinHandle;
6use crate::util::error::RUNTIME_SHUTTING_DOWN_ERROR;
7use crate::util::trace::SpawnMeta;
8
9use std::future::Future;
10use std::io;
11use std::mem;
12use std::time::Duration;
13
14cfg_rt_multi_thread! {
15    use crate::runtime::Builder;
16    use crate::runtime::scheduler::MultiThread;
17}
18
19/// The Tokio runtime.
20///
21/// The runtime provides an I/O driver, task scheduler, [timer], and
22/// blocking pool, necessary for running asynchronous tasks.
23///
24/// Instances of `Runtime` can be created using [`new`], or [`Builder`].
25/// However, most users will use the [`#[tokio::main]`][main] annotation on
26/// their entry point instead.
27///
28/// See [module level][mod] documentation for more details.
29///
30/// # Shutdown
31///
32/// Shutting down the runtime is done by dropping the value, or calling
33/// [`shutdown_background`] or [`shutdown_timeout`].
34///
35/// Tasks spawned through [`Runtime::spawn`] keep running until they yield.
36/// Then they are dropped. They are not *guaranteed* to run to completion, but
37/// *might* do so if they do not yield until completion.
38///
39/// Blocking functions spawned through [`Runtime::spawn_blocking`] keep running
40/// until they return.
41///
42/// The thread initiating the shutdown blocks until all spawned work has been
43/// stopped. This can take an indefinite amount of time. The `Drop`
44/// implementation waits forever for this.
45///
46/// The [`shutdown_background`] and [`shutdown_timeout`] methods can be used if
47/// waiting forever is undesired. When the timeout is reached, spawned work that
48/// did not stop in time and threads running it are leaked. The work continues
49/// to run until one of the stopping conditions is fulfilled, but the thread
50/// initiating the shutdown is unblocked.
51///
52/// Once the runtime has been dropped, any outstanding I/O resources bound to
53/// it will no longer function. Calling any method on them will result in an
54/// error.
55///
56/// # Sharing
57///
58/// There are several ways to establish shared access to a Tokio runtime:
59///
60///  * Using an <code>[Arc]\<Runtime></code>.
61///  * Using a [`Handle`].
62///  * Entering the runtime context.
63///
64/// Using an <code>[Arc]\<Runtime></code> or [`Handle`] allows you to do various
65/// things with the runtime such as spawning new tasks or entering the runtime
66/// context. Both types can be cloned to create a new handle that allows access
67/// to the same runtime. By passing clones into different tasks or threads, you
68/// will be able to access the runtime from those tasks or threads.
69///
70/// The difference between <code>[Arc]\<Runtime></code> and [`Handle`] is that
71/// an <code>[Arc]\<Runtime></code> will prevent the runtime from shutting down,
72/// whereas a [`Handle`] does not prevent that. This is because shutdown of the
73/// runtime happens when the destructor of the `Runtime` object runs.
74///
75/// Calls to [`shutdown_background`] and [`shutdown_timeout`] require exclusive
76/// ownership of the `Runtime` type. When using an <code>[Arc]\<Runtime></code>,
77/// this can be achieved via [`Arc::try_unwrap`] when only one strong count
78/// reference is left over.
79///
80/// The runtime context is entered using the [`Runtime::enter`] or
81/// [`Handle::enter`] methods, which use a thread-local variable to store the
82/// current runtime. Whenever you are inside the runtime context, methods such
83/// as [`tokio::spawn`] will use the runtime whose context you are inside.
84///
85/// [timer]: crate::time
86/// [mod]: index.html
87/// [`new`]: method@Self::new
88/// [`Builder`]: struct@Builder
89/// [`Handle`]: struct@Handle
90/// [main]: macro@crate::main
91/// [`tokio::spawn`]: crate::spawn
92/// [`Arc::try_unwrap`]: std::sync::Arc::try_unwrap
93/// [Arc]: std::sync::Arc
94/// [`shutdown_background`]: method@Runtime::shutdown_background
95/// [`shutdown_timeout`]: method@Runtime::shutdown_timeout
96#[derive(Debug)]
97pub struct Runtime {
98    /// Task scheduler
99    scheduler: Scheduler,
100
101    /// Handle to runtime, also contains driver handles
102    handle: Handle,
103
104    /// Blocking pool handle, used to signal shutdown
105    blocking_pool: BlockingPool,
106}
107
108/// The flavor of a `Runtime`.
109///
110/// This is the return type for [`Handle::runtime_flavor`](crate::runtime::Handle::runtime_flavor()).
111#[derive(Debug, PartialEq, Eq)]
112#[non_exhaustive]
113pub enum RuntimeFlavor {
114    /// The flavor that executes all tasks on the current thread.
115    CurrentThread,
116    /// The flavor that executes tasks across multiple threads.
117    MultiThread,
118}
119
120/// The runtime scheduler is either a multi-thread or a current-thread executor.
121#[derive(Debug)]
122pub(super) enum Scheduler {
123    /// Execute all tasks on the current-thread.
124    CurrentThread(CurrentThread),
125
126    /// Execute tasks across multiple threads.
127    #[cfg(feature = "rt-multi-thread")]
128    MultiThread(MultiThread),
129}
130
131impl Runtime {
132    pub(super) fn from_parts(
133        scheduler: Scheduler,
134        handle: Handle,
135        blocking_pool: BlockingPool,
136    ) -> Runtime {
137        Runtime {
138            scheduler,
139            handle,
140            blocking_pool,
141        }
142    }
143
144    /// Creates a new runtime instance with default configuration values.
145    ///
146    /// This results in the multi threaded scheduler, I/O driver, and time driver being
147    /// initialized.
148    ///
149    /// Most applications will not need to call this function directly. Instead,
150    /// they will use the  [`#[tokio::main]` attribute][main]. When a more complex
151    /// configuration is necessary, the [runtime builder] may be used.
152    ///
153    /// See [module level][mod] documentation for more details.
154    ///
155    /// # Examples
156    ///
157    /// Creating a new `Runtime` with default configuration values.
158    ///
159    /// ```
160    /// use tokio::runtime::Runtime;
161    ///
162    /// let rt = Runtime::new()
163    ///     .unwrap();
164    ///
165    /// // Use the runtime...
166    /// ```
167    ///
168    /// # Errors
169    ///
170    /// Returns an error if the I/O driver or other OS resources required by the
171    /// runtime cannot be initialized.
172    ///
173    /// [mod]: index.html
174    /// [main]: ../attr.main.html
175    /// [threaded scheduler]: index.html#threaded-scheduler
176    /// [runtime builder]: crate::runtime::Builder
177    #[cfg(feature = "rt-multi-thread")]
178    #[cfg_attr(docsrs, doc(cfg(feature = "rt-multi-thread")))]
179    pub fn new() -> std::io::Result<Runtime> {
180        Builder::new_multi_thread().enable_all().build()
181    }
182
183    /// Returns a handle to the runtime's spawner.
184    ///
185    /// The returned handle can be used to spawn tasks that run on this runtime, and can
186    /// be cloned to allow moving the `Handle` to other threads.
187    ///
188    /// Calling [`Handle::block_on`] on a handle to a `current_thread` runtime is error-prone.
189    /// Refer to the documentation of [`Handle::block_on`] for more.
190    ///
191    /// # Examples
192    ///
193    /// ```
194    /// # #[cfg(not(target_family = "wasm"))]
195    /// # {
196    /// use tokio::runtime::Runtime;
197    ///
198    /// let rt = Runtime::new()
199    ///     .unwrap();
200    ///
201    /// let handle = rt.handle();
202    ///
203    /// // Use the handle...
204    /// # }
205    /// ```
206    pub fn handle(&self) -> &Handle {
207        &self.handle
208    }
209
210    /// Spawns a future onto the Tokio runtime.
211    ///
212    /// This spawns the given future onto the runtime's executor, usually a
213    /// thread pool. The thread pool is then responsible for polling the future
214    /// until it completes.
215    ///
216    /// The provided future will start running in the background immediately
217    /// when `spawn` is called, even if you don't await the returned
218    /// `JoinHandle` (assuming that the runtime [is running][running-runtime]).
219    ///
220    /// See [module level][mod] documentation for more details.
221    ///
222    /// [mod]: index.html
223    /// [running-runtime]: index.html#driving-the-runtime
224    ///
225    /// # Examples
226    ///
227    /// ```
228    /// # #[cfg(not(target_family = "wasm"))]
229    /// # {
230    /// use tokio::runtime::Runtime;
231    ///
232    /// # fn dox() {
233    /// // Create the runtime
234    /// let rt = Runtime::new().unwrap();
235    ///
236    /// // Spawn a future onto the runtime
237    /// rt.spawn(async {
238    ///     println!("now running on a worker thread");
239    /// });
240    /// # }
241    /// # }
242    /// ```
243    #[track_caller]
244    pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
245    where
246        F: Future + Send + 'static,
247        F::Output: Send + 'static,
248    {
249        let fut_size = mem::size_of::<F>();
250        if AutoBox::<F>::SHOULD_BOX {
251            self.handle
252                .spawn_named(Box::pin(future), SpawnMeta::new_unnamed(fut_size))
253        } else {
254            self.handle
255                .spawn_named(future, SpawnMeta::new_unnamed(fut_size))
256        }
257    }
258
259    /// Runs the provided function on an executor dedicated to blocking operations.
260    ///
261    /// # Examples
262    ///
263    /// ```
264    /// # #[cfg(not(target_family = "wasm"))]
265    /// # {
266    /// use tokio::runtime::Runtime;
267    ///
268    /// # fn dox() {
269    /// // Create the runtime
270    /// let rt = Runtime::new().unwrap();
271    ///
272    /// // Spawn a blocking function onto the runtime
273    /// rt.spawn_blocking(|| {
274    ///     println!("now running on a worker thread");
275    /// });
276    /// # }
277    /// # }
278    /// ```
279    #[track_caller]
280    pub fn spawn_blocking<F, R>(&self, func: F) -> JoinHandle<R>
281    where
282        F: FnOnce() -> R + Send + 'static,
283        R: Send + 'static,
284    {
285        self.handle.spawn_blocking(func)
286    }
287
288    /// Runs a future to completion on the Tokio runtime. This is the
289    /// runtime's entry point.
290    ///
291    /// This runs the given future on the current thread, blocking until it is
292    /// complete, and yielding its resolved result. Any tasks or timers
293    /// which the future spawns internally will be executed on the runtime.
294    ///
295    /// # Non-worker future
296    ///
297    /// Note that the future required by this function does not run as a
298    /// worker. The expectation is that other tasks are spawned by the future here.
299    /// Awaiting on other futures from the future provided here will not
300    /// perform as fast as those spawned as workers.
301    ///
302    /// # Multi thread scheduler
303    ///
304    /// When the multi thread scheduler is used this will allow futures
305    /// to run within the io driver and timer context of the overall runtime.
306    ///
307    /// Any spawned tasks will continue running after `block_on` returns.
308    ///
309    /// # Current thread scheduler
310    ///
311    /// When the current thread scheduler is enabled `block_on`
312    /// can be called concurrently from multiple threads. The first call
313    /// will take ownership of the io and timer drivers. This means
314    /// other threads which do not own the drivers will hook into that one.
315    /// When the first `block_on` completes, other threads will be able to
316    /// "steal" the driver to allow continued execution of their futures.
317    ///
318    /// Any spawned tasks will be suspended after `block_on` returns. Calling
319    /// `block_on` again will resume previously spawned tasks.
320    ///
321    /// # Panics
322    ///
323    /// This function panics if the provided future panics, or if called within an
324    /// asynchronous execution context.
325    ///
326    /// # Examples
327    ///
328    /// ```no_run
329    /// # #[cfg(not(target_family = "wasm"))]
330    /// # {
331    /// use tokio::runtime::Runtime;
332    ///
333    /// // Create the runtime
334    /// let rt  = Runtime::new().unwrap();
335    ///
336    /// // Execute the future, blocking the current thread until completion
337    /// rt.block_on(async {
338    ///     println!("hello");
339    /// });
340    /// # }
341    /// ```
342    #[track_caller]
343    pub fn block_on<F: Future>(&self, future: F) -> F::Output {
344        let fut_size = mem::size_of::<F>();
345        if AutoBox::<F>::SHOULD_BOX {
346            self.block_on_inner(Box::pin(future), SpawnMeta::new_unnamed(fut_size))
347        } else {
348            self.block_on_inner(future, SpawnMeta::new_unnamed(fut_size))
349        }
350    }
351
352    #[track_caller]
353    fn block_on_inner<F: Future>(&self, future: F, _meta: SpawnMeta<'_>) -> F::Output {
354        #[cfg(all(
355            tokio_unstable,
356            feature = "taskdump",
357            feature = "rt",
358            target_os = "linux",
359            any(
360                target_arch = "aarch64",
361                target_arch = "x86",
362                target_arch = "x86_64",
363                target_arch = "s390x"
364            )
365        ))]
366        let future = super::task::trace::Trace::root(future);
367
368        #[cfg(all(tokio_unstable, feature = "tracing"))]
369        let future = crate::util::trace::task(
370            future,
371            "block_on",
372            _meta,
373            crate::runtime::task::Id::next().as_u64(),
374        );
375
376        let _enter = self.enter();
377
378        match &self.scheduler {
379            Scheduler::CurrentThread(exec) => exec.block_on(&self.handle.inner, future),
380            #[cfg(feature = "rt-multi-thread")]
381            Scheduler::MultiThread(exec) => exec.block_on(&self.handle.inner, future),
382        }
383    }
384
385    /// Enters the runtime context.
386    ///
387    /// This allows you to construct types that must have an executor
388    /// available on creation such as [`Sleep`] or [`TcpStream`]. It will
389    /// also allow you to call methods such as [`tokio::spawn`].
390    ///
391    /// [`Sleep`]: struct@crate::time::Sleep
392    /// [`TcpStream`]: struct@crate::net::TcpStream
393    /// [`tokio::spawn`]: fn@crate::spawn
394    ///
395    /// # Example
396    ///
397    /// ```
398    /// # #[cfg(not(target_family = "wasm"))]
399    /// # {
400    /// use tokio::runtime::Runtime;
401    /// use tokio::task::JoinHandle;
402    ///
403    /// fn function_that_spawns(msg: String) -> JoinHandle<()> {
404    ///     // Had we not used `rt.enter` below, this would panic.
405    ///     tokio::spawn(async move {
406    ///         println!("{}", msg);
407    ///     })
408    /// }
409    ///
410    /// fn main() {
411    ///     let rt = Runtime::new().unwrap();
412    ///
413    ///     let s = "Hello World!".to_string();
414    ///
415    ///     // By entering the context, we tie `tokio::spawn` to this executor.
416    ///     let _guard = rt.enter();
417    ///     let handle = function_that_spawns(s);
418    ///
419    ///     // Wait for the task before we end the test.
420    ///     rt.block_on(handle).unwrap();
421    /// }
422    /// # }
423    /// ```
424    pub fn enter(&self) -> EnterGuard<'_> {
425        self.handle.enter()
426    }
427
428    /// Shuts down the runtime, waiting for at most `duration` for all spawned
429    /// work to stop.
430    ///
431    /// See the [struct level documentation](Runtime#shutdown) for more details.
432    ///
433    /// # Examples
434    ///
435    /// ```
436    /// # #[cfg(not(target_family = "wasm"))]
437    /// # {
438    /// use tokio::runtime::Runtime;
439    /// use tokio::task;
440    ///
441    /// use std::thread;
442    /// use std::time::Duration;
443    ///
444    /// fn main() {
445    ///    let runtime = Runtime::new().unwrap();
446    ///
447    ///    runtime.block_on(async move {
448    ///        task::spawn_blocking(move || {
449    ///            thread::sleep(Duration::from_secs(10_000));
450    ///        });
451    ///    });
452    ///
453    ///    runtime.shutdown_timeout(Duration::from_millis(100));
454    /// }
455    /// # }
456    /// ```
457    pub fn shutdown_timeout(mut self, duration: Duration) {
458        // Wakeup and shutdown all the worker threads
459        self.handle.inner.shutdown();
460        self.blocking_pool.shutdown(Some(duration));
461    }
462
463    /// Shuts down the runtime, without waiting for any spawned work to stop.
464    ///
465    /// This can be useful if you want to drop a runtime from within another runtime.
466    /// Normally, dropping a runtime will block indefinitely for spawned blocking tasks
467    /// to complete, which would normally not be permitted within an asynchronous context.
468    /// By calling `shutdown_background()`, you can drop the runtime from such a context.
469    ///
470    /// Note however, that because we do not wait for any blocking tasks to complete, this
471    /// may result in a resource leak (in that any blocking tasks are still running until they
472    /// return.
473    ///
474    /// See the [struct level documentation](Runtime#shutdown) for more details.
475    ///
476    /// This function is equivalent to calling `shutdown_timeout(Duration::from_nanos(0))`.
477    ///
478    /// ```
479    /// # #[cfg(not(target_family = "wasm"))]
480    /// # {
481    /// use tokio::runtime::Runtime;
482    ///
483    /// fn main() {
484    ///    let runtime = Runtime::new().unwrap();
485    ///
486    ///    runtime.block_on(async move {
487    ///        let inner_runtime = Runtime::new().unwrap();
488    ///        // ...
489    ///        inner_runtime.shutdown_background();
490    ///    });
491    /// }
492    /// # }
493    /// ```
494    pub fn shutdown_background(self) {
495        self.shutdown_timeout(Duration::from_nanos(0));
496    }
497
498    /// Returns a view that lets you get information about how the runtime
499    /// is performing.
500    pub fn metrics(&self) -> crate::runtime::RuntimeMetrics {
501        self.handle.metrics()
502    }
503}
504
505impl Drop for Runtime {
506    fn drop(&mut self) {
507        match &mut self.scheduler {
508            Scheduler::CurrentThread(current_thread) => {
509                // This ensures that tasks spawned on the current-thread
510                // runtime are dropped inside the runtime's context.
511                let _guard = context::try_set_current(&self.handle.inner);
512                current_thread.shutdown(&self.handle.inner);
513            }
514            #[cfg(feature = "rt-multi-thread")]
515            Scheduler::MultiThread(multi_thread) => {
516                // The threaded scheduler drops its tasks on its worker threads, which is
517                // already in the runtime's context.
518                multi_thread.shutdown(&self.handle.inner);
519            }
520        }
521    }
522}
523
524impl std::panic::UnwindSafe for Runtime {}
525
526impl std::panic::RefUnwindSafe for Runtime {}
527
528fn display_eq(d: impl std::fmt::Display, s: &str) -> bool {
529    use std::fmt::Write;
530
531    struct FormatEq<'r> {
532        remainder: &'r str,
533        unequal: bool,
534    }
535
536    impl<'r> Write for FormatEq<'r> {
537        fn write_str(&mut self, s: &str) -> std::fmt::Result {
538            if !self.unequal {
539                if let Some(new_remainder) = self.remainder.strip_prefix(s) {
540                    self.remainder = new_remainder;
541                } else {
542                    self.unequal = true;
543                }
544            }
545            Ok(())
546        }
547    }
548
549    let mut fmt_eq = FormatEq {
550        remainder: s,
551        unequal: false,
552    };
553    let _ = write!(fmt_eq, "{d}");
554    fmt_eq.remainder.is_empty() && !fmt_eq.unequal
555}
556
557/// Checks whether the given error was emitted by Tokio when shutting down its runtime.
558///
559/// # Examples
560///
561/// ```
562/// # #[cfg(not(target_family = "wasm"))]
563/// # {
564/// use tokio::runtime::Runtime;
565/// use tokio::net::TcpListener;
566///
567/// fn main() {
568///     let rt1 = Runtime::new().unwrap();
569///     let rt2 = Runtime::new().unwrap();
570///
571///     let listener = rt1.block_on(async {
572///         TcpListener::bind("127.0.0.1:0").await.unwrap()
573///     });
574///
575///     drop(rt1);
576///
577///     rt2.block_on(async {
578///         let res = listener.accept().await;
579///         assert!(res.is_err());
580///         assert!(tokio::runtime::is_rt_shutdown_err(res.as_ref().unwrap_err()));
581///     });
582/// }
583/// # }
584/// ```
585pub fn is_rt_shutdown_err(err: &io::Error) -> bool {
586    if let Some(inner) = err.get_ref() {
587        err.kind() == io::ErrorKind::Other
588            && inner.source().is_none()
589            && display_eq(inner, RUNTIME_SHUTTING_DOWN_ERROR)
590    } else {
591        false
592    }
593}