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