Skip to content

Commit

Permalink
core: Make use_current_thread error rather than panic when already in…
Browse files Browse the repository at this point in the history
… the pool.
  • Loading branch information
emilio committed Sep 20, 2023
1 parent f4db4d7 commit 40b59c0
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 6 deletions.
13 changes: 7 additions & 6 deletions rayon-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ pub struct ThreadPoolBuildError {
#[derive(Debug)]
enum ErrorKind {
GlobalPoolAlreadyInitialized,
CurrentThreadAlreadyInPool,
IOError(io::Error),
}

Expand Down Expand Up @@ -543,11 +544,6 @@ impl<S> ThreadPoolBuilder<S> {
/// the thread-pool will generally not be picked up automatically by this thread unless you
/// yield to rayon in some way, like via [`yield_now()`], [`yield_local()`], or [`scope()`].
///
/// # Panics
///
/// This function won't panic itself, but [`ThreadPoolBuilder::build()`] will panic if you've
/// called this function and the current thread is already part of another [`ThreadPool`].
///
/// # Local thread-pools
///
/// Using this in a local thread-pool means the registry will be leaked. In future versions
Expand Down Expand Up @@ -759,18 +755,22 @@ impl ThreadPoolBuildError {
const GLOBAL_POOL_ALREADY_INITIALIZED: &str =
"The global thread pool has already been initialized.";

const CURRENT_THREAD_ALREADY_IN_POOL: &str =
"The current thread is already part of another thread pool.";

impl Error for ThreadPoolBuildError {
#[allow(deprecated)]
fn description(&self) -> &str {
match self.kind {
ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED,
ErrorKind::CurrentThreadAlreadyInPool => CURRENT_THREAD_ALREADY_IN_POOL,
ErrorKind::IOError(ref e) => e.description(),
}
}

fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.kind {
ErrorKind::GlobalPoolAlreadyInitialized => None,
ErrorKind::GlobalPoolAlreadyInitialized | ErrorKind::CurrentThreadAlreadyInPool => None,
ErrorKind::IOError(e) => Some(e),
}
}
Expand All @@ -779,6 +779,7 @@ impl Error for ThreadPoolBuildError {
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::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED.fmt(f),
ErrorKind::IOError(e) => e.fmt(f),
}
Expand Down
5 changes: 5 additions & 0 deletions rayon-core/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@ impl Registry {
};

if index == 0 && builder.use_current_thread {
if !WorkerThread::current().is_null() {
return Err(ThreadPoolBuildError::new(
ErrorKind::CurrentThreadAlreadyInPool,
));
}
// Rather than starting a new thread, we're just taking over the current thread
// *without* running the main loop, so we can still return from here.
// The WorkerThread is leaked, but we never shutdown the global pool anyway.
Expand Down
9 changes: 9 additions & 0 deletions rayon-core/tests/use_current_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ fn use_current_thread_basic() {
"Should only spawn one extra thread"
);

let another_pool = ThreadPoolBuilder::new()
.num_threads(2)
.use_current_thread()
.build();
assert!(
another_pool.is_err(),
"Should error if the thread is already part of a pool"
);

let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = Arc::clone(&pair);
pool.spawn(move || {
Expand Down

0 comments on commit 40b59c0

Please sign in to comment.