]> git.proxmox.com Git - rustc.git/blob - vendor/rayon-core/src/lib.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / vendor / rayon-core / src / lib.rs
1 //! Rayon-core houses the core stable APIs of Rayon.
2 //!
3 //! These APIs have been mirrored in the Rayon crate and it is recommended to use these from there.
4 //!
5 //! [`join`] is used to take two closures and potentially run them in parallel.
6 //! - It will run in parallel if task B gets stolen before task A can finish.
7 //! - It will run sequentially if task A finishes before task B is stolen and can continue on task B.
8 //!
9 //! [`scope`] creates a scope in which you can run any number of parallel tasks.
10 //! These tasks can spawn nested tasks and scopes, but given the nature of work stealing, the order of execution can not be guaranteed.
11 //! The scope will exist until all tasks spawned within the scope have been completed.
12 //!
13 //! [`spawn`] add a task into the 'static' or 'global' scope, or a local scope created by the [`scope()`] function.
14 //!
15 //! [`ThreadPool`] can be used to create your own thread pools (using [`ThreadPoolBuilder`]) or to customize the global one.
16 //! Tasks spawned within the pool (using [`install()`], [`join()`], etc.) will be added to a deque,
17 //! where it becomes available for work stealing from other threads in the local threadpool.
18 //!
19 //! [`join`]: fn.join.html
20 //! [`scope`]: fn.scope.html
21 //! [`scope()`]: fn.scope.html
22 //! [`spawn`]: fn.spawn.html
23 //! [`ThreadPool`]: struct.threadpool.html
24 //! [`install()`]: struct.ThreadPool.html#method.install
25 //! [`spawn()`]: struct.ThreadPool.html#method.spawn
26 //! [`join()`]: struct.ThreadPool.html#method.join
27 //! [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html
28 //!
29 //! ## Restricting multiple versions
30 //!
31 //! In order to ensure proper coordination between threadpools, and especially
32 //! to make sure there's only one global threadpool, `rayon-core` is actively
33 //! restricted from building multiple versions of itself into a single target.
34 //! You may see a build error like this in violation:
35 //!
36 //! ```text
37 //! error: native library `rayon-core` is being linked to by more
38 //! than one package, and can only be linked to by one package
39 //! ```
40 //!
41 //! While we strive to keep `rayon-core` semver-compatible, it's still
42 //! possible to arrive at this situation if different crates have overly
43 //! restrictive tilde or inequality requirements for `rayon-core`. The
44 //! conflicting requirements will need to be resolved before the build will
45 //! succeed.
46
47 #![doc(html_root_url = "https://docs.rs/rayon-core/1.9")]
48 #![deny(missing_debug_implementations)]
49 #![deny(missing_docs)]
50 #![deny(unreachable_pub)]
51 #![warn(rust_2018_idioms)]
52
53 use std::any::Any;
54 use std::env;
55 use std::error::Error;
56 use std::fmt;
57 use std::io;
58 use std::marker::PhantomData;
59 use std::str::FromStr;
60
61 #[macro_use]
62 mod log;
63 #[macro_use]
64 mod private;
65
66 mod job;
67 mod join;
68 mod latch;
69 mod registry;
70 mod scope;
71 mod sleep;
72 mod spawn;
73 mod thread_pool;
74 mod unwind;
75
76 mod compile_fail;
77 mod test;
78
79 pub use self::join::{join, join_context};
80 pub use self::registry::ThreadBuilder;
81 pub use self::scope::{in_place_scope, scope, Scope};
82 pub use self::scope::{in_place_scope_fifo, scope_fifo, ScopeFifo};
83 pub use self::spawn::{spawn, spawn_fifo};
84 pub use self::thread_pool::current_thread_has_pending_tasks;
85 pub use self::thread_pool::current_thread_index;
86 pub use self::thread_pool::ThreadPool;
87
88 use self::registry::{CustomSpawn, DefaultSpawn, ThreadSpawn};
89
90 /// Returns the maximum number of threads that Rayon supports in a single thread-pool.
91 ///
92 /// If a higher thread count is requested by calling `ThreadPoolBuilder::num_threads` or by setting
93 /// the `RAYON_NUM_THREADS` environment variable, then it will be reduced to this maximum.
94 ///
95 /// The value may vary between different targets, and is subject to change in new Rayon versions.
96 pub fn max_num_threads() -> usize {
97 // We are limited by the bits available in the sleep counter's `AtomicUsize`.
98 crate::sleep::THREADS_MAX
99 }
100
101 /// Returns the number of threads in the current registry. If this
102 /// code is executing within a Rayon thread-pool, then this will be
103 /// the number of threads for the thread-pool of the current
104 /// thread. Otherwise, it will be the number of threads for the global
105 /// thread-pool.
106 ///
107 /// This can be useful when trying to judge how many times to split
108 /// parallel work (the parallel iterator traits use this value
109 /// internally for this purpose).
110 ///
111 /// # Future compatibility note
112 ///
113 /// Note that unless this thread-pool was created with a
114 /// builder that specifies the number of threads, then this
115 /// number may vary over time in future versions (see [the
116 /// `num_threads()` method for details][snt]).
117 ///
118 /// [snt]: struct.ThreadPoolBuilder.html#method.num_threads
119 pub fn current_num_threads() -> usize {
120 crate::registry::Registry::current_num_threads()
121 }
122
123 /// Error when initializing a thread pool.
124 #[derive(Debug)]
125 pub struct ThreadPoolBuildError {
126 kind: ErrorKind,
127 }
128
129 #[derive(Debug)]
130 enum ErrorKind {
131 GlobalPoolAlreadyInitialized,
132 IOError(io::Error),
133 }
134
135 /// Used to create a new [`ThreadPool`] or to configure the global rayon thread pool.
136 /// ## Creating a ThreadPool
137 /// The following creates a thread pool with 22 threads.
138 ///
139 /// ```rust
140 /// # use rayon_core as rayon;
141 /// let pool = rayon::ThreadPoolBuilder::new().num_threads(22).build().unwrap();
142 /// ```
143 ///
144 /// To instead configure the global thread pool, use [`build_global()`]:
145 ///
146 /// ```rust
147 /// # use rayon_core as rayon;
148 /// rayon::ThreadPoolBuilder::new().num_threads(22).build_global().unwrap();
149 /// ```
150 ///
151 /// [`ThreadPool`]: struct.ThreadPool.html
152 /// [`build_global()`]: struct.ThreadPoolBuilder.html#method.build_global
153 pub struct ThreadPoolBuilder<S = DefaultSpawn> {
154 /// The number of threads in the rayon thread pool.
155 /// If zero will use the RAYON_NUM_THREADS environment variable.
156 /// If RAYON_NUM_THREADS is invalid or zero will use the default.
157 num_threads: usize,
158
159 /// Custom closure, if any, to handle a panic that we cannot propagate
160 /// anywhere else.
161 panic_handler: Option<Box<PanicHandler>>,
162
163 /// Closure to compute the name of a thread.
164 get_thread_name: Option<Box<dyn FnMut(usize) -> String>>,
165
166 /// The stack size for the created worker threads
167 stack_size: Option<usize>,
168
169 /// Closure invoked on worker thread start.
170 start_handler: Option<Box<StartHandler>>,
171
172 /// Closure invoked on worker thread exit.
173 exit_handler: Option<Box<ExitHandler>>,
174
175 /// Closure invoked to spawn threads.
176 spawn_handler: S,
177
178 /// If false, worker threads will execute spawned jobs in a
179 /// "depth-first" fashion. If true, they will do a "breadth-first"
180 /// fashion. Depth-first is the default.
181 breadth_first: bool,
182 }
183
184 /// Contains the rayon thread pool configuration. Use [`ThreadPoolBuilder`] instead.
185 ///
186 /// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html
187 #[deprecated(note = "Use `ThreadPoolBuilder`")]
188 pub struct Configuration {
189 builder: ThreadPoolBuilder,
190 }
191
192 /// The type for a panic handling closure. Note that this same closure
193 /// may be invoked multiple times in parallel.
194 type PanicHandler = dyn Fn(Box<dyn Any + Send>) + Send + Sync;
195
196 /// The type for a closure that gets invoked when a thread starts. The
197 /// closure is passed the index of the thread on which it is invoked.
198 /// Note that this same closure may be invoked multiple times in parallel.
199 type StartHandler = dyn Fn(usize) + Send + Sync;
200
201 /// The type for a closure that gets invoked when a thread exits. The
202 /// closure is passed the index of the thread on which is is invoked.
203 /// Note that this same closure may be invoked multiple times in parallel.
204 type ExitHandler = dyn Fn(usize) + Send + Sync;
205
206 // NB: We can't `#[derive(Default)]` because `S` is left ambiguous.
207 impl Default for ThreadPoolBuilder {
208 fn default() -> Self {
209 ThreadPoolBuilder {
210 num_threads: 0,
211 panic_handler: None,
212 get_thread_name: None,
213 stack_size: None,
214 start_handler: None,
215 exit_handler: None,
216 spawn_handler: DefaultSpawn,
217 breadth_first: false,
218 }
219 }
220 }
221
222 impl ThreadPoolBuilder {
223 /// Creates and returns a valid rayon thread pool builder, but does not initialize it.
224 pub fn new() -> Self {
225 Self::default()
226 }
227 }
228
229 /// Note: the `S: ThreadSpawn` constraint is an internal implementation detail for the
230 /// default spawn and those set by [`spawn_handler`](#method.spawn_handler).
231 impl<S> ThreadPoolBuilder<S>
232 where
233 S: ThreadSpawn,
234 {
235 /// Creates a new `ThreadPool` initialized using this configuration.
236 pub fn build(self) -> Result<ThreadPool, ThreadPoolBuildError> {
237 ThreadPool::build(self)
238 }
239
240 /// Initializes the global thread pool. This initialization is
241 /// **optional**. If you do not call this function, the thread pool
242 /// will be automatically initialized with the default
243 /// configuration. Calling `build_global` is not recommended, except
244 /// in two scenarios:
245 ///
246 /// - You wish to change the default configuration.
247 /// - You are running a benchmark, in which case initializing may
248 /// yield slightly more consistent results, since the worker threads
249 /// will already be ready to go even in the first iteration. But
250 /// this cost is minimal.
251 ///
252 /// Initialization of the global thread pool happens exactly
253 /// once. Once started, the configuration cannot be
254 /// changed. Therefore, if you call `build_global` a second time, it
255 /// will return an error. An `Ok` result indicates that this
256 /// is the first initialization of the thread pool.
257 pub fn build_global(self) -> Result<(), ThreadPoolBuildError> {
258 let registry = registry::init_global_registry(self)?;
259 registry.wait_until_primed();
260 Ok(())
261 }
262 }
263
264 impl ThreadPoolBuilder {
265 /// Creates a scoped `ThreadPool` initialized using this configuration.
266 ///
267 /// This is a convenience function for building a pool using [`crossbeam::scope`]
268 /// to spawn threads in a [`spawn_handler`](#method.spawn_handler).
269 /// The threads in this pool will start by calling `wrapper`, which should
270 /// do initialization and continue by calling `ThreadBuilder::run()`.
271 ///
272 /// [`crossbeam::scope`]: https://docs.rs/crossbeam/0.7/crossbeam/fn.scope.html
273 ///
274 /// # Examples
275 ///
276 /// A scoped pool may be useful in combination with scoped thread-local variables.
277 ///
278 /// ```
279 /// # use rayon_core as rayon;
280 ///
281 /// scoped_tls::scoped_thread_local!(static POOL_DATA: Vec<i32>);
282 ///
283 /// fn main() -> Result<(), rayon::ThreadPoolBuildError> {
284 /// let pool_data = vec![1, 2, 3];
285 ///
286 /// // We haven't assigned any TLS data yet.
287 /// assert!(!POOL_DATA.is_set());
288 ///
289 /// rayon::ThreadPoolBuilder::new()
290 /// .build_scoped(
291 /// // Borrow `pool_data` in TLS for each thread.
292 /// |thread| POOL_DATA.set(&pool_data, || thread.run()),
293 /// // Do some work that needs the TLS data.
294 /// |pool| pool.install(|| assert!(POOL_DATA.is_set())),
295 /// )?;
296 ///
297 /// // Once we've returned, `pool_data` is no longer borrowed.
298 /// drop(pool_data);
299 /// Ok(())
300 /// }
301 /// ```
302 pub fn build_scoped<W, F, R>(self, wrapper: W, with_pool: F) -> Result<R, ThreadPoolBuildError>
303 where
304 W: Fn(ThreadBuilder) + Sync, // expected to call `run()`
305 F: FnOnce(&ThreadPool) -> R,
306 {
307 let result = crossbeam_utils::thread::scope(|scope| {
308 let wrapper = &wrapper;
309 let pool = self
310 .spawn_handler(|thread| {
311 let mut builder = scope.builder();
312 if let Some(name) = thread.name() {
313 builder = builder.name(name.to_string());
314 }
315 if let Some(size) = thread.stack_size() {
316 builder = builder.stack_size(size);
317 }
318 builder.spawn(move |_| wrapper(thread))?;
319 Ok(())
320 })
321 .build()?;
322 Ok(with_pool(&pool))
323 });
324
325 match result {
326 Ok(result) => result,
327 Err(err) => unwind::resume_unwinding(err),
328 }
329 }
330 }
331
332 impl<S> ThreadPoolBuilder<S> {
333 /// Sets a custom function for spawning threads.
334 ///
335 /// Note that the threads will not exit until after the pool is dropped. It
336 /// is up to the caller to wait for thread termination if that is important
337 /// for any invariants. For instance, threads created in [`crossbeam::scope`]
338 /// will be joined before that scope returns, and this will block indefinitely
339 /// if the pool is leaked. Furthermore, the global thread pool doesn't terminate
340 /// until the entire process exits!
341 ///
342 /// [`crossbeam::scope`]: https://docs.rs/crossbeam/0.7/crossbeam/fn.scope.html
343 ///
344 /// # Examples
345 ///
346 /// A minimal spawn handler just needs to call `run()` from an independent thread.
347 ///
348 /// ```
349 /// # use rayon_core as rayon;
350 /// fn main() -> Result<(), rayon::ThreadPoolBuildError> {
351 /// let pool = rayon::ThreadPoolBuilder::new()
352 /// .spawn_handler(|thread| {
353 /// std::thread::spawn(|| thread.run());
354 /// Ok(())
355 /// })
356 /// .build()?;
357 ///
358 /// pool.install(|| println!("Hello from my custom thread!"));
359 /// Ok(())
360 /// }
361 /// ```
362 ///
363 /// The default spawn handler sets the name and stack size if given, and propagates
364 /// any errors from the thread builder.
365 ///
366 /// ```
367 /// # use rayon_core as rayon;
368 /// fn main() -> Result<(), rayon::ThreadPoolBuildError> {
369 /// let pool = rayon::ThreadPoolBuilder::new()
370 /// .spawn_handler(|thread| {
371 /// let mut b = std::thread::Builder::new();
372 /// if let Some(name) = thread.name() {
373 /// b = b.name(name.to_owned());
374 /// }
375 /// if let Some(stack_size) = thread.stack_size() {
376 /// b = b.stack_size(stack_size);
377 /// }
378 /// b.spawn(|| thread.run())?;
379 /// Ok(())
380 /// })
381 /// .build()?;
382 ///
383 /// pool.install(|| println!("Hello from my fully custom thread!"));
384 /// Ok(())
385 /// }
386 /// ```
387 pub fn spawn_handler<F>(self, spawn: F) -> ThreadPoolBuilder<CustomSpawn<F>>
388 where
389 F: FnMut(ThreadBuilder) -> io::Result<()>,
390 {
391 ThreadPoolBuilder {
392 spawn_handler: CustomSpawn::new(spawn),
393 // ..self
394 num_threads: self.num_threads,
395 panic_handler: self.panic_handler,
396 get_thread_name: self.get_thread_name,
397 stack_size: self.stack_size,
398 start_handler: self.start_handler,
399 exit_handler: self.exit_handler,
400 breadth_first: self.breadth_first,
401 }
402 }
403
404 /// Returns a reference to the current spawn handler.
405 fn get_spawn_handler(&mut self) -> &mut S {
406 &mut self.spawn_handler
407 }
408
409 /// Get the number of threads that will be used for the thread
410 /// pool. See `num_threads()` for more information.
411 fn get_num_threads(&self) -> usize {
412 if self.num_threads > 0 {
413 self.num_threads
414 } else {
415 match env::var("RAYON_NUM_THREADS")
416 .ok()
417 .and_then(|s| usize::from_str(&s).ok())
418 {
419 Some(x) if x > 0 => return x,
420 Some(x) if x == 0 => return num_cpus::get(),
421 _ => {}
422 }
423
424 // Support for deprecated `RAYON_RS_NUM_CPUS`.
425 match env::var("RAYON_RS_NUM_CPUS")
426 .ok()
427 .and_then(|s| usize::from_str(&s).ok())
428 {
429 Some(x) if x > 0 => x,
430 _ => num_cpus::get(),
431 }
432 }
433 }
434
435 /// Get the thread name for the thread with the given index.
436 fn get_thread_name(&mut self, index: usize) -> Option<String> {
437 let f = self.get_thread_name.as_mut()?;
438 Some(f(index))
439 }
440
441 /// Sets a closure which takes a thread index and returns
442 /// the thread's name.
443 pub fn thread_name<F>(mut self, closure: F) -> Self
444 where
445 F: FnMut(usize) -> String + 'static,
446 {
447 self.get_thread_name = Some(Box::new(closure));
448 self
449 }
450
451 /// Sets the number of threads to be used in the rayon threadpool.
452 ///
453 /// If you specify a non-zero number of threads using this
454 /// function, then the resulting thread-pools are guaranteed to
455 /// start at most this number of threads.
456 ///
457 /// If `num_threads` is 0, or you do not call this function, then
458 /// the Rayon runtime will select the number of threads
459 /// automatically. At present, this is based on the
460 /// `RAYON_NUM_THREADS` environment variable (if set),
461 /// or the number of logical CPUs (otherwise).
462 /// In the future, however, the default behavior may
463 /// change to dynamically add or remove threads as needed.
464 ///
465 /// **Future compatibility warning:** Given the default behavior
466 /// may change in the future, if you wish to rely on a fixed
467 /// number of threads, you should use this function to specify
468 /// that number. To reproduce the current default behavior, you
469 /// may wish to use the [`num_cpus`
470 /// crate](https://crates.io/crates/num_cpus) to query the number
471 /// of CPUs dynamically.
472 ///
473 /// **Old environment variable:** `RAYON_NUM_THREADS` is a one-to-one
474 /// replacement of the now deprecated `RAYON_RS_NUM_CPUS` environment
475 /// variable. If both variables are specified, `RAYON_NUM_THREADS` will
476 /// be preferred.
477 pub fn num_threads(mut self, num_threads: usize) -> Self {
478 self.num_threads = num_threads;
479 self
480 }
481
482 /// Returns a copy of the current panic handler.
483 fn take_panic_handler(&mut self) -> Option<Box<PanicHandler>> {
484 self.panic_handler.take()
485 }
486
487 /// Normally, whenever Rayon catches a panic, it tries to
488 /// propagate it to someplace sensible, to try and reflect the
489 /// semantics of sequential execution. But in some cases,
490 /// particularly with the `spawn()` APIs, there is no
491 /// obvious place where we should propagate the panic to.
492 /// In that case, this panic handler is invoked.
493 ///
494 /// If no panic handler is set, the default is to abort the
495 /// process, under the principle that panics should not go
496 /// unobserved.
497 ///
498 /// If the panic handler itself panics, this will abort the
499 /// process. To prevent this, wrap the body of your panic handler
500 /// in a call to `std::panic::catch_unwind()`.
501 pub fn panic_handler<H>(mut self, panic_handler: H) -> Self
502 where
503 H: Fn(Box<dyn Any + Send>) + Send + Sync + 'static,
504 {
505 self.panic_handler = Some(Box::new(panic_handler));
506 self
507 }
508
509 /// Get the stack size of the worker threads
510 fn get_stack_size(&self) -> Option<usize> {
511 self.stack_size
512 }
513
514 /// Sets the stack size of the worker threads
515 pub fn stack_size(mut self, stack_size: usize) -> Self {
516 self.stack_size = Some(stack_size);
517 self
518 }
519
520 /// **(DEPRECATED)** Suggest to worker threads that they execute
521 /// spawned jobs in a "breadth-first" fashion.
522 ///
523 /// Typically, when a worker thread is idle or blocked, it will
524 /// attempt to execute the job from the *top* of its local deque of
525 /// work (i.e., the job most recently spawned). If this flag is set
526 /// to true, however, workers will prefer to execute in a
527 /// *breadth-first* fashion -- that is, they will search for jobs at
528 /// the *bottom* of their local deque. (At present, workers *always*
529 /// steal from the bottom of other worker's deques, regardless of
530 /// the setting of this flag.)
531 ///
532 /// If you think of the tasks as a tree, where a parent task
533 /// spawns its children in the tree, then this flag loosely
534 /// corresponds to doing a breadth-first traversal of the tree,
535 /// whereas the default would be to do a depth-first traversal.
536 ///
537 /// **Note that this is an "execution hint".** Rayon's task
538 /// execution is highly dynamic and the precise order in which
539 /// independent tasks are executed is not intended to be
540 /// guaranteed.
541 ///
542 /// This `breadth_first()` method is now deprecated per [RFC #1],
543 /// and in the future its effect may be removed. Consider using
544 /// [`scope_fifo()`] for a similar effect.
545 ///
546 /// [RFC #1]: https://github.com/rayon-rs/rfcs/blob/master/accepted/rfc0001-scope-scheduling.md
547 /// [`scope_fifo()`]: fn.scope_fifo.html
548 #[deprecated(note = "use `scope_fifo` and `spawn_fifo` for similar effect")]
549 pub fn breadth_first(mut self) -> Self {
550 self.breadth_first = true;
551 self
552 }
553
554 fn get_breadth_first(&self) -> bool {
555 self.breadth_first
556 }
557
558 /// Takes the current thread start callback, leaving `None`.
559 fn take_start_handler(&mut self) -> Option<Box<StartHandler>> {
560 self.start_handler.take()
561 }
562
563 /// Sets a callback to be invoked on thread start.
564 ///
565 /// The closure is passed the index of the thread on which it is invoked.
566 /// Note that this same closure may be invoked multiple times in parallel.
567 /// If this closure panics, the panic will be passed to the panic handler.
568 /// If that handler returns, then startup will continue normally.
569 pub fn start_handler<H>(mut self, start_handler: H) -> Self
570 where
571 H: Fn(usize) + Send + Sync + 'static,
572 {
573 self.start_handler = Some(Box::new(start_handler));
574 self
575 }
576
577 /// Returns a current thread exit callback, leaving `None`.
578 fn take_exit_handler(&mut self) -> Option<Box<ExitHandler>> {
579 self.exit_handler.take()
580 }
581
582 /// Sets a callback to be invoked on thread exit.
583 ///
584 /// The closure is passed the index of the thread on which it is invoked.
585 /// Note that this same closure may be invoked multiple times in parallel.
586 /// If this closure panics, the panic will be passed to the panic handler.
587 /// If that handler returns, then the thread will exit normally.
588 pub fn exit_handler<H>(mut self, exit_handler: H) -> Self
589 where
590 H: Fn(usize) + Send + Sync + 'static,
591 {
592 self.exit_handler = Some(Box::new(exit_handler));
593 self
594 }
595 }
596
597 #[allow(deprecated)]
598 impl Configuration {
599 /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
600 pub fn new() -> Configuration {
601 Configuration {
602 builder: ThreadPoolBuilder::new(),
603 }
604 }
605
606 /// Deprecated in favor of `ThreadPoolBuilder::build`.
607 pub fn build(self) -> Result<ThreadPool, Box<dyn Error + 'static>> {
608 self.builder.build().map_err(Box::from)
609 }
610
611 /// Deprecated in favor of `ThreadPoolBuilder::thread_name`.
612 pub fn thread_name<F>(mut self, closure: F) -> Self
613 where
614 F: FnMut(usize) -> String + 'static,
615 {
616 self.builder = self.builder.thread_name(closure);
617 self
618 }
619
620 /// Deprecated in favor of `ThreadPoolBuilder::num_threads`.
621 pub fn num_threads(mut self, num_threads: usize) -> Configuration {
622 self.builder = self.builder.num_threads(num_threads);
623 self
624 }
625
626 /// Deprecated in favor of `ThreadPoolBuilder::panic_handler`.
627 pub fn panic_handler<H>(mut self, panic_handler: H) -> Configuration
628 where
629 H: Fn(Box<dyn Any + Send>) + Send + Sync + 'static,
630 {
631 self.builder = self.builder.panic_handler(panic_handler);
632 self
633 }
634
635 /// Deprecated in favor of `ThreadPoolBuilder::stack_size`.
636 pub fn stack_size(mut self, stack_size: usize) -> Self {
637 self.builder = self.builder.stack_size(stack_size);
638 self
639 }
640
641 /// Deprecated in favor of `ThreadPoolBuilder::breadth_first`.
642 pub fn breadth_first(mut self) -> Self {
643 self.builder = self.builder.breadth_first();
644 self
645 }
646
647 /// Deprecated in favor of `ThreadPoolBuilder::start_handler`.
648 pub fn start_handler<H>(mut self, start_handler: H) -> Configuration
649 where
650 H: Fn(usize) + Send + Sync + 'static,
651 {
652 self.builder = self.builder.start_handler(start_handler);
653 self
654 }
655
656 /// Deprecated in favor of `ThreadPoolBuilder::exit_handler`.
657 pub fn exit_handler<H>(mut self, exit_handler: H) -> Configuration
658 where
659 H: Fn(usize) + Send + Sync + 'static,
660 {
661 self.builder = self.builder.exit_handler(exit_handler);
662 self
663 }
664
665 /// Returns a ThreadPoolBuilder with identical parameters.
666 fn into_builder(self) -> ThreadPoolBuilder {
667 self.builder
668 }
669 }
670
671 impl ThreadPoolBuildError {
672 fn new(kind: ErrorKind) -> ThreadPoolBuildError {
673 ThreadPoolBuildError { kind }
674 }
675 }
676
677 const GLOBAL_POOL_ALREADY_INITIALIZED: &str =
678 "The global thread pool has already been initialized.";
679
680 impl Error for ThreadPoolBuildError {
681 #[allow(deprecated)]
682 fn description(&self) -> &str {
683 match self.kind {
684 ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED,
685 ErrorKind::IOError(ref e) => e.description(),
686 }
687 }
688
689 fn source(&self) -> Option<&(dyn Error + 'static)> {
690 match &self.kind {
691 ErrorKind::GlobalPoolAlreadyInitialized => None,
692 ErrorKind::IOError(e) => Some(e),
693 }
694 }
695 }
696
697 impl fmt::Display for ThreadPoolBuildError {
698 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699 match &self.kind {
700 ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED.fmt(f),
701 ErrorKind::IOError(e) => e.fmt(f),
702 }
703 }
704 }
705
706 /// Deprecated in favor of `ThreadPoolBuilder::build_global`.
707 #[deprecated(note = "use `ThreadPoolBuilder::build_global`")]
708 #[allow(deprecated)]
709 pub fn initialize(config: Configuration) -> Result<(), Box<dyn Error>> {
710 config.into_builder().build_global().map_err(Box::from)
711 }
712
713 impl<S> fmt::Debug for ThreadPoolBuilder<S> {
714 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
715 let ThreadPoolBuilder {
716 ref num_threads,
717 ref get_thread_name,
718 ref panic_handler,
719 ref stack_size,
720 ref start_handler,
721 ref exit_handler,
722 spawn_handler: _,
723 ref breadth_first,
724 } = *self;
725
726 // Just print `Some(<closure>)` or `None` to the debug
727 // output.
728 struct ClosurePlaceholder;
729 impl fmt::Debug for ClosurePlaceholder {
730 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
731 f.write_str("<closure>")
732 }
733 }
734 let get_thread_name = get_thread_name.as_ref().map(|_| ClosurePlaceholder);
735 let panic_handler = panic_handler.as_ref().map(|_| ClosurePlaceholder);
736 let start_handler = start_handler.as_ref().map(|_| ClosurePlaceholder);
737 let exit_handler = exit_handler.as_ref().map(|_| ClosurePlaceholder);
738
739 f.debug_struct("ThreadPoolBuilder")
740 .field("num_threads", num_threads)
741 .field("get_thread_name", &get_thread_name)
742 .field("panic_handler", &panic_handler)
743 .field("stack_size", &stack_size)
744 .field("start_handler", &start_handler)
745 .field("exit_handler", &exit_handler)
746 .field("breadth_first", &breadth_first)
747 .finish()
748 }
749 }
750
751 #[allow(deprecated)]
752 impl Default for Configuration {
753 fn default() -> Self {
754 Configuration {
755 builder: Default::default(),
756 }
757 }
758 }
759
760 #[allow(deprecated)]
761 impl fmt::Debug for Configuration {
762 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
763 self.builder.fmt(f)
764 }
765 }
766
767 /// Provides the calling context to a closure called by `join_context`.
768 #[derive(Debug)]
769 pub struct FnContext {
770 migrated: bool,
771
772 /// disable `Send` and `Sync`, just for a little future-proofing.
773 _marker: PhantomData<*mut ()>,
774 }
775
776 impl FnContext {
777 #[inline]
778 fn new(migrated: bool) -> Self {
779 FnContext {
780 migrated,
781 _marker: PhantomData,
782 }
783 }
784 }
785
786 impl FnContext {
787 /// Returns `true` if the closure was called from a different thread
788 /// than it was provided from.
789 #[inline]
790 pub fn migrated(&self) -> bool {
791 self.migrated
792 }
793 }