Skip to content

Commit 249ad3f

Browse files
committed
Clear the current thread when WorkerThread drops
1 parent 7c4dcd9 commit 249ad3f

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

rayon-core/src/registry.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,16 @@ thread_local! {
613613
static WORKER_THREAD_STATE: Cell<*const WorkerThread> = Cell::new(ptr::null());
614614
}
615615

616+
impl Drop for WorkerThread {
617+
fn drop(&mut self) {
618+
// Undo `set_current`
619+
WORKER_THREAD_STATE.with(|t| {
620+
assert!(t.get().eq(&(self as *const _)));
621+
t.set(ptr::null());
622+
});
623+
}
624+
}
625+
616626
impl WorkerThread {
617627
/// Gets the `WorkerThread` index for the current thread; returns
618628
/// NULL if this is not a worker thread. This pointer is valid
@@ -771,14 +781,14 @@ impl WorkerThread {
771781
/// ////////////////////////////////////////////////////////////////////////
772782
773783
unsafe fn main_loop(worker: Worker<JobRef>, registry: Arc<Registry>, index: usize) {
774-
let worker_thread = WorkerThread {
784+
let worker_thread = &WorkerThread {
775785
worker,
776786
fifo: JobFifo::new(),
777787
index,
778788
rng: XorShift64Star::new(),
779789
registry: registry.clone(),
780790
};
781-
WorkerThread::set_current(&worker_thread);
791+
WorkerThread::set_current(worker_thread);
782792

783793
// let registry know we are ready to do work
784794
registry.thread_infos[index].primed.set();

rayon-core/src/test.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,36 @@ fn configuration() {
160160
fn default_pool() {
161161
ThreadPoolBuilder::default().build().unwrap();
162162
}
163+
164+
/// Test that custom spawned threads get their `WorkerThread` cleared once
165+
/// the pool is done with them, allowing them to be used with rayon again
166+
/// later. e.g. WebAssembly want to have their own pool of available threads.
167+
#[test]
168+
fn cleared_current_thread() -> Result<(), ThreadPoolBuildError> {
169+
let n_threads = 5;
170+
let mut handles = vec![];
171+
let pool = ThreadPoolBuilder::new()
172+
.num_threads(n_threads)
173+
.spawn_handler(|thread| {
174+
let handle = std::thread::spawn(move || {
175+
thread.run();
176+
177+
// Afterward, the current thread shouldn't be set anymore.
178+
assert_eq!(crate::current_thread_index(), None);
179+
});
180+
handles.push(handle);
181+
Ok(())
182+
})
183+
.build()?;
184+
assert_eq!(handles.len(), n_threads);
185+
186+
pool.install(|| assert!(crate::current_thread_index().is_some()));
187+
drop(pool);
188+
189+
// Wait for all threads to make their assertions and exit
190+
for handle in handles {
191+
handle.join().unwrap();
192+
}
193+
194+
Ok(())
195+
}

0 commit comments

Comments
 (0)