1 #[cfg(tokio_unstable)]
2 use crate::runtime;
3 use crate::runtime::{context, scheduler, RuntimeFlavor, RuntimeMetrics};
4 
5 /// Handle to the runtime.
6 ///
7 /// The handle is internally reference-counted and can be freely cloned. A handle can be
8 /// obtained using the [`Runtime::handle`] method.
9 ///
10 /// [`Runtime::handle`]: crate::runtime::Runtime::handle()
11 #[derive(Debug, Clone)]
12 // When the `rt` feature is *not* enabled, this type is still defined, but not
13 // included in the public API.
14 pub struct Handle {
15     pub(crate) inner: scheduler::Handle,
16 }
17 
18 use crate::runtime::task::JoinHandle;
19 use crate::runtime::BOX_FUTURE_THRESHOLD;
20 use crate::util::error::{CONTEXT_MISSING_ERROR, THREAD_LOCAL_DESTROYED_ERROR};
21 use crate::util::trace::SpawnMeta;
22 
23 use std::future::Future;
24 use std::marker::PhantomData;
25 use std::{error, fmt, mem};
26 
27 /// Runtime context guard.
28 ///
29 /// Returned by [`Runtime::enter`] and [`Handle::enter`], the context guard exits
30 /// the runtime context on drop.
31 ///
32 /// [`Runtime::enter`]: fn@crate::runtime::Runtime::enter
33 #[derive(Debug)]
34 #[must_use = "Creating and dropping a guard does nothing"]
35 pub struct EnterGuard<'a> {
36     _guard: context::SetCurrentGuard,
37     _handle_lifetime: PhantomData<&'a Handle>,
38 }
39 
40 impl Handle {
41     /// Enters the runtime context. This allows you to construct types that must
42     /// have an executor available on creation such as [`Sleep`] or
43     /// [`TcpStream`]. It will also allow you to call methods such as
44     /// [`tokio::spawn`] and [`Handle::current`] without panicking.
45     ///
46     /// # Panics
47     ///
48     /// When calling `Handle::enter` multiple times, the returned guards
49     /// **must** be dropped in the reverse order that they were acquired.
50     /// Failure to do so will result in a panic and possible memory leaks.
51     ///
52     /// # Examples
53     ///
54     /// ```
55     /// use tokio::runtime::Runtime;
56     ///
57     /// let rt = Runtime::new().unwrap();
58     ///
59     /// let _guard = rt.enter();
60     /// tokio::spawn(async {
61     ///     println!("Hello world!");
62     /// });
63     /// ```
64     ///
65     /// Do **not** do the following, this shows a scenario that will result in a
66     /// panic and possible memory leak.
67     ///
68     /// ```should_panic
69     /// use tokio::runtime::Runtime;
70     ///
71     /// let rt1 = Runtime::new().unwrap();
72     /// let rt2 = Runtime::new().unwrap();
73     ///
74     /// let enter1 = rt1.enter();
75     /// let enter2 = rt2.enter();
76     ///
77     /// drop(enter1);
78     /// drop(enter2);
79     /// ```
80     ///
81     /// [`Sleep`]: struct@crate::time::Sleep
82     /// [`TcpStream`]: struct@crate::net::TcpStream
83     /// [`tokio::spawn`]: fn@crate::spawn
enter(&self) -> EnterGuard<'_>84     pub fn enter(&self) -> EnterGuard<'_> {
85         EnterGuard {
86             _guard: match context::try_set_current(&self.inner) {
87                 Some(guard) => guard,
88                 None => panic!("{}", crate::util::error::THREAD_LOCAL_DESTROYED_ERROR),
89             },
90             _handle_lifetime: PhantomData,
91         }
92     }
93 
94     /// Returns a `Handle` view over the currently running `Runtime`.
95     ///
96     /// # Panics
97     ///
98     /// This will panic if called outside the context of a Tokio runtime. That means that you must
99     /// call this on one of the threads **being run by the runtime**, or from a thread with an active
100     /// `EnterGuard`. Calling this from within a thread created by `std::thread::spawn` (for example)
101     /// will cause a panic unless that thread has an active `EnterGuard`.
102     ///
103     /// # Examples
104     ///
105     /// This can be used to obtain the handle of the surrounding runtime from an async
106     /// block or function running on that runtime.
107     ///
108     /// ```
109     /// # use std::thread;
110     /// # use tokio::runtime::Runtime;
111     /// # fn dox() {
112     /// # let rt = Runtime::new().unwrap();
113     /// # rt.spawn(async {
114     /// use tokio::runtime::Handle;
115     ///
116     /// // Inside an async block or function.
117     /// let handle = Handle::current();
118     /// handle.spawn(async {
119     ///     println!("now running in the existing Runtime");
120     /// });
121     ///
122     /// # let handle =
123     /// thread::spawn(move || {
124     ///     // Notice that the handle is created outside of this thread and then moved in
125     ///     handle.spawn(async { /* ... */ });
126     ///     // This next line would cause a panic because we haven't entered the runtime
127     ///     // and created an EnterGuard
128     ///     // let handle2 = Handle::current(); // panic
129     ///     // So we create a guard here with Handle::enter();
130     ///     let _guard = handle.enter();
131     ///     // Now we can call Handle::current();
132     ///     let handle2 = Handle::current();
133     /// });
134     /// # handle.join().unwrap();
135     /// # });
136     /// # }
137     /// ```
138     #[track_caller]
current() -> Self139     pub fn current() -> Self {
140         Handle {
141             inner: scheduler::Handle::current(),
142         }
143     }
144 
145     /// Returns a Handle view over the currently running Runtime
146     ///
147     /// Returns an error if no Runtime has been started
148     ///
149     /// Contrary to `current`, this never panics
try_current() -> Result<Self, TryCurrentError>150     pub fn try_current() -> Result<Self, TryCurrentError> {
151         context::with_current(|inner| Handle {
152             inner: inner.clone(),
153         })
154     }
155 
156     /// Spawns a future onto the Tokio runtime.
157     ///
158     /// This spawns the given future onto the runtime's executor, usually a
159     /// thread pool. The thread pool is then responsible for polling the future
160     /// until it completes.
161     ///
162     /// The provided future will start running in the background immediately
163     /// when `spawn` is called, even if you don't await the returned
164     /// `JoinHandle`.
165     ///
166     /// See [module level][mod] documentation for more details.
167     ///
168     /// [mod]: index.html
169     ///
170     /// # Examples
171     ///
172     /// ```
173     /// use tokio::runtime::Runtime;
174     ///
175     /// # fn dox() {
176     /// // Create the runtime
177     /// let rt = Runtime::new().unwrap();
178     /// // Get a handle from this runtime
179     /// let handle = rt.handle();
180     ///
181     /// // Spawn a future onto the runtime using the handle
182     /// handle.spawn(async {
183     ///     println!("now running on a worker thread");
184     /// });
185     /// # }
186     /// ```
187     #[track_caller]
spawn<F>(&self, future: F) -> JoinHandle<F::Output> where F: Future + Send + 'static, F::Output: Send + 'static,188     pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
189     where
190         F: Future + Send + 'static,
191         F::Output: Send + 'static,
192     {
193         let fut_size = mem::size_of::<F>();
194         if fut_size > BOX_FUTURE_THRESHOLD {
195             self.spawn_named(Box::pin(future), SpawnMeta::new_unnamed(fut_size))
196         } else {
197             self.spawn_named(future, SpawnMeta::new_unnamed(fut_size))
198         }
199     }
200 
201     /// Runs the provided function on an executor dedicated to blocking
202     /// operations.
203     ///
204     /// # Examples
205     ///
206     /// ```
207     /// use tokio::runtime::Runtime;
208     ///
209     /// # fn dox() {
210     /// // Create the runtime
211     /// let rt = Runtime::new().unwrap();
212     /// // Get a handle from this runtime
213     /// let handle = rt.handle();
214     ///
215     /// // Spawn a blocking function onto the runtime using the handle
216     /// handle.spawn_blocking(|| {
217     ///     println!("now running on a worker thread");
218     /// });
219     /// # }
220     #[track_caller]
spawn_blocking<F, R>(&self, func: F) -> JoinHandle<R> where F: FnOnce() -> R + Send + 'static, R: Send + 'static,221     pub fn spawn_blocking<F, R>(&self, func: F) -> JoinHandle<R>
222     where
223         F: FnOnce() -> R + Send + 'static,
224         R: Send + 'static,
225     {
226         self.inner.blocking_spawner().spawn_blocking(self, func)
227     }
228 
229     /// Runs a future to completion on this `Handle`'s associated `Runtime`.
230     ///
231     /// This runs the given future on the current thread, blocking until it is
232     /// complete, and yielding its resolved result. Any tasks or timers which
233     /// the future spawns internally will be executed on the runtime.
234     ///
235     /// When this is used on a `current_thread` runtime, only the
236     /// [`Runtime::block_on`] method can drive the IO and timer drivers, but the
237     /// `Handle::block_on` method cannot drive them. This means that, when using
238     /// this method on a `current_thread` runtime, anything that relies on IO or
239     /// timers will not work unless there is another thread currently calling
240     /// [`Runtime::block_on`] on the same runtime.
241     ///
242     /// # If the runtime has been shut down
243     ///
244     /// If the `Handle`'s associated `Runtime` has been shut down (through
245     /// [`Runtime::shutdown_background`], [`Runtime::shutdown_timeout`], or by
246     /// dropping it) and `Handle::block_on` is used it might return an error or
247     /// panic. Specifically IO resources will return an error and timers will
248     /// panic. Runtime independent futures will run as normal.
249     ///
250     /// # Panics
251     ///
252     /// This function panics if the provided future panics, if called within an
253     /// asynchronous execution context, or if a timer future is executed on a runtime that has been
254     /// shut down.
255     ///
256     /// # Examples
257     ///
258     /// ```
259     /// use tokio::runtime::Runtime;
260     ///
261     /// // Create the runtime
262     /// let rt  = Runtime::new().unwrap();
263     ///
264     /// // Get a handle from this runtime
265     /// let handle = rt.handle();
266     ///
267     /// // Execute the future, blocking the current thread until completion
268     /// handle.block_on(async {
269     ///     println!("hello");
270     /// });
271     /// ```
272     ///
273     /// Or using `Handle::current`:
274     ///
275     /// ```
276     /// use tokio::runtime::Handle;
277     ///
278     /// #[tokio::main]
279     /// async fn main () {
280     ///     let handle = Handle::current();
281     ///     std::thread::spawn(move || {
282     ///         // Using Handle::block_on to run async code in the new thread.
283     ///         handle.block_on(async {
284     ///             println!("hello");
285     ///         });
286     ///     });
287     /// }
288     /// ```
289     ///
290     /// [`JoinError`]: struct@crate::task::JoinError
291     /// [`JoinHandle`]: struct@crate::task::JoinHandle
292     /// [`Runtime::block_on`]: fn@crate::runtime::Runtime::block_on
293     /// [`Runtime::shutdown_background`]: fn@crate::runtime::Runtime::shutdown_background
294     /// [`Runtime::shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
295     /// [`spawn_blocking`]: crate::task::spawn_blocking
296     /// [`tokio::fs`]: crate::fs
297     /// [`tokio::net`]: crate::net
298     /// [`tokio::time`]: crate::time
299     #[track_caller]
block_on<F: Future>(&self, future: F) -> F::Output300     pub fn block_on<F: Future>(&self, future: F) -> F::Output {
301         let fut_size = mem::size_of::<F>();
302         if fut_size > BOX_FUTURE_THRESHOLD {
303             self.block_on_inner(Box::pin(future), SpawnMeta::new_unnamed(fut_size))
304         } else {
305             self.block_on_inner(future, SpawnMeta::new_unnamed(fut_size))
306         }
307     }
308 
309     #[track_caller]
block_on_inner<F: Future>(&self, future: F, _meta: SpawnMeta<'_>) -> F::Output310     fn block_on_inner<F: Future>(&self, future: F, _meta: SpawnMeta<'_>) -> F::Output {
311         #[cfg(all(
312             tokio_unstable,
313             tokio_taskdump,
314             feature = "rt",
315             target_os = "linux",
316             any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
317         ))]
318         let future = super::task::trace::Trace::root(future);
319 
320         #[cfg(all(tokio_unstable, feature = "tracing"))]
321         let future =
322             crate::util::trace::task(future, "block_on", _meta, super::task::Id::next().as_u64());
323 
324         // Enter the runtime context. This sets the current driver handles and
325         // prevents blocking an existing runtime.
326         context::enter_runtime(&self.inner, true, |blocking| {
327             blocking.block_on(future).expect("failed to park thread")
328         })
329     }
330 
331     #[track_caller]
spawn_named<F>(&self, future: F, _meta: SpawnMeta<'_>) -> JoinHandle<F::Output> where F: Future + Send + 'static, F::Output: Send + 'static,332     pub(crate) fn spawn_named<F>(&self, future: F, _meta: SpawnMeta<'_>) -> JoinHandle<F::Output>
333     where
334         F: Future + Send + 'static,
335         F::Output: Send + 'static,
336     {
337         let id = crate::runtime::task::Id::next();
338         #[cfg(all(
339             tokio_unstable,
340             tokio_taskdump,
341             feature = "rt",
342             target_os = "linux",
343             any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
344         ))]
345         let future = super::task::trace::Trace::root(future);
346         #[cfg(all(tokio_unstable, feature = "tracing"))]
347         let future = crate::util::trace::task(future, "task", _meta, id.as_u64());
348         self.inner.spawn(future, id)
349     }
350 
351     #[track_caller]
352     #[allow(dead_code)]
spawn_local_named<F>( &self, future: F, _meta: SpawnMeta<'_>, ) -> JoinHandle<F::Output> where F: Future + 'static, F::Output: 'static,353     pub(crate) unsafe fn spawn_local_named<F>(
354         &self,
355         future: F,
356         _meta: SpawnMeta<'_>,
357     ) -> JoinHandle<F::Output>
358     where
359         F: Future + 'static,
360         F::Output: 'static,
361     {
362         let id = crate::runtime::task::Id::next();
363         #[cfg(all(
364             tokio_unstable,
365             tokio_taskdump,
366             feature = "rt",
367             target_os = "linux",
368             any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
369         ))]
370         let future = super::task::trace::Trace::root(future);
371         #[cfg(all(tokio_unstable, feature = "tracing"))]
372         let future = crate::util::trace::task(future, "task", _meta, id.as_u64());
373         self.inner.spawn_local(future, id)
374     }
375 
376     /// Returns the flavor of the current `Runtime`.
377     ///
378     /// # Examples
379     ///
380     /// ```
381     /// use tokio::runtime::{Handle, RuntimeFlavor};
382     ///
383     /// #[tokio::main(flavor = "current_thread")]
384     /// async fn main() {
385     ///   assert_eq!(RuntimeFlavor::CurrentThread, Handle::current().runtime_flavor());
386     /// }
387     /// ```
388     ///
389     /// ```
390     /// use tokio::runtime::{Handle, RuntimeFlavor};
391     ///
392     /// #[tokio::main(flavor = "multi_thread", worker_threads = 4)]
393     /// async fn main() {
394     ///   assert_eq!(RuntimeFlavor::MultiThread, Handle::current().runtime_flavor());
395     /// }
396     /// ```
runtime_flavor(&self) -> RuntimeFlavor397     pub fn runtime_flavor(&self) -> RuntimeFlavor {
398         match self.inner {
399             scheduler::Handle::CurrentThread(_) => RuntimeFlavor::CurrentThread,
400             #[cfg(feature = "rt-multi-thread")]
401             scheduler::Handle::MultiThread(_) => RuntimeFlavor::MultiThread,
402             #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
403             scheduler::Handle::MultiThreadAlt(_) => RuntimeFlavor::MultiThreadAlt,
404         }
405     }
406 
407     cfg_unstable! {
408         /// Returns the [`Id`] of the current `Runtime`.
409         ///
410         /// # Examples
411         ///
412         /// ```
413         /// use tokio::runtime::Handle;
414         ///
415         /// #[tokio::main(flavor = "current_thread")]
416         /// async fn main() {
417         ///   println!("Current runtime id: {}", Handle::current().id());
418         /// }
419         /// ```
420         ///
421         /// **Note**: This is an [unstable API][unstable]. The public API of this type
422         /// may break in 1.x releases. See [the documentation on unstable
423         /// features][unstable] for details.
424         ///
425         /// [unstable]: crate#unstable-features
426         /// [`Id`]: struct@crate::runtime::Id
427         pub fn id(&self) -> runtime::Id {
428             let owned_id = match &self.inner {
429                 scheduler::Handle::CurrentThread(handle) => handle.owned_id(),
430                 #[cfg(feature = "rt-multi-thread")]
431                 scheduler::Handle::MultiThread(handle) => handle.owned_id(),
432                 #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
433                 scheduler::Handle::MultiThreadAlt(handle) => handle.owned_id(),
434             };
435             owned_id.into()
436         }
437     }
438 
439     /// Returns a view that lets you get information about how the runtime
440     /// is performing.
metrics(&self) -> RuntimeMetrics441     pub fn metrics(&self) -> RuntimeMetrics {
442         RuntimeMetrics::new(self.clone())
443     }
444 }
445 
446 cfg_taskdump! {
447     impl Handle {
448         /// Captures a snapshot of the runtime's state.
449         ///
450         /// This functionality is experimental, and comes with a number of
451         /// requirements and limitations.
452         ///
453         /// # Examples
454         ///
455         /// This can be used to get call traces of each task in the runtime.
456         /// Calls to `Handle::dump` should usually be enclosed in a
457         /// [timeout][crate::time::timeout], so that dumping does not escalate a
458         /// single blocked runtime thread into an entirely blocked runtime.
459         ///
460         /// ```
461         /// # use tokio::runtime::Runtime;
462         /// # fn dox() {
463         /// # let rt = Runtime::new().unwrap();
464         /// # rt.spawn(async {
465         /// use tokio::runtime::Handle;
466         /// use tokio::time::{timeout, Duration};
467         ///
468         /// // Inside an async block or function.
469         /// let handle = Handle::current();
470         /// if let Ok(dump) = timeout(Duration::from_secs(2), handle.dump()).await {
471         ///     for (i, task) in dump.tasks().iter().enumerate() {
472         ///         let trace = task.trace();
473         ///         println!("TASK {i}:");
474         ///         println!("{trace}\n");
475         ///     }
476         /// }
477         /// # });
478         /// # }
479         /// ```
480         ///
481         /// This produces highly detailed traces of tasks; e.g.:
482         ///
483         /// ```plain
484         /// TASK 0:
485         /// ╼ dump::main::{{closure}}::a::{{closure}} at /tokio/examples/dump.rs:18:20
486         /// └╼ dump::main::{{closure}}::b::{{closure}} at /tokio/examples/dump.rs:23:20
487         ///    └╼ dump::main::{{closure}}::c::{{closure}} at /tokio/examples/dump.rs:28:24
488         ///       └╼ tokio::sync::barrier::Barrier::wait::{{closure}} at /tokio/tokio/src/sync/barrier.rs:129:10
489         ///          └╼ <tokio::util::trace::InstrumentedAsyncOp<F> as core::future::future::Future>::poll at /tokio/tokio/src/util/trace.rs:77:46
490         ///             └╼ tokio::sync::barrier::Barrier::wait_internal::{{closure}} at /tokio/tokio/src/sync/barrier.rs:183:36
491         ///                └╼ tokio::sync::watch::Receiver<T>::changed::{{closure}} at /tokio/tokio/src/sync/watch.rs:604:55
492         ///                   └╼ tokio::sync::watch::changed_impl::{{closure}} at /tokio/tokio/src/sync/watch.rs:755:18
493         ///                      └╼ <tokio::sync::notify::Notified as core::future::future::Future>::poll at /tokio/tokio/src/sync/notify.rs:1103:9
494         ///                         └╼ tokio::sync::notify::Notified::poll_notified at /tokio/tokio/src/sync/notify.rs:996:32
495         /// ```
496         ///
497         /// # Requirements
498         ///
499         /// ## Debug Info Must Be Available
500         ///
501         /// To produce task traces, the application must **not** be compiled
502         /// with `split debuginfo`. On Linux, including `debuginfo` within the
503         /// application binary is the (correct) default. You can further ensure
504         /// this behavior with the following directive in your `Cargo.toml`:
505         ///
506         /// ```toml
507         /// [profile.*]
508         /// split-debuginfo = "off"
509         /// ```
510         ///
511         /// ## Unstable Features
512         ///
513         /// This functionality is **unstable**, and requires both the
514         /// `tokio_unstable` and `tokio_taskdump` `cfg` flags to be set.
515         ///
516         /// You can do this by setting the `RUSTFLAGS` environment variable
517         /// before invoking `cargo`; e.g.:
518         /// ```bash
519         /// RUSTFLAGS="--cfg tokio_unstable --cfg tokio_taskdump" cargo run --example dump
520         /// ```
521         ///
522         /// Or by [configuring][cargo-config] `rustflags` in
523         /// `.cargo/config.toml`:
524         /// ```text
525         /// [build]
526         /// rustflags = ["--cfg", "tokio_unstable", "--cfg", "tokio_taskdump"]
527         /// ```
528         ///
529         /// [cargo-config]:
530         ///     https://doc.rust-lang.org/cargo/reference/config.html
531         ///
532         /// ## Platform Requirements
533         ///
534         /// Task dumps are supported on Linux atop `aarch64`, `x86` and `x86_64`.
535         ///
536         /// ## Current Thread Runtime Requirements
537         ///
538         /// On the `current_thread` runtime, task dumps may only be requested
539         /// from *within* the context of the runtime being dumped. Do not, for
540         /// example, await `Handle::dump()` on a different runtime.
541         ///
542         /// # Limitations
543         ///
544         /// ## Performance
545         ///
546         /// Although enabling the `tokio_taskdump` feature imposes virtually no
547         /// additional runtime overhead, actually calling `Handle::dump` is
548         /// expensive. The runtime must synchronize and pause its workers, then
549         /// re-poll every task in a special tracing mode. Avoid requesting dumps
550         /// often.
551         ///
552         /// ## Local Executors
553         ///
554         /// Tasks managed by local executors (e.g., `FuturesUnordered` and
555         /// [`LocalSet`][crate::task::LocalSet]) may not appear in task dumps.
556         ///
557         /// ## Non-Termination When Workers Are Blocked
558         ///
559         /// The future produced by `Handle::dump` may never produce `Ready` if
560         /// another runtime worker is blocked for more than 250ms. This may
561         /// occur if a dump is requested during shutdown, or if another runtime
562         /// worker is infinite looping or synchronously deadlocked. For these
563         /// reasons, task dumping should usually be paired with an explicit
564         /// [timeout][crate::time::timeout].
565         pub async fn dump(&self) -> crate::runtime::Dump {
566             match &self.inner {
567                 scheduler::Handle::CurrentThread(handle) => handle.dump(),
568                 #[cfg(all(feature = "rt-multi-thread", not(target_os = "wasi")))]
569                 scheduler::Handle::MultiThread(handle) => {
570                     // perform the trace in a separate thread so that the
571                     // trace itself does not appear in the taskdump.
572                     let handle = handle.clone();
573                     spawn_thread(async {
574                         let handle = handle;
575                         handle.dump().await
576                     }).await
577                 },
578                 #[cfg(all(tokio_unstable, feature = "rt-multi-thread", not(target_os = "wasi")))]
579                 scheduler::Handle::MultiThreadAlt(_) => panic!("task dump not implemented for this runtime flavor"),
580             }
581         }
582 
583         /// Produces `true` if the current task is being traced for a dump;
584         /// otherwise false. This function is only public for integration
585         /// testing purposes. Do not rely on it.
586         #[doc(hidden)]
587         pub fn is_tracing() -> bool {
588             super::task::trace::Context::is_tracing()
589         }
590     }
591 
592     cfg_rt_multi_thread! {
593         /// Spawn a new thread and asynchronously await on its result.
594         async fn spawn_thread<F>(f: F) -> <F as Future>::Output
595         where
596             F: Future + Send + 'static,
597             <F as Future>::Output: Send + 'static
598         {
599             let (tx, rx) = crate::sync::oneshot::channel();
600             crate::loom::thread::spawn(|| {
601                 let rt = crate::runtime::Builder::new_current_thread().build().unwrap();
602                 rt.block_on(async {
603                     let _ = tx.send(f.await);
604                 });
605             });
606             rx.await.unwrap()
607         }
608     }
609 }
610 
611 /// Error returned by `try_current` when no Runtime has been started
612 #[derive(Debug)]
613 pub struct TryCurrentError {
614     kind: TryCurrentErrorKind,
615 }
616 
617 impl TryCurrentError {
new_no_context() -> Self618     pub(crate) fn new_no_context() -> Self {
619         Self {
620             kind: TryCurrentErrorKind::NoContext,
621         }
622     }
623 
new_thread_local_destroyed() -> Self624     pub(crate) fn new_thread_local_destroyed() -> Self {
625         Self {
626             kind: TryCurrentErrorKind::ThreadLocalDestroyed,
627         }
628     }
629 
630     /// Returns true if the call failed because there is currently no runtime in
631     /// the Tokio context.
is_missing_context(&self) -> bool632     pub fn is_missing_context(&self) -> bool {
633         matches!(self.kind, TryCurrentErrorKind::NoContext)
634     }
635 
636     /// Returns true if the call failed because the Tokio context thread-local
637     /// had been destroyed. This can usually only happen if in the destructor of
638     /// other thread-locals.
is_thread_local_destroyed(&self) -> bool639     pub fn is_thread_local_destroyed(&self) -> bool {
640         matches!(self.kind, TryCurrentErrorKind::ThreadLocalDestroyed)
641     }
642 }
643 
644 enum TryCurrentErrorKind {
645     NoContext,
646     ThreadLocalDestroyed,
647 }
648 
649 impl fmt::Debug for TryCurrentErrorKind {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result650     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
651         match self {
652             TryCurrentErrorKind::NoContext => f.write_str("NoContext"),
653             TryCurrentErrorKind::ThreadLocalDestroyed => f.write_str("ThreadLocalDestroyed"),
654         }
655     }
656 }
657 
658 impl fmt::Display for TryCurrentError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result659     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
660         use TryCurrentErrorKind as E;
661         match self.kind {
662             E::NoContext => f.write_str(CONTEXT_MISSING_ERROR),
663             E::ThreadLocalDestroyed => f.write_str(THREAD_LOCAL_DESTROYED_ERROR),
664         }
665     }
666 }
667 
668 impl error::Error for TryCurrentError {}
669