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