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