madsim_real_tokio/runtime/
runtime.rs

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