Skip to main content

tokio/runtime/
builder.rs

1#![cfg_attr(loom, allow(unused_imports))]
2
3use crate::runtime::handle::Handle;
4use crate::runtime::{
5    blocking, driver, Callback, HistogramBuilder, Runtime, TaskCallback, TimerFlavor,
6};
7#[cfg(tokio_unstable)]
8use crate::runtime::{metrics::HistogramConfiguration, TaskMeta};
9
10use crate::runtime::{LocalOptions, LocalRuntime};
11use crate::util::rand::{RngSeed, RngSeedGenerator};
12
13use crate::runtime::blocking::BlockingPool;
14use crate::runtime::scheduler::CurrentThread;
15use std::fmt;
16use std::io;
17use std::thread::ThreadId;
18use std::time::Duration;
19
20/// Builds Tokio Runtime with custom configuration values.
21///
22/// Methods can be chained in order to set the configuration values. The
23/// Runtime is constructed by calling [`build`].
24///
25/// New instances of `Builder` are obtained via [`Builder::new_multi_thread`]
26/// or [`Builder::new_current_thread`].
27///
28/// See function level documentation for details on the various configuration
29/// settings.
30///
31/// [`build`]: method@Self::build
32/// [`Builder::new_multi_thread`]: method@Self::new_multi_thread
33/// [`Builder::new_current_thread`]: method@Self::new_current_thread
34///
35/// # Examples
36///
37/// ```
38/// # #[cfg(not(target_family = "wasm"))]
39/// # {
40/// use tokio::runtime::Builder;
41///
42/// fn main() {
43///     // build runtime
44///     let runtime = Builder::new_multi_thread()
45///         .worker_threads(4)
46///         .thread_name("my-custom-name")
47///         .thread_stack_size(3 * 1024 * 1024)
48///         .build()
49///         .unwrap();
50///
51///     // use runtime ...
52/// }
53/// # }
54/// ```
55pub struct Builder {
56    /// Runtime type
57    kind: Kind,
58
59    /// Name of the runtime.
60    name: Option<String>,
61
62    /// Whether or not to enable the I/O driver
63    enable_io: bool,
64    nevents: usize,
65    nevents_busy: Option<usize>,
66
67    /// Whether or not to enable the time driver
68    enable_time: bool,
69
70    /// Whether or not the clock should start paused.
71    start_paused: bool,
72
73    /// The number of worker threads, used by Runtime.
74    ///
75    /// Only used when not using the current-thread executor.
76    worker_threads: Option<usize>,
77
78    /// Cap on thread usage.
79    max_blocking_threads: usize,
80
81    /// Name fn used for threads spawned by the runtime.
82    pub(super) thread_name: ThreadNameFn,
83
84    /// Stack size used for threads spawned by the runtime.
85    pub(super) thread_stack_size: Option<usize>,
86
87    /// Callback to run after each thread starts.
88    pub(super) after_start: Option<Callback>,
89
90    /// To run before each worker thread stops
91    pub(super) before_stop: Option<Callback>,
92
93    /// To run before each worker thread is parked.
94    pub(super) before_park: Option<Callback>,
95
96    /// To run after each thread is unparked.
97    pub(super) after_unpark: Option<Callback>,
98
99    /// To run before each task is spawned.
100    pub(super) before_spawn: Option<TaskCallback>,
101
102    /// To run before each poll
103    #[cfg(tokio_unstable)]
104    pub(super) before_poll: Option<TaskCallback>,
105
106    /// To run after each poll
107    #[cfg(tokio_unstable)]
108    pub(super) after_poll: Option<TaskCallback>,
109
110    /// To run after each task is terminated.
111    pub(super) after_termination: Option<TaskCallback>,
112
113    /// Customizable keep alive timeout for `BlockingPool`
114    pub(super) keep_alive: Option<Duration>,
115
116    /// How many ticks before pulling a task from the global/remote queue?
117    ///
118    /// When `None`, the value is unspecified and behavior details are left to
119    /// the scheduler. Each scheduler flavor could choose to either pick its own
120    /// default value or use some other strategy to decide when to poll from the
121    /// global queue. For example, the multi-threaded scheduler uses a
122    /// self-tuning strategy based on mean task poll times.
123    pub(super) global_queue_interval: Option<u32>,
124
125    /// How many ticks before yielding to the driver for timer and I/O events?
126    pub(super) event_interval: u32,
127
128    /// When true, the multi-threade scheduler LIFO slot should not be used.
129    ///
130    /// This option should only be exposed as unstable.
131    pub(super) disable_lifo_slot: bool,
132
133    /// Specify a random number generator seed to provide deterministic results
134    pub(super) seed_generator: RngSeedGenerator,
135
136    /// When true, enables task poll count histogram instrumentation.
137    pub(super) metrics_poll_count_histogram_enable: bool,
138
139    /// Configures the task poll count histogram
140    pub(super) metrics_poll_count_histogram: HistogramBuilder,
141
142    /// When true, enables task schedule latency instrumentation.
143    pub(super) track_task_schedule_latency: bool,
144
145    /// When true, enables the task schedule latency histogram.
146    pub(super) metrics_schedule_latency_histogram_enabled: bool,
147
148    /// Configures the task schedule latency histogram.
149    pub(super) metrics_schedule_latency_histogram: HistogramBuilder,
150
151    #[cfg(tokio_unstable)]
152    pub(super) unhandled_panic: UnhandledPanic,
153
154    timer_flavor: TimerFlavor,
155
156    /// Whether or not to enable eager hand-off for the I/O and time drivers (in
157    /// `tokio_unstable`).
158    enable_eager_driver_handoff: bool,
159
160    /// When true, the blocking pool uses the sharded queue implementation.
161    pub(super) sharded_blocking_queue: bool,
162}
163
164cfg_unstable! {
165    /// How the runtime should respond to unhandled panics.
166    ///
167    /// Instances of `UnhandledPanic` are passed to `Builder::unhandled_panic`
168    /// to configure the runtime behavior when a spawned task panics.
169    ///
170    /// See [`Builder::unhandled_panic`] for more details.
171    #[derive(Debug, Clone)]
172    #[non_exhaustive]
173    pub enum UnhandledPanic {
174        /// The runtime should ignore panics on spawned tasks.
175        ///
176        /// The panic is forwarded to the task's [`JoinHandle`] and all spawned
177        /// tasks continue running normally.
178        ///
179        /// This is the default behavior.
180        ///
181        /// # Examples
182        ///
183        /// ```
184        /// # #[cfg(not(target_family = "wasm"))]
185        /// # {
186        /// use tokio::runtime::{self, UnhandledPanic};
187        ///
188        /// # pub fn main() {
189        /// let rt = runtime::Builder::new_current_thread()
190        ///     .unhandled_panic(UnhandledPanic::Ignore)
191        ///     .build()
192        ///     .unwrap();
193        ///
194        /// let task1 = rt.spawn(async { panic!("boom"); });
195        /// let task2 = rt.spawn(async {
196        ///     // This task completes normally
197        ///     "done"
198        /// });
199        ///
200        /// rt.block_on(async {
201        ///     // The panic on the first task is forwarded to the `JoinHandle`
202        ///     assert!(task1.await.is_err());
203        ///
204        ///     // The second task completes normally
205        ///     assert!(task2.await.is_ok());
206        /// })
207        /// # }
208        /// # }
209        /// ```
210        ///
211        /// [`JoinHandle`]: struct@crate::task::JoinHandle
212        Ignore,
213
214        /// The runtime should immediately shutdown if a spawned task panics.
215        ///
216        /// The runtime will immediately shutdown even if the panicked task's
217        /// [`JoinHandle`] is still available. All further spawned tasks will be
218        /// immediately dropped and call to [`Runtime::block_on`] will panic.
219        ///
220        /// # Examples
221        ///
222        /// ```should_panic
223        /// use tokio::runtime::{self, UnhandledPanic};
224        ///
225        /// # pub fn main() {
226        /// let rt = runtime::Builder::new_current_thread()
227        ///     .unhandled_panic(UnhandledPanic::ShutdownRuntime)
228        ///     .build()
229        ///     .unwrap();
230        ///
231        /// rt.spawn(async { panic!("boom"); });
232        /// rt.spawn(async {
233        ///     // This task never completes.
234        /// });
235        ///
236        /// rt.block_on(async {
237        ///     // Do some work
238        /// # loop { tokio::task::yield_now().await; }
239        /// })
240        /// # }
241        /// ```
242        ///
243        /// [`JoinHandle`]: struct@crate::task::JoinHandle
244        ShutdownRuntime,
245    }
246}
247
248pub(crate) type ThreadNameFn = std::sync::Arc<dyn Fn() -> String + Send + Sync + 'static>;
249
250/// The default for the `sharded_blocking_queue` option: enabled iff the
251/// `TOKIO_UNSTABLE_SHARDED_BLOCKING_QUEUE` environment variable is set to a
252/// value other than `0`.
253fn sharded_blocking_queue_default() -> bool {
254    match std::env::var_os("TOKIO_UNSTABLE_SHARDED_BLOCKING_QUEUE") {
255        Some(value) => !value.is_empty() && value != "0",
256        None => false,
257    }
258}
259
260#[derive(Clone, Copy)]
261pub(crate) enum Kind {
262    CurrentThread,
263    #[cfg(feature = "rt-multi-thread")]
264    MultiThread,
265}
266
267impl Builder {
268    /// Returns a new builder with the current thread scheduler selected.
269    ///
270    /// Configuration methods can be chained on the return value.
271    ///
272    /// To spawn non-`Send` tasks on the resulting runtime, combine it with a
273    /// [`LocalSet`], or call [`build_local`] to create a [`LocalRuntime`].
274    ///
275    /// [`LocalSet`]: crate::task::LocalSet
276    /// [`LocalRuntime`]: crate::runtime::LocalRuntime
277    /// [`build_local`]: crate::runtime::Builder::build_local
278    pub fn new_current_thread() -> Builder {
279        #[cfg(loom)]
280        const EVENT_INTERVAL: u32 = 4;
281        // The number `61` is fairly arbitrary. I believe this value was copied from golang.
282        #[cfg(not(loom))]
283        const EVENT_INTERVAL: u32 = 61;
284
285        Builder::new(Kind::CurrentThread, EVENT_INTERVAL)
286    }
287
288    /// Returns a new builder with the multi thread scheduler selected.
289    ///
290    /// Configuration methods can be chained on the return value.
291    #[cfg(feature = "rt-multi-thread")]
292    #[cfg_attr(docsrs, doc(cfg(feature = "rt-multi-thread")))]
293    pub fn new_multi_thread() -> Builder {
294        // The number `61` is fairly arbitrary. I believe this value was copied from golang.
295        Builder::new(Kind::MultiThread, 61)
296    }
297
298    /// Returns a new runtime builder initialized with default configuration
299    /// values.
300    ///
301    /// Configuration methods can be chained on the return value.
302    pub(crate) fn new(kind: Kind, event_interval: u32) -> Builder {
303        Builder {
304            kind,
305
306            // Default runtime name
307            name: None,
308
309            // I/O defaults to "off"
310            enable_io: false,
311            nevents: 1024,
312            nevents_busy: None,
313
314            // Time defaults to "off"
315            enable_time: false,
316
317            // The clock starts not-paused
318            start_paused: false,
319
320            // Read from environment variable first in multi-threaded mode.
321            // Default to lazy auto-detection (one thread per CPU core)
322            worker_threads: None,
323
324            max_blocking_threads: 512,
325
326            // Default thread name
327            thread_name: std::sync::Arc::new(|| "tokio-rt-worker".into()),
328
329            // Do not set a stack size by default
330            thread_stack_size: None,
331
332            // No worker thread callbacks
333            after_start: None,
334            before_stop: None,
335            before_park: None,
336            after_unpark: None,
337
338            before_spawn: None,
339            after_termination: None,
340
341            #[cfg(tokio_unstable)]
342            before_poll: None,
343            #[cfg(tokio_unstable)]
344            after_poll: None,
345
346            keep_alive: None,
347
348            // Defaults for these values depend on the scheduler kind, so we get them
349            // as parameters.
350            global_queue_interval: None,
351            event_interval,
352
353            seed_generator: RngSeedGenerator::new(RngSeed::new()),
354
355            #[cfg(tokio_unstable)]
356            unhandled_panic: UnhandledPanic::Ignore,
357
358            metrics_poll_count_histogram_enable: false,
359
360            metrics_poll_count_histogram: HistogramBuilder::default(),
361
362            track_task_schedule_latency: false,
363
364            metrics_schedule_latency_histogram_enabled: false,
365
366            metrics_schedule_latency_histogram: HistogramBuilder::default(),
367
368            disable_lifo_slot: false,
369
370            timer_flavor: TimerFlavor::Traditional,
371
372            // Eager driver handoff is disabled by default.
373            enable_eager_driver_handoff: false,
374
375            sharded_blocking_queue: sharded_blocking_queue_default(),
376        }
377    }
378
379    /// Enables both I/O and time drivers.
380    ///
381    /// Doing this is a shorthand for calling `enable_io` and `enable_time`
382    /// individually. If additional components are added to Tokio in the future,
383    /// `enable_all` will include these future components.
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// # #[cfg(not(target_family = "wasm"))]
389    /// # {
390    /// use tokio::runtime;
391    ///
392    /// let rt = runtime::Builder::new_multi_thread()
393    ///     .enable_all()
394    ///     .build()
395    ///     .unwrap();
396    /// # }
397    /// ```
398    pub fn enable_all(&mut self) -> &mut Self {
399        #[cfg(any(
400            feature = "net",
401            all(unix, feature = "process"),
402            all(unix, feature = "signal")
403        ))]
404        self.enable_io();
405
406        #[cfg(all(
407            tokio_unstable,
408            feature = "io-uring",
409            feature = "rt",
410            feature = "fs",
411            target_os = "linux",
412        ))]
413        self.enable_io_uring();
414
415        #[cfg(feature = "time")]
416        self.enable_time();
417
418        self
419    }
420
421    /// Enables the alternative timer implementation, which is disabled by default.
422    ///
423    /// The alternative timer implementation is an unstable feature that may
424    /// provide better performance on multi-threaded runtimes with a large number
425    /// of worker threads.
426    ///
427    /// This option only applies to multi-threaded runtimes. Attempting to use
428    /// this option with any other runtime type will have no effect.
429    ///
430    /// [Click here to share your experience with the alternative timer](https://github.com/tokio-rs/tokio/issues/7745)
431    ///
432    /// # Examples
433    ///
434    /// ```
435    /// # #[cfg(not(target_family = "wasm"))]
436    /// # {
437    /// use tokio::runtime;
438    ///
439    /// let rt = runtime::Builder::new_multi_thread()
440    ///   .enable_alt_timer()
441    ///   .build()
442    ///   .unwrap();
443    /// # }
444    /// ```
445    #[cfg(all(tokio_unstable, feature = "time", feature = "rt-multi-thread"))]
446    #[cfg_attr(
447        docsrs,
448        doc(cfg(all(tokio_unstable, feature = "time", feature = "rt-multi-thread")))
449    )]
450    pub fn enable_alt_timer(&mut self) -> &mut Self {
451        self.enable_time();
452        self.timer_flavor = TimerFlavor::Alternative;
453        self
454    }
455
456    /// Enable eager hand-off of the I/O and time drivers for multi-threaded
457    /// runtimes, which is disabled by default.
458    ///
459    /// When this option is enabled, a worker thread which has parked on the I/O
460    /// or time driver will notify another worker thread once it is preparing to
461    /// begin polling a task from the run queue, so that the notified worker can
462    /// begin polling the I/O or time driver. This can reduce the latency with
463    /// which I/O and timer notifications are processed, especially when some
464    /// tasks have polls that take a long time to complete. In addition, it can
465    /// reduce the risk of a deadlock which may occur when a task blocks the
466    /// worker thread which is holding the I/O or time driver until some other
467    /// task, which is waiting for a notification from *that* driver, unblocks
468    /// it.
469    ///
470    /// This option is disabled by default, as enabling it may potentially
471    /// increase contention due to extra synchronization in cross-driver
472    /// wakeups.
473    ///
474    /// This option only applies to multi-threaded runtimes. Attempting to use
475    /// this option with any other runtime type will have no effect.
476    ///
477    /// **Note**: This is an [unstable API][unstable]. Eager driver hand-off is
478    /// an experimental feature whose behavior may be removed or changed in 1.x
479    /// releases. See [the documentation on unstable features][unstable] for
480    /// details.
481    ///
482    /// [unstable]: crate#unstable-features
483    #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
484    #[cfg_attr(docsrs, doc(cfg(all(tokio_unstable, feature = "rt-multi-thread"))))]
485    pub fn enable_eager_driver_handoff(&mut self) -> &mut Self {
486        self.enable_eager_driver_handoff = true;
487        self
488    }
489
490    /// Enables the sharded `spawn_blocking` queue, which is disabled by
491    /// default.
492    ///
493    /// By default, the blocking pool's task queue is protected by a single
494    /// mutex, which can become a point of contention when many threads spawn
495    /// blocking tasks concurrently. When this option is enabled, tasks are
496    /// instead distributed across several independently-locked queue shards.
497    ///
498    /// The sharded queue can also be enabled by setting the
499    /// `TOKIO_UNSTABLE_SHARDED_BLOCKING_QUEUE` environment variable to any
500    /// value other than `0`.
501    ///
502    /// [Click here to share your experience with the sharded queue](https://github.com/tokio-rs/tokio/issues/8067)
503    ///
504    /// **Note**: This is an [unstable API][unstable]. The sharded
505    /// `spawn_blocking` queue is an experimental feature that may be removed
506    /// or become the default behavior in 1.x releases. See
507    /// [the documentation on unstable features][unstable] for details.
508    ///
509    /// # Examples
510    ///
511    /// ```
512    /// # #[cfg(not(target_family = "wasm"))]
513    /// # {
514    /// use tokio::runtime;
515    ///
516    /// let rt = runtime::Builder::new_multi_thread()
517    ///   .enable_sharded_blocking_queue()
518    ///   .build()
519    ///   .unwrap();
520    /// # }
521    /// ```
522    ///
523    /// [unstable]: crate#unstable-features
524    #[cfg(tokio_unstable)]
525    #[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
526    pub fn enable_sharded_blocking_queue(&mut self) -> &mut Self {
527        self.sharded_blocking_queue = true;
528        self
529    }
530
531    /// Sets the number of worker threads the `Runtime` will use.
532    ///
533    /// This can be any number above 0 though it is advised to keep this value
534    /// on the smaller side.
535    ///
536    /// This will override the value read from environment variable `TOKIO_WORKER_THREADS`.
537    ///
538    /// # Default
539    ///
540    /// The default value is the number of cores available to the system.
541    ///
542    /// Currently, this is determined by calling
543    /// [`std::thread::available_parallelism`]. Please see its documentation
544    /// for caveats.
545    ///
546    /// When using the `current_thread` runtime this method has no effect.
547    ///
548    /// # Examples
549    ///
550    /// ## Multi threaded runtime with 4 threads
551    ///
552    /// ```
553    /// # #[cfg(not(target_family = "wasm"))]
554    /// # {
555    /// use tokio::runtime;
556    ///
557    /// // This will spawn a work-stealing runtime with 4 worker threads.
558    /// let rt = runtime::Builder::new_multi_thread()
559    ///     .worker_threads(4)
560    ///     .build()
561    ///     .unwrap();
562    ///
563    /// rt.spawn(async move {});
564    /// # }
565    /// ```
566    ///
567    /// ## Current thread runtime (will only run on the current thread via `Runtime::block_on`)
568    ///
569    /// ```
570    /// use tokio::runtime;
571    ///
572    /// // Create a runtime that _must_ be driven from a call
573    /// // to `Runtime::block_on`.
574    /// let rt = runtime::Builder::new_current_thread()
575    ///     .build()
576    ///     .unwrap();
577    ///
578    /// // This will run the runtime and future on the current thread
579    /// rt.block_on(async move {});
580    /// ```
581    ///
582    /// # Panics
583    ///
584    /// This will panic if `val` is not larger than `0`.
585    #[track_caller]
586    pub fn worker_threads(&mut self, val: usize) -> &mut Self {
587        assert!(val > 0, "Worker threads cannot be set to 0");
588        self.worker_threads = Some(val);
589        self
590    }
591
592    /// Specifies the limit for additional threads spawned by the Runtime.
593    ///
594    /// These threads are used for blocking operations like tasks spawned
595    /// through [`spawn_blocking`], this includes but is not limited to:
596    /// - [`fs`] operations
597    /// - dns resolution through [`ToSocketAddrs`]
598    /// - writing to [`Stdout`] or [`Stderr`]
599    /// - reading from [`Stdin`]
600    ///
601    /// Unlike the [`worker_threads`], they are not always active and will exit
602    /// if left idle for too long. You can change this timeout duration with [`thread_keep_alive`].
603    ///
604    /// It's recommended to not set this limit too low in order to avoid hanging on operations
605    /// requiring [`spawn_blocking`].
606    ///
607    /// The default value is 512.
608    ///
609    /// # Queue Behavior
610    ///
611    /// When a blocking task is submitted, it will be inserted into a queue. If available, one of
612    /// the idle threads will be notified to run the task. Otherwise, if the threshold set by this
613    /// method has not been reached, a new thread will be spawned. If no idle thread is available
614    /// and no more threads are allowed to be spawned, the task will remain in the queue until one
615    /// of the busy threads pick it up. Note that since the queue does not apply any backpressure,
616    /// it could potentially grow unbounded.
617    ///
618    /// # Panics
619    ///
620    /// This will panic if `val` is not larger than `0`.
621    ///
622    /// # Upgrading from 0.x
623    ///
624    /// In old versions `max_threads` limited both blocking and worker threads, but the
625    /// current `max_blocking_threads` does not include async worker threads in the count.
626    ///
627    /// [`spawn_blocking`]: fn@crate::task::spawn_blocking
628    /// [`fs`]: mod@crate::fs
629    /// [`ToSocketAddrs`]: trait@crate::net::ToSocketAddrs
630    /// [`Stdout`]: struct@crate::io::Stdout
631    /// [`Stdin`]: struct@crate::io::Stdin
632    /// [`Stderr`]: struct@crate::io::Stderr
633    /// [`worker_threads`]: Self::worker_threads
634    /// [`thread_keep_alive`]: Self::thread_keep_alive
635    #[track_caller]
636    #[cfg_attr(docsrs, doc(alias = "max_threads"))]
637    pub fn max_blocking_threads(&mut self, val: usize) -> &mut Self {
638        assert!(val > 0, "Max blocking threads cannot be set to 0");
639        self.max_blocking_threads = val;
640        self
641    }
642
643    /// Sets name of threads spawned by the `Runtime`'s thread pool.
644    ///
645    /// The default name is "tokio-rt-worker".
646    ///
647    /// # Examples
648    ///
649    /// ```
650    /// # #[cfg(not(target_family = "wasm"))]
651    /// # {
652    /// # use tokio::runtime;
653    ///
654    /// # pub fn main() {
655    /// let rt = runtime::Builder::new_multi_thread()
656    ///     .thread_name("my-pool")
657    ///     .build();
658    /// # }
659    /// # }
660    /// ```
661    pub fn thread_name(&mut self, val: impl Into<String>) -> &mut Self {
662        let val = val.into();
663        self.thread_name = std::sync::Arc::new(move || val.clone());
664        self
665    }
666
667    /// Sets the name of the runtime.
668    ///
669    /// # Examples
670    ///
671    /// ```
672    /// # #[cfg(not(target_family = "wasm"))]
673    /// # {
674    /// # use tokio::runtime;
675    ///
676    /// # pub fn main() {
677    /// let rt = runtime::Builder::new_multi_thread()
678    ///     .name("my-runtime")
679    ///     .build();
680    /// # }
681    /// # }
682    /// ```
683    /// # Panics
684    ///
685    /// This function will panic if an empty value is passed as an argument.
686    ///
687    #[track_caller]
688    pub fn name(&mut self, val: impl Into<String>) -> &mut Self {
689        let val = val.into();
690        assert!(!val.trim().is_empty(), "runtime name shouldn't be empty");
691        self.name = Some(val);
692        self
693    }
694
695    /// Sets a function used to generate the name of threads spawned by the `Runtime`'s thread pool.
696    ///
697    /// The default name fn is `|| "tokio-rt-worker".into()`.
698    ///
699    /// # Examples
700    ///
701    /// ```
702    /// # #[cfg(not(target_family = "wasm"))]
703    /// # {
704    /// # use tokio::runtime;
705    /// # use std::sync::atomic::{AtomicUsize, Ordering};
706    /// # pub fn main() {
707    /// let rt = runtime::Builder::new_multi_thread()
708    ///     .thread_name_fn(|| {
709    ///        static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
710    ///        let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
711    ///        format!("my-pool-{}", id)
712    ///     })
713    ///     .build();
714    /// # }
715    /// # }
716    /// ```
717    pub fn thread_name_fn<F>(&mut self, f: F) -> &mut Self
718    where
719        F: Fn() -> String + Send + Sync + 'static,
720    {
721        self.thread_name = std::sync::Arc::new(f);
722        self
723    }
724
725    /// Sets the stack size (in bytes) for worker threads.
726    ///
727    /// The actual stack size may be greater than this value if the platform
728    /// specifies minimal stack size.
729    ///
730    /// The default stack size for spawned threads is 2 MiB, though this
731    /// particular stack size is subject to change in the future.
732    ///
733    /// # Examples
734    ///
735    /// ```
736    /// # #[cfg(not(target_family = "wasm"))]
737    /// # {
738    /// # use tokio::runtime;
739    ///
740    /// # pub fn main() {
741    /// let rt = runtime::Builder::new_multi_thread()
742    ///     .thread_stack_size(32 * 1024)
743    ///     .build();
744    /// # }
745    /// # }
746    /// ```
747    pub fn thread_stack_size(&mut self, val: usize) -> &mut Self {
748        self.thread_stack_size = Some(val);
749        self
750    }
751
752    /// Executes function `f` after each thread is started but before it starts
753    /// doing work.
754    ///
755    /// This is intended for bookkeeping and monitoring use cases.
756    ///
757    /// # Examples
758    ///
759    /// ```
760    /// # #[cfg(not(target_family = "wasm"))]
761    /// # {
762    /// # use tokio::runtime;
763    /// # pub fn main() {
764    /// let runtime = runtime::Builder::new_multi_thread()
765    ///     .on_thread_start(|| {
766    ///         println!("thread started");
767    ///     })
768    ///     .build();
769    /// # }
770    /// # }
771    /// ```
772    #[cfg(not(loom))]
773    pub fn on_thread_start<F>(&mut self, f: F) -> &mut Self
774    where
775        F: Fn() + Send + Sync + 'static,
776    {
777        self.after_start = Some(std::sync::Arc::new(f));
778        self
779    }
780
781    /// Executes function `f` before each thread stops.
782    ///
783    /// This is intended for bookkeeping and monitoring use cases.
784    ///
785    /// # Examples
786    ///
787    /// ```
788    /// # #[cfg(not(target_family = "wasm"))]
789    /// # {
790    /// # use tokio::runtime;
791    /// # pub fn main() {
792    /// let runtime = runtime::Builder::new_multi_thread()
793    ///     .on_thread_stop(|| {
794    ///         println!("thread stopping");
795    ///     })
796    ///     .build();
797    /// # }
798    /// # }
799    /// ```
800    #[cfg(not(loom))]
801    pub fn on_thread_stop<F>(&mut self, f: F) -> &mut Self
802    where
803        F: Fn() + Send + Sync + 'static,
804    {
805        self.before_stop = Some(std::sync::Arc::new(f));
806        self
807    }
808
809    /// Executes function `f` just before a thread is parked (goes idle).
810    /// `f` is called within the Tokio context, so functions like [`tokio::spawn`](crate::spawn)
811    /// can be called, and may result in this thread being unparked immediately.
812    ///
813    /// This can be used to start work only when the executor is idle, or for bookkeeping
814    /// and monitoring purposes.
815    ///
816    /// Note: There can only be one park callback for a runtime; calling this function
817    /// more than once replaces the last callback defined, rather than adding to it.
818    ///
819    /// # Examples
820    ///
821    /// ## Multithreaded executor
822    /// ```
823    /// # #[cfg(not(target_family = "wasm"))]
824    /// # {
825    /// # use std::sync::Arc;
826    /// # use std::sync::atomic::{AtomicBool, Ordering};
827    /// # use tokio::runtime;
828    /// # use tokio::sync::Barrier;
829    /// # pub fn main() {
830    /// let once = AtomicBool::new(true);
831    /// let barrier = Arc::new(Barrier::new(2));
832    ///
833    /// let runtime = runtime::Builder::new_multi_thread()
834    ///     .worker_threads(1)
835    ///     .on_thread_park({
836    ///         let barrier = barrier.clone();
837    ///         move || {
838    ///             let barrier = barrier.clone();
839    ///             if once.swap(false, Ordering::Relaxed) {
840    ///                 tokio::spawn(async move { barrier.wait().await; });
841    ///            }
842    ///         }
843    ///     })
844    ///     .build()
845    ///     .unwrap();
846    ///
847    /// runtime.block_on(async {
848    ///    barrier.wait().await;
849    /// })
850    /// # }
851    /// # }
852    /// ```
853    /// ## Current thread executor
854    /// ```
855    /// # use std::sync::Arc;
856    /// # use std::sync::atomic::{AtomicBool, Ordering};
857    /// # use tokio::runtime;
858    /// # use tokio::sync::Barrier;
859    /// # pub fn main() {
860    /// let once = AtomicBool::new(true);
861    /// let barrier = Arc::new(Barrier::new(2));
862    ///
863    /// let runtime = runtime::Builder::new_current_thread()
864    ///     .on_thread_park({
865    ///         let barrier = barrier.clone();
866    ///         move || {
867    ///             let barrier = barrier.clone();
868    ///             if once.swap(false, Ordering::Relaxed) {
869    ///                 tokio::spawn(async move { barrier.wait().await; });
870    ///            }
871    ///         }
872    ///     })
873    ///     .build()
874    ///     .unwrap();
875    ///
876    /// runtime.block_on(async {
877    ///    barrier.wait().await;
878    /// })
879    /// # }
880    /// ```
881    #[cfg(not(loom))]
882    pub fn on_thread_park<F>(&mut self, f: F) -> &mut Self
883    where
884        F: Fn() + Send + Sync + 'static,
885    {
886        self.before_park = Some(std::sync::Arc::new(f));
887        self
888    }
889
890    /// Executes function `f` just after a thread unparks (starts executing tasks).
891    ///
892    /// This is intended for bookkeeping and monitoring use cases; note that work
893    /// in this callback will increase latencies when the application has allowed one or
894    /// more runtime threads to go idle.
895    ///
896    /// Note: There can only be one unpark callback for a runtime; calling this function
897    /// more than once replaces the last callback defined, rather than adding to it.
898    ///
899    /// # Examples
900    ///
901    /// ```
902    /// # #[cfg(not(target_family = "wasm"))]
903    /// # {
904    /// # use tokio::runtime;
905    /// # pub fn main() {
906    /// let runtime = runtime::Builder::new_multi_thread()
907    ///     .on_thread_unpark(|| {
908    ///         println!("thread unparking");
909    ///     })
910    ///     .build();
911    ///
912    /// runtime.unwrap().block_on(async {
913    ///    tokio::task::yield_now().await;
914    ///    println!("Hello from Tokio!");
915    /// })
916    /// # }
917    /// # }
918    /// ```
919    #[cfg(not(loom))]
920    pub fn on_thread_unpark<F>(&mut self, f: F) -> &mut Self
921    where
922        F: Fn() + Send + Sync + 'static,
923    {
924        self.after_unpark = Some(std::sync::Arc::new(f));
925        self
926    }
927
928    /// Executes function `f` just before a task is spawned.
929    ///
930    /// `f` is called within the Tokio context, so functions like
931    /// [`tokio::spawn`](crate::spawn) can be called, and may result in this callback being
932    /// invoked immediately.
933    ///
934    /// This can be used for bookkeeping or monitoring purposes.
935    ///
936    /// Note: There can only be one spawn callback for a runtime; calling this function more
937    /// than once replaces the last callback defined, rather than adding to it.
938    ///
939    /// This *does not* support [`LocalSet`](crate::task::LocalSet) at this time.
940    ///
941    /// **Note**: This is an [unstable API][unstable]. The public API of this type
942    /// may break in 1.x releases. See [the documentation on unstable
943    /// features][unstable] for details.
944    ///
945    /// [unstable]: crate#unstable-features
946    ///
947    /// # Examples
948    ///
949    /// ```
950    /// # use tokio::runtime;
951    /// # pub fn main() {
952    /// let runtime = runtime::Builder::new_current_thread()
953    ///     .on_task_spawn(|_| {
954    ///         println!("spawning task");
955    ///     })
956    ///     .build()
957    ///     .unwrap();
958    ///
959    /// runtime.block_on(async {
960    ///     tokio::task::spawn(std::future::ready(()));
961    ///
962    ///     for _ in 0..64 {
963    ///         tokio::task::yield_now().await;
964    ///     }
965    /// })
966    /// # }
967    /// ```
968    #[cfg(all(not(loom), tokio_unstable))]
969    #[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
970    pub fn on_task_spawn<F>(&mut self, f: F) -> &mut Self
971    where
972        F: Fn(&TaskMeta<'_>) + Send + Sync + 'static,
973    {
974        self.before_spawn = Some(std::sync::Arc::new(f));
975        self
976    }
977
978    /// Executes function `f` just before a task is polled
979    ///
980    /// `f` is called within the Tokio context, so functions like
981    /// [`tokio::spawn`](crate::spawn) can be called, and may result in this callback being
982    /// invoked immediately.
983    ///
984    /// When task schedule latency tracking is enabled, the latency is available
985    /// from `TaskMeta::schedule_latency`.
986    ///
987    /// **Note**: This is an [unstable API][unstable]. The public API of this type
988    /// may break in 1.x releases. See [the documentation on unstable
989    /// features][unstable] for details.
990    ///
991    /// [unstable]: crate#unstable-features
992    ///
993    /// # Examples
994    ///
995    /// ```
996    /// # #[cfg(not(target_family = "wasm"))]
997    /// # {
998    /// # use std::sync::{atomic::AtomicUsize, Arc};
999    /// # use tokio::task::yield_now;
1000    /// # pub fn main() {
1001    /// let poll_start_counter = Arc::new(AtomicUsize::new(0));
1002    /// let poll_start = poll_start_counter.clone();
1003    /// let rt = tokio::runtime::Builder::new_multi_thread()
1004    ///     .enable_all()
1005    ///     .on_before_task_poll(move |meta| {
1006    ///         println!("task {} is about to be polled", meta.id())
1007    ///     })
1008    ///     .build()
1009    ///     .unwrap();
1010    /// let task = rt.spawn(async {
1011    ///     yield_now().await;
1012    /// });
1013    /// let _ = rt.block_on(task);
1014    ///
1015    /// # }
1016    /// # }
1017    /// ```
1018    #[cfg(tokio_unstable)]
1019    #[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
1020    pub fn on_before_task_poll<F>(&mut self, f: F) -> &mut Self
1021    where
1022        F: Fn(&TaskMeta<'_>) + Send + Sync + 'static,
1023    {
1024        self.before_poll = Some(std::sync::Arc::new(f));
1025        self
1026    }
1027
1028    /// Executes function `f` just after a task is polled
1029    ///
1030    /// `f` is called within the Tokio context, so functions like
1031    /// [`tokio::spawn`](crate::spawn) can be called, and may result in this callback being
1032    /// invoked immediately.
1033    ///
1034    /// When task schedule latency tracking is enabled, the latency is available
1035    /// from `TaskMeta::schedule_latency`.
1036    ///
1037    /// **Note**: This is an [unstable API][unstable]. The public API of this type
1038    /// may break in 1.x releases. See [the documentation on unstable
1039    /// features][unstable] for details.
1040    ///
1041    /// [unstable]: crate#unstable-features
1042    ///
1043    /// # Examples
1044    ///
1045    /// ```
1046    /// # #[cfg(not(target_family = "wasm"))]
1047    /// # {
1048    /// # use std::sync::{atomic::AtomicUsize, Arc};
1049    /// # use tokio::task::yield_now;
1050    /// # pub fn main() {
1051    /// let poll_stop_counter = Arc::new(AtomicUsize::new(0));
1052    /// let poll_stop = poll_stop_counter.clone();
1053    /// let rt = tokio::runtime::Builder::new_multi_thread()
1054    ///     .enable_all()
1055    ///     .on_after_task_poll(move |meta| {
1056    ///         println!("task {} completed polling", meta.id());
1057    ///     })
1058    ///     .build()
1059    ///     .unwrap();
1060    /// let task = rt.spawn(async {
1061    ///     yield_now().await;
1062    /// });
1063    /// let _ = rt.block_on(task);
1064    ///
1065    /// # }
1066    /// # }
1067    /// ```
1068    #[cfg(tokio_unstable)]
1069    #[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
1070    pub fn on_after_task_poll<F>(&mut self, f: F) -> &mut Self
1071    where
1072        F: Fn(&TaskMeta<'_>) + Send + Sync + 'static,
1073    {
1074        self.after_poll = Some(std::sync::Arc::new(f));
1075        self
1076    }
1077
1078    /// Executes function `f` just after a task is terminated.
1079    ///
1080    /// `f` is called within the Tokio context, so functions like
1081    /// [`tokio::spawn`](crate::spawn) can be called.
1082    ///
1083    /// This can be used for bookkeeping or monitoring purposes.
1084    ///
1085    /// Note: There can only be one task termination callback for a runtime; calling this
1086    /// function more than once replaces the last callback defined, rather than adding to it.
1087    ///
1088    /// This *does not* support [`LocalSet`](crate::task::LocalSet) at this time.
1089    ///
1090    /// **Note**: This is an [unstable API][unstable]. The public API of this type
1091    /// may break in 1.x releases. See [the documentation on unstable
1092    /// features][unstable] for details.
1093    ///
1094    /// [unstable]: crate#unstable-features
1095    ///
1096    /// # Examples
1097    ///
1098    /// ```
1099    /// # use tokio::runtime;
1100    /// # pub fn main() {
1101    /// let runtime = runtime::Builder::new_current_thread()
1102    ///     .on_task_terminate(|_| {
1103    ///         println!("killing task");
1104    ///     })
1105    ///     .build()
1106    ///     .unwrap();
1107    ///
1108    /// runtime.block_on(async {
1109    ///     tokio::task::spawn(std::future::ready(()));
1110    ///
1111    ///     for _ in 0..64 {
1112    ///         tokio::task::yield_now().await;
1113    ///     }
1114    /// })
1115    /// # }
1116    /// ```
1117    #[cfg(all(not(loom), tokio_unstable))]
1118    #[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
1119    pub fn on_task_terminate<F>(&mut self, f: F) -> &mut Self
1120    where
1121        F: Fn(&TaskMeta<'_>) + Send + Sync + 'static,
1122    {
1123        self.after_termination = Some(std::sync::Arc::new(f));
1124        self
1125    }
1126
1127    /// Creates the configured `Runtime`.
1128    ///
1129    /// The returned `Runtime` instance is ready to spawn tasks.
1130    ///
1131    /// # Examples
1132    ///
1133    /// ```
1134    /// # #[cfg(not(target_family = "wasm"))]
1135    /// # {
1136    /// use tokio::runtime::Builder;
1137    ///
1138    /// let rt  = Builder::new_multi_thread().build().unwrap();
1139    ///
1140    /// rt.block_on(async {
1141    ///     println!("Hello from the Tokio runtime");
1142    /// });
1143    /// # }
1144    /// ```
1145    ///
1146    /// # Errors
1147    ///
1148    /// Returns an error if the I/O driver or other OS resources required by the
1149    /// runtime cannot be initialized.
1150    pub fn build(&mut self) -> io::Result<Runtime> {
1151        match &self.kind {
1152            Kind::CurrentThread => self.build_current_thread_runtime(),
1153            #[cfg(feature = "rt-multi-thread")]
1154            Kind::MultiThread => self.build_threaded_runtime(),
1155        }
1156    }
1157
1158    /// Creates the configured [`LocalRuntime`].
1159    ///
1160    /// The returned [`LocalRuntime`] instance is ready to spawn tasks.
1161    ///
1162    /// # Panics
1163    ///
1164    /// This will panic if the runtime is configured with [`new_multi_thread()`].
1165    ///
1166    /// [`new_multi_thread()`]: Builder::new_multi_thread
1167    ///
1168    /// # Examples
1169    ///
1170    /// ```
1171    /// use tokio::runtime::{Builder, LocalOptions};
1172    ///
1173    /// let rt = Builder::new_current_thread()
1174    ///     .build_local(LocalOptions::default())
1175    ///     .unwrap();
1176    ///
1177    /// rt.spawn_local(async {
1178    ///     println!("Hello from the Tokio runtime");
1179    /// });
1180    /// ```
1181    ///
1182    /// # Errors
1183    ///
1184    /// Returns an error if the I/O driver or other OS resources required by the
1185    /// runtime cannot be initialized.
1186    pub fn build_local(&mut self, _options: LocalOptions) -> io::Result<LocalRuntime> {
1187        match &self.kind {
1188            Kind::CurrentThread => self.build_current_thread_local_runtime(),
1189            #[cfg(feature = "rt-multi-thread")]
1190            Kind::MultiThread => panic!("multi_thread is not supported for LocalRuntime"),
1191        }
1192    }
1193
1194    fn get_cfg(&self) -> driver::Cfg {
1195        driver::Cfg {
1196            enable_pause_time: match self.kind {
1197                Kind::CurrentThread => true,
1198                #[cfg(feature = "rt-multi-thread")]
1199                Kind::MultiThread => false,
1200            },
1201            enable_io: self.enable_io,
1202            enable_time: self.enable_time,
1203            start_paused: self.start_paused,
1204            nevents: self.nevents,
1205            nevents_busy: self.nevents_busy,
1206            timer_flavor: self.timer_flavor,
1207        }
1208    }
1209
1210    /// Sets a custom timeout for a thread in the blocking pool.
1211    ///
1212    /// By default, the timeout for a thread is set to 10 seconds. This can
1213    /// be overridden using `.thread_keep_alive()`.
1214    ///
1215    /// # Example
1216    ///
1217    /// ```
1218    /// # #[cfg(not(target_family = "wasm"))]
1219    /// # {
1220    /// # use tokio::runtime;
1221    /// # use std::time::Duration;
1222    /// # pub fn main() {
1223    /// let rt = runtime::Builder::new_multi_thread()
1224    ///     .thread_keep_alive(Duration::from_millis(100))
1225    ///     .build();
1226    /// # }
1227    /// # }
1228    /// ```
1229    pub fn thread_keep_alive(&mut self, duration: Duration) -> &mut Self {
1230        self.keep_alive = Some(duration);
1231        self
1232    }
1233
1234    /// Sets the number of scheduler ticks after which the scheduler will poll the global
1235    /// task queue.
1236    ///
1237    /// A scheduler "tick" roughly corresponds to one `poll` invocation on a task.
1238    ///
1239    /// By default the global queue interval is 31 for the current-thread scheduler. Please see
1240    /// [the module documentation] for the default behavior of the multi-thread scheduler.
1241    ///
1242    /// Schedulers have a local queue of already-claimed tasks, and a global queue of incoming
1243    /// tasks. Setting the interval to a smaller value increases the fairness of the scheduler,
1244    /// at the cost of more synchronization overhead. That can be beneficial for prioritizing
1245    /// getting started on new work, especially if tasks frequently yield rather than complete
1246    /// or await on further I/O. Setting the interval to `1` will prioritize the global queue and
1247    /// tasks from the local queue will be executed only if the global queue is empty.
1248    /// Conversely, a higher value prioritizes existing work, and is a good choice when most
1249    /// tasks quickly complete polling.
1250    ///
1251    /// [the module documentation]: crate::runtime#multi-threaded-runtime-behavior-at-the-time-of-writing
1252    ///
1253    /// # Panics
1254    ///
1255    /// This function will panic if 0 is passed as an argument.
1256    ///
1257    /// # Examples
1258    ///
1259    /// ```
1260    /// # #[cfg(not(target_family = "wasm"))]
1261    /// # {
1262    /// # use tokio::runtime;
1263    /// # pub fn main() {
1264    /// let rt = runtime::Builder::new_multi_thread()
1265    ///     .global_queue_interval(31)
1266    ///     .build();
1267    /// # }
1268    /// # }
1269    /// ```
1270    #[track_caller]
1271    pub fn global_queue_interval(&mut self, val: u32) -> &mut Self {
1272        assert!(val > 0, "global_queue_interval must be greater than 0");
1273        self.global_queue_interval = Some(val);
1274        self
1275    }
1276
1277    /// Sets the number of scheduler ticks after which the scheduler will poll for
1278    /// external events (timers, I/O, and so on).
1279    ///
1280    /// A scheduler "tick" roughly corresponds to one `poll` invocation on a task.
1281    ///
1282    /// By default, the event interval is `61` for all scheduler types.
1283    ///
1284    /// Setting the event interval determines the effective "priority" of delivering
1285    /// these external events (which may wake up additional tasks), compared to
1286    /// executing tasks that are currently ready to run. A smaller value is useful
1287    /// when tasks frequently spend a long time in polling, or infrequently yield,
1288    /// which can result in overly long delays picking up I/O events. Conversely,
1289    /// picking up new events requires extra synchronization and syscall overhead,
1290    /// so if tasks generally complete their polling quickly, a higher event interval
1291    /// will minimize that overhead while still keeping the scheduler responsive to
1292    /// events.
1293    ///
1294    /// # Panics
1295    ///
1296    /// This function will panic if 0 is passed as an argument.
1297    ///
1298    /// # Examples
1299    ///
1300    /// ```
1301    /// # #[cfg(not(target_family = "wasm"))]
1302    /// # {
1303    /// # use tokio::runtime;
1304    /// # pub fn main() {
1305    /// let rt = runtime::Builder::new_multi_thread()
1306    ///     .event_interval(31)
1307    ///     .build();
1308    /// # }
1309    /// # }
1310    /// ```
1311    #[track_caller]
1312    pub fn event_interval(&mut self, val: u32) -> &mut Self {
1313        assert!(val > 0, "event_interval must be greater than 0");
1314        self.event_interval = val;
1315        self
1316    }
1317
1318    cfg_unstable! {
1319        /// Configure how the runtime responds to an unhandled panic on a
1320        /// spawned task.
1321        ///
1322        /// By default, an unhandled panic (i.e. a panic not caught by
1323        /// [`std::panic::catch_unwind`]) has no impact on the runtime's
1324        /// execution. The panic's error value is forwarded to the task's
1325        /// [`JoinHandle`] and all other spawned tasks continue running.
1326        ///
1327        /// The `unhandled_panic` option enables configuring this behavior.
1328        ///
1329        /// * `UnhandledPanic::Ignore` is the default behavior. Panics on
1330        ///   spawned tasks have no impact on the runtime's execution.
1331        /// * `UnhandledPanic::ShutdownRuntime` will force the runtime to
1332        ///   shutdown immediately when a spawned task panics even if that
1333        ///   task's `JoinHandle` has not been dropped. All other spawned tasks
1334        ///   will immediately terminate and further calls to
1335        ///   [`Runtime::block_on`] will panic.
1336        ///
1337        /// # Panics
1338        /// This method panics if called with [`UnhandledPanic::ShutdownRuntime`]
1339        /// on a runtime other than the current thread runtime.
1340        ///
1341        /// # Unstable
1342        ///
1343        /// This option is currently unstable and its implementation is
1344        /// incomplete. The API may change or be removed in the future. See
1345        /// issue [tokio-rs/tokio#4516] for more details.
1346        ///
1347        /// # Examples
1348        ///
1349        /// The following demonstrates a runtime configured to shutdown on
1350        /// panic. The first spawned task panics and results in the runtime
1351        /// shutting down. The second spawned task never has a chance to
1352        /// execute. The call to `block_on` will panic due to the runtime being
1353        /// forcibly shutdown.
1354        ///
1355        /// ```should_panic
1356        /// use tokio::runtime::{self, UnhandledPanic};
1357        ///
1358        /// # pub fn main() {
1359        /// let rt = runtime::Builder::new_current_thread()
1360        ///     .unhandled_panic(UnhandledPanic::ShutdownRuntime)
1361        ///     .build()
1362        ///     .unwrap();
1363        ///
1364        /// rt.spawn(async { panic!("boom"); });
1365        /// rt.spawn(async {
1366        ///     // This task never completes.
1367        /// });
1368        ///
1369        /// rt.block_on(async {
1370        ///     // Do some work
1371        /// # loop { tokio::task::yield_now().await; }
1372        /// })
1373        /// # }
1374        /// ```
1375        ///
1376        /// [`JoinHandle`]: struct@crate::task::JoinHandle
1377        /// [tokio-rs/tokio#4516]: https://github.com/tokio-rs/tokio/issues/4516
1378        pub fn unhandled_panic(&mut self, behavior: UnhandledPanic) -> &mut Self {
1379            if !matches!(self.kind, Kind::CurrentThread) && matches!(behavior, UnhandledPanic::ShutdownRuntime) {
1380                panic!("UnhandledPanic::ShutdownRuntime is only supported in current thread runtime");
1381            }
1382
1383            self.unhandled_panic = behavior;
1384            self
1385        }
1386
1387        /// Disables the LIFO task scheduler heuristic.
1388        ///
1389        /// The multi-threaded scheduler includes a heuristic for optimizing
1390        /// message-passing patterns. This heuristic results in the **last**
1391        /// scheduled task being polled first.
1392        ///
1393        /// To implement this heuristic, each worker thread has a slot which
1394        /// holds the task that should be polled next. However, this slot cannot
1395        /// be stolen by other worker threads, which can result in lower total
1396        /// throughput when tasks tend to have longer poll times.
1397        ///
1398        /// This configuration option will disable this heuristic resulting in
1399        /// all scheduled tasks being pushed into the worker-local queue, which
1400        /// is stealable.
1401        ///
1402        /// Consider trying this option when the task "scheduled" time is high
1403        /// but the runtime is underutilized. Use [tokio-rs/tokio-metrics] to
1404        /// collect this data.
1405        ///
1406        /// # Unstable
1407        ///
1408        /// This configuration option is considered a workaround for the LIFO
1409        /// slot not being stealable. When the slot becomes stealable, we will
1410        /// revisit whether or not this option is necessary. See
1411        /// issue [tokio-rs/tokio#4941].
1412        ///
1413        /// # Examples
1414        ///
1415        /// ```
1416        /// # #[cfg(not(target_family = "wasm"))]
1417        /// # {
1418        /// use tokio::runtime;
1419        ///
1420        /// let rt = runtime::Builder::new_multi_thread()
1421        ///     .disable_lifo_slot()
1422        ///     .build()
1423        ///     .unwrap();
1424        /// # }
1425        /// ```
1426        ///
1427        /// [tokio-rs/tokio-metrics]: https://github.com/tokio-rs/tokio-metrics
1428        /// [tokio-rs/tokio#4941]: https://github.com/tokio-rs/tokio/issues/4941
1429        pub fn disable_lifo_slot(&mut self) -> &mut Self {
1430            self.disable_lifo_slot = true;
1431            self
1432        }
1433
1434        /// Specifies the random number generation seed to use within all
1435        /// threads associated with the runtime being built.
1436        ///
1437        /// This option is intended to make certain parts of the runtime
1438        /// deterministic (e.g. the [`tokio::select!`] macro). In the case of
1439        /// [`tokio::select!`] it will ensure that the order that branches are
1440        /// polled is deterministic.
1441        ///
1442        /// In addition to the code specifying `rng_seed` and interacting with
1443        /// the runtime, the internals of Tokio and the Rust compiler may affect
1444        /// the sequences of random numbers. In order to ensure repeatable
1445        /// results, the version of Tokio, the versions of all other
1446        /// dependencies that interact with Tokio, and the Rust compiler version
1447        /// should also all remain constant.
1448        ///
1449        /// # Examples
1450        ///
1451        /// ```
1452        /// # use tokio::runtime::{self, RngSeed};
1453        /// # pub fn main() {
1454        /// let seed = RngSeed::from_bytes(b"place your seed here");
1455        /// let rt = runtime::Builder::new_current_thread()
1456        ///     .rng_seed(seed)
1457        ///     .build();
1458        /// # }
1459        /// ```
1460        ///
1461        /// [`tokio::select!`]: crate::select
1462        pub fn rng_seed(&mut self, seed: RngSeed) -> &mut Self {
1463            self.seed_generator = RngSeedGenerator::new(seed);
1464            self
1465        }
1466    }
1467
1468    cfg_unstable_metrics! {
1469        /// Enables tracking the distribution of task poll times.
1470        ///
1471        /// Task poll times are not instrumented by default as doing so requires
1472        /// calling [`Instant::now()`] twice per task poll, which could add
1473        /// measurable overhead. Use the [`Handle::metrics()`] to access the
1474        /// metrics data.
1475        ///
1476        /// The histogram uses fixed bucket sizes. In other words, the histogram
1477        /// buckets are not dynamic based on input values. Use the
1478        /// `metrics_poll_time_histogram` builder methods to configure the
1479        /// histogram details.
1480        ///
1481        /// By default, a linear histogram with 10 buckets each 100 microseconds wide will be used.
1482        /// This has an extremely low memory footprint, but may not provide enough granularity. For
1483        /// better granularity with low memory usage, use [`metrics_poll_time_histogram_configuration()`]
1484        /// to select [`LogHistogram`] instead.
1485        ///
1486        /// # Examples
1487        ///
1488        /// ```
1489        /// # #[cfg(not(target_family = "wasm"))]
1490        /// # {
1491        /// use tokio::runtime;
1492        ///
1493        /// let rt = runtime::Builder::new_multi_thread()
1494        ///     .enable_metrics_poll_time_histogram()
1495        ///     .build()
1496        ///     .unwrap();
1497        /// # // Test default values here
1498        /// # fn us(n: u64) -> std::time::Duration { std::time::Duration::from_micros(n) }
1499        /// # let m = rt.handle().metrics();
1500        /// # assert_eq!(m.poll_time_histogram_num_buckets(), 10);
1501        /// # assert_eq!(m.poll_time_histogram_bucket_range(0), us(0)..us(100));
1502        /// # assert_eq!(m.poll_time_histogram_bucket_range(1), us(100)..us(200));
1503        /// # }
1504        /// ```
1505        ///
1506        /// [`Handle::metrics()`]: crate::runtime::Handle::metrics
1507        /// [`Instant::now()`]: std::time::Instant::now
1508        /// [`LogHistogram`]: crate::runtime::LogHistogram
1509        /// [`metrics_poll_time_histogram_configuration()`]: Builder::metrics_poll_time_histogram_configuration
1510        pub fn enable_metrics_poll_time_histogram(&mut self) -> &mut Self {
1511            self.metrics_poll_count_histogram_enable = true;
1512            self
1513        }
1514
1515        /// Deprecated. Use [`enable_metrics_poll_time_histogram()`] instead.
1516        ///
1517        /// [`enable_metrics_poll_time_histogram()`]: Builder::enable_metrics_poll_time_histogram
1518        #[deprecated(note = "`poll_count_histogram` related methods have been renamed `poll_time_histogram` to better reflect their functionality.")]
1519        #[doc(hidden)]
1520        pub fn enable_metrics_poll_count_histogram(&mut self) -> &mut Self {
1521            self.enable_metrics_poll_time_histogram()
1522        }
1523
1524        /// Sets the histogram scale for tracking the distribution of task poll
1525        /// times.
1526        ///
1527        /// Tracking the distribution of task poll times can be done using a
1528        /// linear or log scale. When using linear scale, each histogram bucket
1529        /// will represent the same range of poll times. When using log scale,
1530        /// each histogram bucket will cover a range twice as big as the
1531        /// previous bucket.
1532        ///
1533        /// **Default:** linear scale.
1534        ///
1535        /// # Examples
1536        ///
1537        /// ```
1538        /// # #[cfg(not(target_family = "wasm"))]
1539        /// # {
1540        /// use tokio::runtime::{self, HistogramScale};
1541        ///
1542        /// # #[allow(deprecated)]
1543        /// let rt = runtime::Builder::new_multi_thread()
1544        ///     .enable_metrics_poll_time_histogram()
1545        ///     .metrics_poll_count_histogram_scale(HistogramScale::Log)
1546        ///     .build()
1547        ///     .unwrap();
1548        /// # }
1549        /// ```
1550        #[deprecated(note = "use `metrics_poll_time_histogram_configuration`")]
1551        pub fn metrics_poll_count_histogram_scale(&mut self, histogram_scale: crate::runtime::HistogramScale) -> &mut Self {
1552            self.metrics_poll_count_histogram.legacy_mut(|b|b.scale = histogram_scale);
1553            self
1554        }
1555
1556        /// Configure the histogram for tracking poll times
1557        ///
1558        /// By default, a linear histogram with 10 buckets each 100 microseconds wide will be used.
1559        /// This has an extremely low memory footprint, but may not provide enough granularity. For
1560        /// better granularity with low memory usage, use [`LogHistogram`] instead.
1561        ///
1562        /// # Examples
1563        /// Configure a [`LogHistogram`] with [default configuration]:
1564        /// ```
1565        /// # #[cfg(not(target_family = "wasm"))]
1566        /// # {
1567        /// use tokio::runtime;
1568        /// use tokio::runtime::{HistogramConfiguration, LogHistogram};
1569        ///
1570        /// let rt = runtime::Builder::new_multi_thread()
1571        ///     .enable_metrics_poll_time_histogram()
1572        ///     .metrics_poll_time_histogram_configuration(
1573        ///         HistogramConfiguration::log(LogHistogram::default())
1574        ///     )
1575        ///     .build()
1576        ///     .unwrap();
1577        /// # }
1578        /// ```
1579        ///
1580        /// Configure a linear histogram with 100 buckets, each 10μs wide
1581        /// ```
1582        /// # #[cfg(not(target_family = "wasm"))]
1583        /// # {
1584        /// use tokio::runtime;
1585        /// use std::time::Duration;
1586        /// use tokio::runtime::HistogramConfiguration;
1587        ///
1588        /// let rt = runtime::Builder::new_multi_thread()
1589        ///     .enable_metrics_poll_time_histogram()
1590        ///     .metrics_poll_time_histogram_configuration(
1591        ///         HistogramConfiguration::linear(Duration::from_micros(10), 100)
1592        ///     )
1593        ///     .build()
1594        ///     .unwrap();
1595        /// # }
1596        /// ```
1597        ///
1598        /// Configure a [`LogHistogram`] with the following settings:
1599        /// - Measure times from 100ns to 120s
1600        /// - Max error of 0.1
1601        /// - No more than 1024 buckets
1602        /// ```
1603        /// # #[cfg(not(target_family = "wasm"))]
1604        /// # {
1605        /// use std::time::Duration;
1606        /// use tokio::runtime;
1607        /// use tokio::runtime::{HistogramConfiguration, LogHistogram};
1608        ///
1609        /// let rt = runtime::Builder::new_multi_thread()
1610        ///     .enable_metrics_poll_time_histogram()
1611        ///     .metrics_poll_time_histogram_configuration(
1612        ///         HistogramConfiguration::log(LogHistogram::builder()
1613        ///             .max_value(Duration::from_secs(120))
1614        ///             .min_value(Duration::from_nanos(100))
1615        ///             .max_error(0.1)
1616        ///             .max_buckets(1024)
1617        ///             .expect("configuration uses 488 buckets")
1618        ///         )
1619        ///     )
1620        ///     .build()
1621        ///     .unwrap();
1622        /// # }
1623        /// ```
1624        ///
1625        /// When migrating from the legacy histogram ([`HistogramScale::Log`]) and wanting
1626        /// to match the previous behavior, use `precision_exact(0)`. This creates a histogram
1627        /// where each bucket is twice the size of the previous bucket.
1628        /// ```rust
1629        /// use std::time::Duration;
1630        /// use tokio::runtime::{HistogramConfiguration, LogHistogram};
1631        /// let rt = tokio::runtime::Builder::new_current_thread()
1632        ///     .enable_all()
1633        ///     .enable_metrics_poll_time_histogram()
1634        ///     .metrics_poll_time_histogram_configuration(HistogramConfiguration::log(
1635        ///         LogHistogram::builder()
1636        ///             .min_value(Duration::from_micros(20))
1637        ///             .max_value(Duration::from_millis(4))
1638        ///             // Set `precision_exact` to `0` to match `HistogramScale::Log`
1639        ///             .precision_exact(0)
1640        ///             .max_buckets(10)
1641        ///             .unwrap(),
1642        ///     ))
1643        ///     .build()
1644        ///     .unwrap();
1645        /// ```
1646        ///
1647        /// [`LogHistogram`]: crate::runtime::LogHistogram
1648        /// [default configuration]: crate::runtime::LogHistogramBuilder
1649        /// [`HistogramScale::Log`]: crate::runtime::HistogramScale::Log
1650        pub fn metrics_poll_time_histogram_configuration(&mut self, configuration: HistogramConfiguration) -> &mut Self {
1651            self.metrics_poll_count_histogram.histogram_type = configuration.inner;
1652            self
1653        }
1654
1655        /// Sets the histogram resolution for tracking the distribution of task
1656        /// poll times.
1657        ///
1658        /// The resolution is the histogram's first bucket's range. When using a
1659        /// linear histogram scale, each bucket will cover the same range. When
1660        /// using a log scale, each bucket will cover a range twice as big as
1661        /// the previous bucket. In the log case, the resolution represents the
1662        /// smallest bucket range.
1663        ///
1664        /// Note that, when using log scale, the resolution is rounded up to the
1665        /// nearest power of 2 in nanoseconds.
1666        ///
1667        /// **Default:** 100 microseconds.
1668        ///
1669        /// # Examples
1670        ///
1671        /// ```
1672        /// # #[cfg(not(target_family = "wasm"))]
1673        /// # {
1674        /// use tokio::runtime;
1675        /// use std::time::Duration;
1676        ///
1677        /// # #[allow(deprecated)]
1678        /// let rt = runtime::Builder::new_multi_thread()
1679        ///     .enable_metrics_poll_time_histogram()
1680        ///     .metrics_poll_count_histogram_resolution(Duration::from_micros(100))
1681        ///     .build()
1682        ///     .unwrap();
1683        /// # }
1684        /// ```
1685        #[deprecated(note = "use `metrics_poll_time_histogram_configuration`")]
1686        pub fn metrics_poll_count_histogram_resolution(&mut self, resolution: Duration) -> &mut Self {
1687            assert!(resolution > Duration::from_secs(0));
1688            // Sanity check the argument and also make the cast below safe.
1689            assert!(resolution <= Duration::from_secs(1));
1690
1691            let resolution = resolution.as_nanos() as u64;
1692
1693            self.metrics_poll_count_histogram.legacy_mut(|b|b.resolution = resolution);
1694            self
1695        }
1696
1697        /// Sets the number of buckets for the histogram tracking the
1698        /// distribution of task poll times.
1699        ///
1700        /// The last bucket tracks all greater values that fall out of other
1701        /// ranges. So, configuring the histogram using a linear scale,
1702        /// resolution of 50ms, and 10 buckets, the 10th bucket will track task
1703        /// polls that take more than 450ms to complete.
1704        ///
1705        /// **Default:** 10
1706        ///
1707        /// # Examples
1708        ///
1709        /// ```
1710        /// # #[cfg(not(target_family = "wasm"))]
1711        /// # {
1712        /// use tokio::runtime;
1713        ///
1714        /// # #[allow(deprecated)]
1715        /// let rt = runtime::Builder::new_multi_thread()
1716        ///     .enable_metrics_poll_time_histogram()
1717        ///     .metrics_poll_count_histogram_buckets(15)
1718        ///     .build()
1719        ///     .unwrap();
1720        /// # }
1721        /// ```
1722        #[deprecated(note = "use `metrics_poll_time_histogram_configuration`")]
1723        pub fn metrics_poll_count_histogram_buckets(&mut self, buckets: usize) -> &mut Self {
1724            self.metrics_poll_count_histogram.legacy_mut(|b|b.num_buckets = buckets);
1725            self
1726        }
1727    }
1728
1729    fn build_current_thread_runtime(&mut self) -> io::Result<Runtime> {
1730        use crate::runtime::runtime::Scheduler;
1731
1732        let (scheduler, handle, blocking_pool) =
1733            self.build_current_thread_runtime_components(None)?;
1734
1735        Ok(Runtime::from_parts(
1736            Scheduler::CurrentThread(scheduler),
1737            handle,
1738            blocking_pool,
1739        ))
1740    }
1741
1742    fn build_current_thread_local_runtime(&mut self) -> io::Result<LocalRuntime> {
1743        use crate::runtime::local_runtime::LocalRuntimeScheduler;
1744
1745        let tid = std::thread::current().id();
1746
1747        let (scheduler, handle, blocking_pool) =
1748            self.build_current_thread_runtime_components(Some(tid))?;
1749
1750        Ok(LocalRuntime::from_parts(
1751            LocalRuntimeScheduler::CurrentThread(scheduler),
1752            handle,
1753            blocking_pool,
1754        ))
1755    }
1756
1757    fn build_current_thread_runtime_components(
1758        &mut self,
1759        local_tid: Option<ThreadId>,
1760    ) -> io::Result<(CurrentThread, Handle, BlockingPool)> {
1761        use crate::runtime::scheduler;
1762        use crate::runtime::Config;
1763
1764        let mut cfg = self.get_cfg();
1765        cfg.timer_flavor = TimerFlavor::Traditional;
1766        let (driver, driver_handle) = driver::Driver::new(cfg)?;
1767
1768        // Blocking pool
1769        let blocking_pool = blocking::create_blocking_pool(self, self.max_blocking_threads, 0);
1770        let blocking_spawner = blocking_pool.spawner().clone();
1771
1772        // Generate a rng seed for this runtime.
1773        let seed_generator_1 = self.seed_generator.next_generator();
1774        let seed_generator_2 = self.seed_generator.next_generator();
1775
1776        // And now put a single-threaded scheduler on top of the timer. When
1777        // there are no futures ready to do something, it'll let the timer or
1778        // the reactor to generate some new stimuli for the futures to continue
1779        // in their life.
1780        let (scheduler, handle) = CurrentThread::new(
1781            driver,
1782            driver_handle,
1783            blocking_spawner,
1784            seed_generator_2,
1785            Config {
1786                before_park: self.before_park.clone(),
1787                after_unpark: self.after_unpark.clone(),
1788                before_spawn: self.before_spawn.clone(),
1789                #[cfg(tokio_unstable)]
1790                before_poll: self.before_poll.clone(),
1791                #[cfg(tokio_unstable)]
1792                after_poll: self.after_poll.clone(),
1793                after_termination: self.after_termination.clone(),
1794                global_queue_interval: self.global_queue_interval,
1795                event_interval: self.event_interval,
1796                #[cfg(tokio_unstable)]
1797                unhandled_panic: self.unhandled_panic.clone(),
1798                disable_lifo_slot: self.disable_lifo_slot,
1799                // This setting never makes sense for a current thread runtime,
1800                // as it only configures how the I/O driver is stolen across
1801                // workers.
1802                enable_eager_driver_handoff: false,
1803                seed_generator: seed_generator_1,
1804                metrics_poll_count_histogram: self.metrics_poll_count_histogram_builder(),
1805                track_task_schedule_latency: self.track_task_schedule_latency,
1806                metrics_schedule_latency_histogram: self
1807                    .metrics_schedule_latency_histogram_builder(),
1808            },
1809            local_tid,
1810            self.name.clone(),
1811        );
1812
1813        let handle = Handle {
1814            inner: scheduler::Handle::CurrentThread(handle),
1815        };
1816
1817        Ok((scheduler, handle, blocking_pool))
1818    }
1819
1820    fn metrics_poll_count_histogram_builder(&self) -> Option<HistogramBuilder> {
1821        if self.metrics_poll_count_histogram_enable {
1822            Some(self.metrics_poll_count_histogram.clone())
1823        } else {
1824            None
1825        }
1826    }
1827
1828    fn metrics_schedule_latency_histogram_builder(&self) -> Option<HistogramBuilder> {
1829        if self.metrics_schedule_latency_histogram_enabled {
1830            Some(self.metrics_schedule_latency_histogram.clone())
1831        } else {
1832            None
1833        }
1834    }
1835
1836    /// Enables the I/O driver.
1837    ///
1838    /// Doing this enables using net, process, signal, and some I/O types on
1839    /// the runtime.
1840    ///
1841    /// # Examples
1842    ///
1843    /// ```
1844    /// use tokio::runtime;
1845    ///
1846    /// let rt = runtime::Builder::new_current_thread()
1847    ///     .enable_io()
1848    ///     .build()
1849    ///     .unwrap();
1850    /// ```
1851    pub fn enable_io(&mut self) -> &mut Self {
1852        self.enable_io = true;
1853        self
1854    }
1855
1856    /// Sets the max number of I/O events processed per tick.
1857    ///
1858    /// To take a smaller batch on polls that do not wait, see
1859    /// [`max_io_events_per_busy_tick`].
1860    ///
1861    /// [`max_io_events_per_busy_tick`]: Builder::max_io_events_per_busy_tick
1862    ///
1863    /// # Panics
1864    ///
1865    /// Panics if `capacity` is zero.
1866    ///
1867    /// # Examples
1868    ///
1869    /// ```
1870    /// use tokio::runtime;
1871    ///
1872    /// let rt = runtime::Builder::new_current_thread()
1873    ///     .enable_io()
1874    ///     .max_io_events_per_tick(1024)
1875    ///     .build()
1876    ///     .unwrap();
1877    /// ```
1878    #[track_caller]
1879    pub fn max_io_events_per_tick(&mut self, capacity: usize) -> &mut Self {
1880        assert!(capacity > 0, "max_io_events_per_tick must be non-zero");
1881        self.nevents = capacity;
1882        self
1883    }
1884
1885    /// Sets the max number of I/O events a worker processes when it polls
1886    /// the driver while it still has tasks to run.
1887    ///
1888    /// A busy worker polls the driver every [`event_interval`] tasks, and
1889    /// every task that poll wakes goes to its local queue. A large batch
1890    /// overflows that queue, and under sustained overload the overflow
1891    /// grows until requests time out. A small busy batch leaves the rest
1892    /// in the kernel. An idle worker still takes up to
1893    /// [`max_io_events_per_tick`] events.
1894    ///
1895    /// The runtime treats any poll that does not wait as busy. That
1896    /// includes a park with a timer that has already expired, because the
1897    /// worker runs that timer's task next.
1898    ///
1899    /// A multi-thread worker's local queue holds 256 tasks, so set
1900    /// `max_io_events_per_tick` to at most 256 as well, with room for the
1901    /// tasks those tasks wake.
1902    ///
1903    /// The default is to use the same value as [`max_io_events_per_tick`].
1904    ///
1905    /// [`event_interval`]: Builder::event_interval
1906    /// [`max_io_events_per_tick`]: Builder::max_io_events_per_tick
1907    ///
1908    /// # Panics
1909    ///
1910    /// Panics if `capacity` is zero.
1911    ///
1912    /// # Examples
1913    ///
1914    /// ```
1915    /// use tokio::runtime;
1916    ///
1917    /// let rt = runtime::Builder::new_current_thread()
1918    ///     .enable_io()
1919    ///     .max_io_events_per_tick(128)
1920    ///     .max_io_events_per_busy_tick(8)
1921    ///     .build()
1922    ///     .unwrap();
1923    /// ```
1924    #[track_caller]
1925    pub fn max_io_events_per_busy_tick(&mut self, capacity: usize) -> &mut Self {
1926        assert!(capacity > 0, "max_io_events_per_busy_tick must be non-zero");
1927        self.nevents_busy = Some(capacity);
1928        self
1929    }
1930}
1931
1932cfg_time! {
1933    impl Builder {
1934        /// Enables the time driver.
1935        ///
1936        /// Doing this enables using `tokio::time` on the runtime.
1937        ///
1938        /// # Examples
1939        ///
1940        /// ```
1941        /// # #[cfg(not(target_family = "wasm"))]
1942        /// # {
1943        /// use tokio::runtime;
1944        ///
1945        /// let rt = runtime::Builder::new_multi_thread()
1946        ///     .enable_time()
1947        ///     .build()
1948        ///     .unwrap();
1949        /// # }
1950        /// ```
1951        pub fn enable_time(&mut self) -> &mut Self {
1952            self.enable_time = true;
1953            self
1954        }
1955    }
1956}
1957
1958cfg_io_uring! {
1959    impl Builder {
1960        /// Enables the tokio's io_uring driver.
1961        ///
1962        /// Doing this enables using io_uring operations on the runtime.
1963        ///
1964        /// # Examples
1965        ///
1966        /// ```
1967        /// use tokio::runtime;
1968        ///
1969        /// let rt = runtime::Builder::new_multi_thread()
1970        ///     .enable_io_uring()
1971        ///     .build()
1972        ///     .unwrap();
1973        /// ```
1974        #[cfg_attr(docsrs, doc(cfg(feature = "io-uring")))]
1975        pub fn enable_io_uring(&mut self) -> &mut Self {
1976            // Currently, the uring flag is equivalent to `enable_io`.
1977            self.enable_io = true;
1978            self
1979        }
1980    }
1981}
1982
1983cfg_test_util! {
1984    impl Builder {
1985        /// Controls if the runtime's clock starts paused or advancing.
1986        ///
1987        /// Pausing time requires the current-thread runtime; construction of
1988        /// the runtime will panic otherwise.
1989        ///
1990        /// # Examples
1991        ///
1992        /// ```
1993        /// use tokio::runtime;
1994        ///
1995        /// let rt = runtime::Builder::new_current_thread()
1996        ///     .enable_time()
1997        ///     .start_paused(true)
1998        ///     .build()
1999        ///     .unwrap();
2000        /// ```
2001        pub fn start_paused(&mut self, start_paused: bool) -> &mut Self {
2002            self.start_paused = start_paused;
2003            self
2004        }
2005    }
2006}
2007
2008cfg_schedule_latency! {
2009    impl Builder {
2010        /// Enables tracking task schedule latency.
2011        ///
2012        /// Task schedule latency is measured from a task's most recent
2013        /// transition to the scheduled state until immediately before it is
2014        /// polled. Waking a task that is already scheduled does not reset the
2015        /// measurement. Once enabled, the latency is available to task poll
2016        /// hooks through [`TaskMeta::schedule_latency`].
2017        ///
2018        /// Task schedule latencies are not tracked by default as doing so
2019        /// requires calling [`Instant::now()`] when a task is scheduled and
2020        /// when it is polled, which could add measurable overhead.
2021        ///
2022        /// The [`enable_metrics_schedule_latency_histogram`] method also
2023        /// enables tracking and records the latencies in a histogram.
2024        ///
2025        /// **This feature is only supported on 64-bit targets.**
2026        ///
2027        /// # Examples
2028        ///
2029        /// ```
2030        /// # use tokio::runtime;
2031        /// let runtime = runtime::Builder::new_current_thread()
2032        ///     .track_task_schedule_latency()
2033        ///     .on_before_task_poll(|meta| {
2034        ///         if let Some(latency) = meta.schedule_latency() {
2035        ///             println!("task schedule latency: {latency:?}");
2036        ///         }
2037        ///     })
2038        ///     .build()
2039        ///     .unwrap();
2040        /// ```
2041        ///
2042        /// [`TaskMeta::schedule_latency`]: crate::runtime::TaskMeta::schedule_latency
2043        /// [`Instant::now()`]: std::time::Instant::now
2044        /// [`enable_metrics_schedule_latency_histogram`]: Builder::enable_metrics_schedule_latency_histogram
2045        pub fn track_task_schedule_latency(&mut self) -> &mut Self {
2046            self.track_task_schedule_latency = true;
2047            self
2048        }
2049
2050        /// Enables tracking the distribution of task schedule latencies. Task
2051        /// schedule latency is the time between when a task is scheduled for
2052        /// execution and when it is polled.
2053        ///
2054        /// **This feature is only supported on 64-bit targets.**
2055        ///
2056        /// Task schedule latencies are not instrumented by default as doing
2057        /// so requires calling [`Instant::now()`] when a task is scheduled
2058        /// and when it is polled, which could add measurable overhead. Use
2059        /// the [`Handle::metrics()`] to access the metrics data.
2060        ///
2061        /// By default, a linear histogram with 10 buckets each 100 microseconds wide will be used.
2062        /// This has an extremely low memory footprint, but may not provide enough granularity. For
2063        /// better granularity with low memory usage, use [`metrics_schedule_latency_histogram_configuration()`]
2064        /// to select [`LogHistogram`] instead.
2065        ///
2066        /// On the multi-thread runtime, each task polled from the LIFO slot is
2067        /// recorded as a separate schedule-latency sample. Task poll hooks
2068        /// receive the same per-task latency through [`TaskMeta::schedule_latency`].
2069        ///
2070        /// # Examples
2071        ///
2072        /// ```
2073        /// # #[cfg(not(target_family = "wasm"))]
2074        /// # {
2075        /// use tokio::runtime;
2076        ///
2077        /// let rt = runtime::Builder::new_multi_thread()
2078        ///     .enable_metrics_schedule_latency_histogram()
2079        ///     .build()
2080        ///     .unwrap();
2081        /// # // Test default values here
2082        /// # fn us(n: u64) -> std::time::Duration { std::time::Duration::from_micros(n) }
2083        /// # let m = rt.handle().metrics();
2084        /// # assert_eq!(m.schedule_latency_histogram_num_buckets(), 10);
2085        /// # assert_eq!(m.schedule_latency_histogram_bucket_range(0), us(0)..us(100));
2086        /// # assert_eq!(m.schedule_latency_histogram_bucket_range(1), us(100)..us(200));
2087        /// # }
2088        /// ```
2089        ///
2090        /// [`Handle::metrics()`]: crate::runtime::Handle::metrics
2091        /// [`Instant::now()`]: std::time::Instant::now
2092        /// [`LogHistogram`]: crate::runtime::LogHistogram
2093        /// [`metrics_schedule_latency_histogram_configuration()`]: Builder::metrics_schedule_latency_histogram_configuration
2094        pub fn enable_metrics_schedule_latency_histogram(&mut self) -> &mut Self {
2095            self.track_task_schedule_latency = true;
2096            self.metrics_schedule_latency_histogram_enabled = true;
2097            self
2098        }
2099
2100        /// Configure the histogram for tracking task schedule latencies.
2101        ///
2102        /// Tracking of task schedule latencies must be enabled with
2103        /// [`enable_metrics_schedule_latency_histogram()`] for this function
2104        /// to have any effect.
2105        ///
2106        /// By default, a linear histogram with 10 buckets each 100 microseconds wide will be used.
2107        /// This has an extremely low memory footprint, but may not provide enough granularity. For
2108        /// better granularity with low memory usage, use [`LogHistogram`] instead.
2109        ///
2110        /// # Examples
2111        /// Configure a [`LogHistogram`] with [default configuration]:
2112        /// ```
2113        /// # #[cfg(not(target_family = "wasm"))]
2114        /// # {
2115        /// use tokio::runtime;
2116        /// use tokio::runtime::{HistogramConfiguration, LogHistogram};
2117        ///
2118        /// let rt = runtime::Builder::new_multi_thread()
2119        ///     .enable_metrics_schedule_latency_histogram()
2120        ///     .metrics_schedule_latency_histogram_configuration(
2121        ///         HistogramConfiguration::log(LogHistogram::default())
2122        ///     )
2123        ///     .build()
2124        ///     .unwrap();
2125        /// # }
2126        /// ```
2127        ///
2128        /// Configure a linear histogram with 100 buckets, each 10μs wide
2129        /// ```
2130        /// # #[cfg(not(target_family = "wasm"))]
2131        /// # {
2132        /// use tokio::runtime;
2133        /// use std::time::Duration;
2134        /// use tokio::runtime::HistogramConfiguration;
2135        ///
2136        /// let rt = runtime::Builder::new_multi_thread()
2137        ///     .enable_metrics_schedule_latency_histogram()
2138        ///     .metrics_schedule_latency_histogram_configuration(
2139        ///         HistogramConfiguration::linear(Duration::from_micros(10), 100)
2140        ///     )
2141        ///     .build()
2142        ///     .unwrap();
2143        /// # }
2144        /// ```
2145        ///
2146        /// Configure a [`LogHistogram`] with the following settings:
2147        /// - Measure times from 100ns to 120s
2148        /// - Max error of 0.1
2149        /// - No more than 1024 buckets
2150        /// ```
2151        /// # #[cfg(not(target_family = "wasm"))]
2152        /// # {
2153        /// use std::time::Duration;
2154        /// use tokio::runtime;
2155        /// use tokio::runtime::{HistogramConfiguration, LogHistogram};
2156        ///
2157        /// let rt = runtime::Builder::new_multi_thread()
2158        ///     .enable_metrics_schedule_latency_histogram()
2159        ///     .metrics_schedule_latency_histogram_configuration(
2160        ///         HistogramConfiguration::log(LogHistogram::builder()
2161        ///             .max_value(Duration::from_secs(120))
2162        ///             .min_value(Duration::from_nanos(100))
2163        ///             .max_error(0.1)
2164        ///             .max_buckets(1024)
2165        ///             .expect("configuration uses 488 buckets")
2166        ///         )
2167        ///     )
2168        ///     .build()
2169        ///     .unwrap();
2170        /// # }
2171        /// ```
2172        ///
2173        /// [`LogHistogram`]: crate::runtime::LogHistogram
2174        /// [`enable_metrics_schedule_latency_histogram()`]: Builder::enable_metrics_schedule_latency_histogram
2175        pub fn metrics_schedule_latency_histogram_configuration(&mut self, configuration: HistogramConfiguration) -> &mut Self {
2176            self.metrics_schedule_latency_histogram.histogram_type = configuration.inner;
2177            self
2178        }
2179    }
2180}
2181
2182cfg_rt_multi_thread! {
2183    impl Builder {
2184        fn build_threaded_runtime(&mut self) -> io::Result<Runtime> {
2185            use crate::loom::sys::num_cpus;
2186            use crate::runtime::{Config, runtime::Scheduler};
2187            use crate::runtime::scheduler::{self, MultiThread};
2188
2189            let worker_threads = self.worker_threads.unwrap_or_else(num_cpus);
2190
2191            let (driver, driver_handle) = driver::Driver::new(self.get_cfg())?;
2192
2193            // Create the blocking pool
2194            let blocking_pool =
2195                blocking::create_blocking_pool(self, self.max_blocking_threads + worker_threads, worker_threads);
2196            let blocking_spawner = blocking_pool.spawner().clone();
2197
2198            // Generate a rng seed for this runtime.
2199            let seed_generator_1 = self.seed_generator.next_generator();
2200            let seed_generator_2 = self.seed_generator.next_generator();
2201
2202            let (scheduler, handle, launch) = MultiThread::new(
2203                worker_threads,
2204                driver,
2205                driver_handle,
2206                blocking_spawner,
2207                seed_generator_2,
2208                Config {
2209                    before_park: self.before_park.clone(),
2210                    after_unpark: self.after_unpark.clone(),
2211                    before_spawn: self.before_spawn.clone(),
2212                    #[cfg(tokio_unstable)]
2213                    before_poll: self.before_poll.clone(),
2214                    #[cfg(tokio_unstable)]
2215                    after_poll: self.after_poll.clone(),
2216                    after_termination: self.after_termination.clone(),
2217                    global_queue_interval: self.global_queue_interval,
2218                    event_interval: self.event_interval,
2219                    #[cfg(tokio_unstable)]
2220                    unhandled_panic: self.unhandled_panic.clone(),
2221                    disable_lifo_slot: self.disable_lifo_slot,
2222                    enable_eager_driver_handoff: self.enable_eager_driver_handoff,
2223                    seed_generator: seed_generator_1,
2224                    metrics_poll_count_histogram: self.metrics_poll_count_histogram_builder(),
2225                    track_task_schedule_latency: self.track_task_schedule_latency,
2226                    metrics_schedule_latency_histogram: self.metrics_schedule_latency_histogram_builder(),
2227                },
2228                self.timer_flavor,
2229                self.name.clone(),
2230            );
2231
2232            let handle = Handle { inner: scheduler::Handle::MultiThread(handle) };
2233
2234            // Spawn the thread pool workers
2235            let _enter = handle.enter();
2236            launch.launch();
2237
2238            Ok(Runtime::from_parts(Scheduler::MultiThread(scheduler), handle, blocking_pool))
2239        }
2240    }
2241}
2242
2243impl fmt::Debug for Builder {
2244    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2245        let mut debug = fmt.debug_struct("Builder");
2246
2247        if let Some(name) = &self.name {
2248            debug.field("name", name);
2249        }
2250
2251        debug
2252            .field("worker_threads", &self.worker_threads)
2253            .field("max_blocking_threads", &self.max_blocking_threads)
2254            .field(
2255                "thread_name",
2256                &"<dyn Fn() -> String + Send + Sync + 'static>",
2257            )
2258            .field("thread_stack_size", &self.thread_stack_size)
2259            .field("after_start", &self.after_start.as_ref().map(|_| "..."))
2260            .field("before_stop", &self.before_stop.as_ref().map(|_| "..."))
2261            .field("before_park", &self.before_park.as_ref().map(|_| "..."))
2262            .field("after_unpark", &self.after_unpark.as_ref().map(|_| "..."))
2263            .field(
2264                "enable_eager_driver_handoff",
2265                &self.enable_eager_driver_handoff,
2266            );
2267
2268        if self.name.is_none() {
2269            debug.finish_non_exhaustive()
2270        } else {
2271            debug.finish()
2272        }
2273    }
2274}