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}