use std::{env, error::Error, fmt, io, str::FromStr, thread};
mod bridge;
mod broadcast;
mod job;
mod join;
mod latch;
mod registry;
mod sleep;
mod sort;
mod spawn;
#[cfg(test)]
mod test;
mod thread_pool;
mod unwind;
pub use self::thread_pool::{ThreadPool, Yield};
#[cfg(test)]
pub(crate) use self::thread_pool::{current_thread_index, yield_now};
pub(crate) use self::{
bridge::{fold_init, map_collect_vec, map_init_collect_vec, try_fold, try_map_collect_vec},
join::join,
sort::{par_mergesort, par_quicksort},
};
pub(crate) fn current_num_threads() -> usize {
registry::Registry::current_num_threads()
}
struct SendPtr<T>(*mut T);
unsafe impl<T: Send> Send for SendPtr<T> {}
unsafe impl<T: Send> Sync for SendPtr<T> {}
impl<T> SendPtr<T> {
const fn get(self) -> *mut T {
self.0
}
}
impl<T> Clone for SendPtr<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for SendPtr<T> {}
#[derive(Debug)]
pub struct ThreadPoolBuildError {
kind: ErrorKind,
}
#[derive(Debug)]
enum ErrorKind {
CurrentThreadAlreadyInPool,
IOError(io::Error),
}
pub struct ThreadPoolBuilder {
num_threads: usize,
use_current_thread: bool,
get_thread_name: Option<Box<dyn FnMut(usize) -> String>>,
stack_size: Option<usize>,
start_handler: Option<Box<StartHandler>>,
start_threads: bool,
}
type StartHandler = dyn Fn(usize) + Send + Sync;
impl Default for ThreadPoolBuilder {
fn default() -> Self {
Self {
num_threads: 0,
use_current_thread: false,
get_thread_name: None,
stack_size: None,
start_handler: None,
start_threads: true,
}
}
}
impl ThreadPoolBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn build(self) -> Result<ThreadPool, ThreadPoolBuildError> {
ThreadPool::build(self)
}
fn get_num_threads(&self) -> usize {
if self.num_threads > 0 {
self.num_threads
} else {
let default = || {
thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1)
};
match env::var("RAYON_NUM_THREADS")
.ok()
.and_then(|s| usize::from_str(&s).ok())
{
Some(x @ 1..) => return x,
Some(0) => return default(),
_ => {}
}
match env::var("RAYON_RS_NUM_CPUS")
.ok()
.and_then(|s| usize::from_str(&s).ok())
{
Some(x @ 1..) => x,
_ => default(),
}
}
}
fn get_thread_name(&mut self, index: usize) -> Option<String> {
let f = self.get_thread_name.as_mut()?;
Some(f(index))
}
pub fn thread_name<F>(mut self, closure: F) -> Self
where
F: FnMut(usize) -> String + 'static,
{
self.get_thread_name = Some(Box::new(closure));
self
}
pub const fn num_threads(mut self, num_threads: usize) -> Self {
self.num_threads = num_threads;
self
}
pub const fn use_current_thread(mut self) -> Self {
self.use_current_thread = true;
self
}
const fn get_stack_size(&self) -> Option<usize> {
self.stack_size
}
pub const fn stack_size(mut self, stack_size: usize) -> Self {
self.stack_size = Some(stack_size);
self
}
const fn take_start_handler(&mut self) -> Option<Box<StartHandler>> {
self.start_handler.take()
}
pub fn start_handler<H>(mut self, start_handler: H) -> Self
where
H: Fn(usize) + Send + Sync + 'static,
{
self.start_handler = Some(Box::new(start_handler));
self
}
#[cfg(any(test, feature = "test-utils"))]
pub(crate) const fn unstarted_workers(mut self) -> Self {
self.start_threads = false;
self
}
}
impl ThreadPoolBuildError {
const fn new(kind: ErrorKind) -> Self {
Self { kind }
}
}
const CURRENT_THREAD_ALREADY_IN_POOL: &str =
"The current thread is already part of another thread pool.";
impl Error for ThreadPoolBuildError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.kind {
ErrorKind::CurrentThreadAlreadyInPool => None,
ErrorKind::IOError(e) => Some(e),
}
}
}
impl fmt::Display for ThreadPoolBuildError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
ErrorKind::CurrentThreadAlreadyInPool => CURRENT_THREAD_ALREADY_IN_POOL.fmt(f),
ErrorKind::IOError(e) => e.fmt(f),
}
}
}
impl fmt::Debug for ThreadPoolBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
ref num_threads,
ref use_current_thread,
ref get_thread_name,
ref stack_size,
ref start_handler,
ref start_threads,
} = *self;
struct ClosurePlaceholder;
impl fmt::Debug for ClosurePlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<closure>")
}
}
let get_thread_name = get_thread_name.as_ref().map(|_| ClosurePlaceholder);
let start_handler = start_handler.as_ref().map(|_| ClosurePlaceholder);
f.debug_struct("ThreadPoolBuilder")
.field("num_threads", num_threads)
.field("use_current_thread", use_current_thread)
.field("get_thread_name", &get_thread_name)
.field("stack_size", &stack_size)
.field("start_handler", &start_handler)
.field("start_threads", start_threads)
.finish()
}
}