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