tokio/runtime/mod.rs
1//! The Tokio runtime.
2//!
3//! Unlike other Rust programs, asynchronous applications require runtime
4//! support. In particular, the following runtime services are necessary:
5//!
6//! * An **I/O event loop**, called the driver, which drives I/O resources and
7//! dispatches I/O events to tasks that depend on them.
8//! * A **scheduler** to execute [tasks] that use these I/O resources.
9//! * A **timer** for scheduling work to run after a set period of time.
10//!
11//! Tokio's [`Runtime`] bundles all of these services as a single type, allowing
12//! them to be started, shut down, and configured together. However, often it is
13//! not required to configure a [`Runtime`] manually, and a user may just use the
14//! [`tokio::main`] attribute macro, which creates a [`Runtime`] under the hood.
15//!
16//! # Choose your runtime
17//!
18//! Here is the rules of thumb to choose the right runtime for your application.
19//!
20//! ```plaintext
21//! +------------------------------------------------------+
22//! | Do you want work-stealing or multi-thread scheduler? |
23//! +------------------------------------------------------+
24//! | Yes | No
25//! | |
26//! | |
27//! v |
28//! +------------------------+ |
29//! | Multi-threaded Runtime | |
30//! +------------------------+ |
31//! |
32//! V
33//! +--------------------------------+
34//! | Do you execute `!Send` Future? |
35//! +--------------------------------+
36//! | Yes | No
37//! | |
38//! V |
39//! +---------------+ |
40//! | Local Runtime | |
41//! +---------------+ |
42//! |
43//! v
44//! +------------------------+
45//! | Current-thread Runtime |
46//! +------------------------+
47//! ```
48//!
49//! The above decision tree is not exhaustive. there are other factors that
50//! may influence your decision.
51//!
52//! ## Bridging with sync code
53//!
54//! See <https://tokio.rs/tokio/topics/bridging> for details.
55//!
56//! ## NUMA awareness
57//!
58//! The tokio runtime is not NUMA (Non-Uniform Memory Access) aware.
59//! You may want to start multiple runtimes instead of a single runtime
60//! for better performance on NUMA systems.
61//!
62//! # Usage
63//!
64//! When no fine tuning is required, the [`tokio::main`] attribute macro can be
65//! used.
66//!
67//! ```no_run
68//! # #[cfg(not(target_family = "wasm"))]
69//! # {
70//! use tokio::net::TcpListener;
71//! use tokio::io::{AsyncReadExt, AsyncWriteExt};
72//!
73//! #[tokio::main]
74//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
75//! let listener = TcpListener::bind("127.0.0.1:8080").await?;
76//!
77//! loop {
78//! let (mut socket, _) = listener.accept().await?;
79//!
80//! tokio::spawn(async move {
81//! let mut buf = [0; 1024];
82//!
83//! // In a loop, read data from the socket and write the data back.
84//! loop {
85//! let n = match socket.read(&mut buf).await {
86//! // socket closed
87//! Ok(0) => return,
88//! Ok(n) => n,
89//! Err(e) => {
90//! println!("failed to read from socket; err = {:?}", e);
91//! return;
92//! }
93//! };
94//!
95//! // Write the data back
96//! if let Err(e) = socket.write_all(&buf[0..n]).await {
97//! println!("failed to write to socket; err = {:?}", e);
98//! return;
99//! }
100//! }
101//! });
102//! }
103//! }
104//! # }
105//! ```
106//!
107//! From within the context of the runtime, additional tasks are spawned using
108//! the [`tokio::spawn`] function. Futures spawned using this function will be
109//! executed on the same thread pool used by the [`Runtime`].
110//!
111//! A [`Runtime`] instance can also be used directly.
112//!
113//! ```no_run
114//! # #[cfg(not(target_family = "wasm"))]
115//! # {
116//! use tokio::net::TcpListener;
117//! use tokio::io::{AsyncReadExt, AsyncWriteExt};
118//! use tokio::runtime::Runtime;
119//!
120//! fn main() -> Result<(), Box<dyn std::error::Error>> {
121//! // Create the runtime
122//! let rt = Runtime::new()?;
123//!
124//! // Spawn the root task
125//! rt.block_on(async {
126//! let listener = TcpListener::bind("127.0.0.1:8080").await?;
127//!
128//! loop {
129//! let (mut socket, _) = listener.accept().await?;
130//!
131//! tokio::spawn(async move {
132//! let mut buf = [0; 1024];
133//!
134//! // In a loop, read data from the socket and write the data back.
135//! loop {
136//! let n = match socket.read(&mut buf).await {
137//! // socket closed
138//! Ok(0) => return,
139//! Ok(n) => n,
140//! Err(e) => {
141//! println!("failed to read from socket; err = {:?}", e);
142//! return;
143//! }
144//! };
145//!
146//! // Write the data back
147//! if let Err(e) = socket.write_all(&buf[0..n]).await {
148//! println!("failed to write to socket; err = {:?}", e);
149//! return;
150//! }
151//! }
152//! });
153//! }
154//! })
155//! }
156//! # }
157//! ```
158//!
159//! ## Runtime Configurations
160//!
161//! Tokio provides multiple task scheduling strategies, suitable for different
162//! applications. The [runtime builder] or `#[tokio::main]` attribute may be
163//! used to select which scheduler to use.
164//!
165//! #### Multi-Thread Scheduler
166//!
167//! The multi-thread scheduler executes futures on a _thread pool_, using a
168//! work-stealing strategy. By default, it will start a worker thread for each
169//! CPU core available on the system. This tends to be the ideal configuration
170//! for most applications, but see the docs of
171//! [`std::thread::available_parallelism`] for caveats. The multi-thread
172//! scheduler requires the `rt-multi-thread` feature flag, and is selected by
173//! default:
174//! ```
175//! # #[cfg(not(target_family = "wasm"))]
176//! # {
177//! use tokio::runtime;
178//!
179//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
180//! let threaded_rt = runtime::Runtime::new()?;
181//! # Ok(()) }
182//! # }
183//! ```
184//!
185//! Most applications should use the multi-thread scheduler, except in some
186//! niche use-cases, such as when running only a single thread is required.
187//!
188//! #### Current-Thread Scheduler
189//!
190//! The current-thread scheduler provides a _single-threaded_ future executor.
191//! All tasks will be created and executed on the current thread. This requires
192//! the `rt` feature flag.
193//! ```
194//! use tokio::runtime;
195//!
196//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
197//! let rt = runtime::Builder::new_current_thread()
198//! .build()?;
199//! # Ok(()) }
200//! ```
201//!
202//! #### Resource drivers
203//!
204//! When configuring a runtime by hand, no resource drivers are enabled by
205//! default. In this case, attempting to use networking types or time types will
206//! fail. In order to enable these types, the resource drivers must be enabled.
207//! This is done with [`Builder::enable_io`] and [`Builder::enable_time`]. As a
208//! shorthand, [`Builder::enable_all`] enables both resource drivers.
209//!
210//! ## Driving the runtime
211//!
212//! A Tokio runtime can only execute tasks if the runtime is running. Normally
213//! this is not an issue as the default configuration of a runtime is always running,
214//! but alternate configurations such as the current-thread runtime require that
215//! [`Runtime::block_on`] is called.
216//!
217//! - A multi-threaded runtime is always running because it spawns its own worker
218//! threads.
219//! - A current-thread runtime does not spawn any worker threads, so it can only
220//! execute tasks when you provide a thread by calling [`Runtime::block_on`].
221//! - A [`LocalSet`](crate::task::LocalSet) only executes local tasks spawned on
222//! it when the `LocalSet` is `.awaited` or otherwise driven using one of its
223//! methods for this purpose.
224//!
225//! Please be aware that [`Handle::block_on`] does not drive the runtime.
226//! There must be at least one call to [`Runtime::block_on`] when using the current
227//! thread runtime. [`Handle::block_on`] is not enough.
228//!
229//! ## Lifetime of spawned threads
230//!
231//! The runtime may spawn threads depending on its configuration and usage. The
232//! multi-thread scheduler spawns threads to schedule tasks and for `spawn_blocking`
233//! calls.
234//!
235//! While the `Runtime` is active, threads may shut down after periods of being
236//! idle. Once `Runtime` is dropped, all runtime threads have usually been
237//! terminated, but in the presence of unstoppable spawned work are not
238//! guaranteed to have been terminated. See the
239//! [struct level documentation](Runtime#shutdown) for more details.
240//!
241//! ## Unix `fork`
242//!
243//! User code that calls `fork(2)` without immediately calling `exec` must not
244//! reuse Tokio in the child process. Tokio supports this kind of fork only in
245//! two cases:
246//!
247//! - The fork happens before the parent process has used Tokio in any way.
248//! - The child process does not use Tokio after the fork.
249//!
250//! Creating or using a Tokio runtime in a child process after the parent has
251//! used Tokio is not supported, even if the runtime in the child is newly
252//! created. Some Tokio modules, including process and signal handling, use
253//! process-global state that cannot currently be reset after `fork`.
254//!
255//! [tasks]: crate::task
256//! [`Runtime`]: Runtime
257//! [`tokio::spawn`]: crate::spawn
258//! [`tokio::main`]: ../attr.main.html
259//! [runtime builder]: crate::runtime::Builder
260//! [`Runtime::new`]: crate::runtime::Runtime::new
261//! [`Builder::enable_io`]: crate::runtime::Builder::enable_io
262//! [`Builder::enable_time`]: crate::runtime::Builder::enable_time
263//! [`Builder::enable_all`]: crate::runtime::Builder::enable_all
264//!
265//! # Detailed runtime behavior
266//!
267//! This section gives more details into how the Tokio runtime will schedule
268//! tasks for execution.
269//!
270//! At its most basic level, a runtime has a collection of tasks that need to be
271//! scheduled. It will repeatedly remove a task from that collection and
272//! schedule it (by calling [`poll`]). When the collection is empty, the thread
273//! will go to sleep until a task is added to the collection.
274//!
275//! However, the above is not sufficient to guarantee a well-behaved runtime.
276//! For example, the runtime might have a single task that is always ready to be
277//! scheduled, and schedule that task every time. This is a problem because it
278//! starves other tasks by not scheduling them. To solve this, Tokio provides
279//! the following fairness guarantee:
280//!
281//! > If the total number of tasks does not grow without bound, and no task is
282//! > [blocking the thread], then it is guaranteed that tasks are scheduled
283//! > fairly.
284//!
285//! Or, more formally:
286//!
287//! > Under the following two assumptions:
288//! >
289//! > * There is some number `MAX_TASKS` such that the total number of tasks on
290//! > the runtime at any specific point in time never exceeds `MAX_TASKS`.
291//! > * There is some number `MAX_SCHEDULE` such that calling [`poll`] on any
292//! > task spawned on the runtime returns within `MAX_SCHEDULE` time units.
293//! >
294//! > Then, there is some number `MAX_DELAY` such that when a task is woken, it
295//! > will be scheduled by the runtime within `MAX_DELAY` time units.
296//!
297//! (Here, `MAX_TASKS` and `MAX_SCHEDULE` can be any number and the user of
298//! the runtime may choose them. The `MAX_DELAY` number is controlled by the
299//! runtime, and depends on the value of `MAX_TASKS` and `MAX_SCHEDULE`.)
300//!
301//! Other than the above fairness guarantee, there is no guarantee about the
302//! order in which tasks are scheduled. There is also no guarantee that the
303//! runtime is equally fair to all tasks. For example, if the runtime has two
304//! tasks A and B that are both ready, then the runtime may schedule A five
305//! times before it schedules B. This is the case even if A yields using
306//! [`yield_now`]. All that is guaranteed is that it will schedule B eventually.
307//!
308//! Normally, tasks are scheduled only if they have been woken by calling
309//! [`wake`] on their waker. However, this is not guaranteed, and Tokio may
310//! schedule tasks that have not been woken under some circumstances. This is
311//! called a spurious wakeup.
312//!
313//! ## IO and timers
314//!
315//! Beyond just scheduling tasks, the runtime must also manage IO resources and
316//! timers. It does this by periodically checking whether there are any IO
317//! resources or timers that are ready, and waking the relevant task so that
318//! it will be scheduled.
319//!
320//! These checks are performed periodically between scheduling tasks. Under the
321//! same assumptions as the previous fairness guarantee, Tokio guarantees that
322//! it will wake tasks with an IO or timer event within some maximum number of
323//! time units.
324//!
325//! ## Current thread runtime (behavior at the time of writing)
326//!
327//! This section describes how the [current thread runtime] behaves today. This
328//! behavior may change in future versions of Tokio.
329//!
330//! The current thread runtime maintains two FIFO queues of tasks that are ready
331//! to be scheduled: the global queue and the local queue. The runtime will prefer
332//! to choose the next task to schedule from the local queue, and will only pick a
333//! task from the global queue if the local queue is empty, or if it has picked
334//! a task from the local queue 31 times in a row. The number 31 can be
335//! changed using the [`global_queue_interval`] setting.
336//!
337//! The runtime will check for new IO or timer events whenever there are no
338//! tasks ready to be scheduled, or when it has scheduled 61 tasks in a row. The
339//! number 61 may be changed using the [`event_interval`] setting.
340//!
341//! When a task is woken from within a task running on the runtime, then the
342//! woken task is added directly to the local queue. Otherwise, the task is
343//! added to the global queue. The current thread runtime does not use [the lifo
344//! slot optimization].
345//!
346//! ## Multi threaded runtime (behavior at the time of writing)
347//!
348//! This section describes how the [multi thread runtime] behaves today. This
349//! behavior may change in future versions of Tokio.
350//!
351//! A multi thread runtime has a fixed number of worker threads, which are all
352//! created on startup. The multi thread runtime maintains one global queue, and
353//! a local queue for each worker thread. The local queue of a worker thread can
354//! fit at most 256 tasks. If more than 256 tasks are added to the local queue,
355//! then half of them are moved to the global queue to make space.
356//!
357//! The runtime will prefer to choose the next task to schedule from the local
358//! queue, and will only pick a task from the global queue if the local queue is
359//! empty, or if it has picked a task from the local queue
360//! [`global_queue_interval`] times in a row. If the value of
361//! [`global_queue_interval`] is not explicitly set using the runtime builder,
362//! then the runtime will dynamically compute it using a heuristic that targets
363//! 10ms intervals between each check of the global queue (based on the
364//! [`worker_mean_poll_time`] metric).
365//!
366//! If both the local queue and global queue is empty, then the worker thread
367//! will attempt to steal tasks from the local queue of another worker thread.
368//! Stealing is done by moving half of the tasks in one local queue to another
369//! local queue.
370//!
371//! The runtime will check for new IO or timer events whenever there are no
372//! tasks ready to be scheduled, or when it has scheduled 61 tasks in a row. The
373//! number 61 may be changed using the [`event_interval`] setting.
374//!
375//! The multi thread runtime uses [the lifo slot optimization]: Whenever a task
376//! wakes up another task, the other task is added to the worker thread's lifo
377//! slot instead of being added to a queue. If there was already a task in the
378//! lifo slot when this happened, then the lifo slot is replaced, and the task
379//! that used to be in the lifo slot is placed in the thread's local queue.
380//! When the runtime finishes scheduling a task, it will schedule the task in
381//! the lifo slot immediately, if any. When the lifo slot is used, the [coop
382//! budget] is not reset. Furthermore, if a worker thread uses the lifo slot
383//! three times in a row, it is temporarily disabled until the worker thread has
384//! scheduled a task that didn't come from the lifo slot. The lifo slot can be
385//! disabled using the [`disable_lifo_slot`] setting. The lifo slot is separate
386//! from the local queue, so other worker threads cannot steal the task in the
387//! lifo slot.
388//!
389//! When a task is woken from a thread that is not a worker thread, then the
390//! task is placed in the global queue.
391//!
392//! # Performance tuning
393//!
394//! ## File descriptor table pre-warming
395//!
396//! On Linux, file descriptor table growth can stall worker threads. See the
397//! [`prewarm-fd-table`] example.
398//!
399//! [`poll`]: std::future::Future::poll
400//! [`wake`]: std::task::Waker::wake
401//! [`yield_now`]: crate::task::yield_now
402//! [blocking the thread]: https://ryhl.io/blog/async-what-is-blocking/
403//! [current thread runtime]: crate::runtime::Builder::new_current_thread
404//! [multi thread runtime]: crate::runtime::Builder::new_multi_thread
405//! [`global_queue_interval`]: crate::runtime::Builder::global_queue_interval
406//! [`event_interval`]: crate::runtime::Builder::event_interval
407//! [`disable_lifo_slot`]: crate::runtime::Builder::disable_lifo_slot
408//! [the lifo slot optimization]: crate::runtime::Builder::disable_lifo_slot
409//! [coop budget]: crate::task::coop#cooperative-scheduling
410//! [`worker_mean_poll_time`]: crate::runtime::RuntimeMetrics::worker_mean_poll_time
411//! [`prewarm-fd-table`]: https://github.com/tokio-rs/tokio/blob/master/examples/prewarm-fd-table.rs
412
413// At the top due to macros
414#[cfg(test)]
415#[cfg(not(target_family = "wasm"))]
416#[macro_use]
417mod tests;
418
419pub(crate) mod context;
420
421pub(crate) mod park;
422
423#[cfg(all(target_os = "emscripten", not(target_feature = "atomics")))]
424pub(crate) mod jspi;
425
426pub(crate) mod driver;
427
428pub(crate) mod scheduler;
429
430cfg_io_driver_impl! {
431 pub(crate) mod io;
432}
433
434cfg_process_driver! {
435 mod process;
436}
437
438#[allow(dead_code)]
439#[derive(Debug, Copy, Clone, PartialEq)]
440pub(crate) enum TimerFlavor {
441 Traditional,
442 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
443 Alternative,
444}
445
446cfg_time! {
447 pub(crate) mod time;
448
449 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
450 pub(crate) mod time_alt;
451
452 use std::task::{Context, Poll};
453 use std::pin::Pin;
454
455 #[derive(Debug)]
456 pub(crate) enum Timer {
457 Traditional(time::TimerEntry),
458
459 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
460 Alternative(time_alt::Timer),
461 }
462
463 impl Timer {
464 #[cfg_attr(not(all(tokio_unstable, feature = "rt-multi-thread")), allow(unused_variables))]
465 #[track_caller]
466 pub(crate) fn new(handle: &scheduler::Handle, deadline: u64) -> Self {
467 match handle.timer_flavor() {
468 TimerFlavor::Traditional => {
469 Timer::Traditional(time::TimerEntry::new())
470 }
471 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
472 TimerFlavor::Alternative => {
473 Timer::Alternative(time_alt::Timer::new(handle, deadline))
474 }
475 }
476 }
477
478 pub(crate) fn init(self: Pin<&mut Self>, handle: &scheduler::Handle, deadline: u64) {
479 // Safety: we never move the inner entries.
480 let this = unsafe { self.get_unchecked_mut() };
481 match this {
482 // Safety: we never move the inner entries.
483 Timer::Traditional(entry) => unsafe {
484 Pin::new_unchecked(entry).init(handle, deadline);
485 }
486 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
487 Timer::Alternative(_) => {},
488 }
489 }
490
491 pub(crate) fn is_elapsed(&self) -> bool {
492 match self {
493 Timer::Traditional(entry) => entry.is_elapsed(),
494 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
495 Timer::Alternative(entry) => entry.is_elapsed(),
496 }
497 }
498
499 pub(crate) fn cancel(self: Pin<&mut Self>, handle: &scheduler::Handle) {
500 // Safety: we never move the inner entries.
501 let this = unsafe { self.get_unchecked_mut() };
502 match this {
503 // Safety: we never move the inner entries.
504 Timer::Traditional(entry) => unsafe {
505 Pin::new_unchecked(entry).cancel(handle);
506 }
507 // Safety: we never move the inner entries.
508 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
509 Timer::Alternative(entry) => unsafe {
510 Pin::new_unchecked(entry).cancel();
511 }
512 }
513 }
514
515 pub(crate) fn reset(self: Pin<&mut Self>, handle: &scheduler::Handle, deadline: u64) {
516 // Safety: we never move the inner entries.
517 let this = unsafe { self.get_unchecked_mut() };
518 match this {
519 // Safety: we never move the inner entries.
520 Timer::Traditional(entry) => unsafe {
521 Pin::new_unchecked(entry).reset(handle, deadline);
522 }
523 // Safety: we never move the inner entries.
524 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
525 Timer::Alternative(entry) => unsafe {
526 let mut entry = Pin::new_unchecked(entry);
527 entry.cancel();
528 entry.set(time_alt::Timer::new(handle, deadline));
529 },
530 }
531 }
532
533 pub(crate) fn poll_elapsed(
534 self: Pin<&mut Self>,
535 cx: &mut Context<'_>,
536 handle: &scheduler::Handle,
537 ) -> Poll<Result<(), crate::time::error::Error>> {
538 // Safety: we never move the inner entries.
539 let this = unsafe { self.get_unchecked_mut() };
540 match this {
541 // Safety: we never move the inner entries.
542 Timer::Traditional(entry) => unsafe {
543 Pin::new_unchecked(entry).poll_elapsed(cx, handle)
544 }
545 // Safety: we never move the inner entries.
546 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
547 Timer::Alternative(entry) => unsafe {
548 Pin::new_unchecked(entry).poll_elapsed(cx).map(Ok)
549 }
550 }
551 }
552 }
553}
554
555cfg_signal_internal_and_unix! {
556 pub(crate) mod signal;
557}
558
559cfg_rt! {
560 pub(crate) mod task;
561
562 mod config;
563 use config::Config;
564
565 mod blocking;
566 #[cfg_attr(target_os = "wasi", allow(unused_imports))]
567 pub(crate) use blocking::spawn_blocking;
568
569 cfg_trace! {
570 pub(crate) use blocking::Mandatory;
571 }
572
573 cfg_io_blocking! {
574 // Emscripten uses the inline shim in `crate::blocking`.
575 #[cfg_attr(target_os = "emscripten", allow(unused_imports))]
576 pub(crate) use blocking::spawn_mandatory_blocking;
577 }
578
579 mod builder;
580 pub use self::builder::Builder;
581 cfg_unstable! {
582 pub use self::builder::UnhandledPanic;
583 pub use crate::util::rand::RngSeed;
584 }
585
586 /// Returns the index of the current worker thread, if called from a
587 /// runtime worker thread.
588 ///
589 /// The returned value is a 0-based index matching the worker indices
590 /// used by [`RuntimeMetrics`] methods such as
591 /// [`worker_total_busy_duration`](RuntimeMetrics::worker_total_busy_duration).
592 ///
593 /// Returns `None` when called from outside a runtime worker thread
594 /// (for example, from a blocking thread or a non-Tokio thread). On the
595 /// multi-thread runtime, the thread that calls [`Runtime::block_on`] is
596 /// not a worker thread, so this also returns `None` there.
597 ///
598 /// For the current-thread runtime, this returns `Some(0)` when called from
599 /// the thread that currently owns the runtime driver. If multiple threads
600 /// call [`Runtime::block_on`] concurrently, calls on threads that do not
601 /// own the driver return `None`. A [`LocalRuntime`] can only be driven from
602 /// its owning thread, so calls inside `block_on` always return `Some(0)`.
603 ///
604 /// Note that the result may change across `.await` points, as the
605 /// task may be moved to a different worker thread by the scheduler.
606 ///
607 /// # Examples
608 ///
609 /// ```
610 /// # #[cfg(not(target_family = "wasm"))]
611 /// # {
612 /// #[tokio::main(flavor = "multi_thread", worker_threads = 4)]
613 /// async fn main() {
614 /// let index = tokio::spawn(async {
615 /// tokio::runtime::worker_index()
616 /// }).await.unwrap();
617 /// println!("Task ran on worker {:?}", index);
618 /// }
619 /// # }
620 /// ```
621 pub fn worker_index() -> Option<usize> {
622 context::worker_index()
623 }
624
625 cfg_taskdump! {
626 pub mod dump;
627 pub use dump::Dump;
628 }
629
630 mod task_hooks;
631 pub(crate) use task_hooks::{TaskHooks, TaskCallback};
632 cfg_unstable! {
633 pub use task_hooks::TaskMeta;
634 }
635 #[cfg(not(tokio_unstable))]
636 pub(crate) use task_hooks::TaskMeta;
637
638 mod handle;
639 pub use handle::{EnterGuard, Handle, TryCurrentError};
640
641 mod runtime;
642 pub use runtime::{Runtime, RuntimeFlavor, is_rt_shutdown_err};
643
644 mod local_runtime;
645 pub use local_runtime::{LocalRuntime, LocalOptions};
646
647 mod id;
648 pub use id::Id;
649
650
651 /// Boundary value to prevent stack overflow caused by a large-sized
652 /// Future being placed in the stack.
653 pub(crate) const BOX_FUTURE_THRESHOLD: usize = if cfg!(debug_assertions) {
654 2048
655 } else {
656 16384
657 };
658
659 /// Decides whether a future or closure of type `T` is boxed before it is
660 /// turned into a task, based on [`BOX_FUTURE_THRESHOLD`].
661 ///
662 /// The decision is an associated constant rather than a runtime
663 /// comparison of `std::mem::size_of::<T>()` so that only the taken branch
664 /// is instantiated. With a runtime `if`, both branches are instantiated
665 /// for every `T` (one task harness for `T`, one for `Pin<Box<T>>`),
666 /// doubling the generated code for every spawned future in a crate. A
667 /// branch on a constant that is known once `T` is known is pruned by the
668 /// monomorphization collector, so only the harness that is actually used
669 /// is generated.
670 pub(crate) struct AutoBox<T>(std::marker::PhantomData<T>);
671
672 impl<T> AutoBox<T> {
673 /// `true` if a value of type `T` is larger than [`BOX_FUTURE_THRESHOLD`].
674 pub(crate) const SHOULD_BOX: bool = std::mem::size_of::<T>() > BOX_FUTURE_THRESHOLD;
675 }
676
677 mod thread_id;
678 pub(crate) use thread_id::ThreadId;
679
680 pub(crate) mod metrics;
681 pub use metrics::RuntimeMetrics;
682
683 cfg_unstable_metrics! {
684 pub use metrics::{HistogramScale, HistogramConfiguration, LogHistogram, LogHistogramBuilder, InvalidHistogramConfiguration} ;
685
686 cfg_net! {
687 pub(crate) use metrics::IoDriverMetrics;
688 }
689 }
690
691 pub(crate) use metrics::{MetricsBatch, SchedulerMetrics, WorkerMetrics, HistogramBuilder};
692
693 /// After thread starts / before thread stops
694 type Callback = std::sync::Arc<dyn Fn() + Send + Sync>;
695}