Skip to content

Commit 46fc17b

Browse files
committed
Auto merge of rust-lang#138702 - m-ou-se:spawn-in-atexit, r=Mark-Simulacrum
Allow spawning threads after TLS destruction Fixes rust-lang#138696
2 parents ecb170a + 3237b50 commit 46fc17b

File tree

2 files changed

+37
-9
lines changed

2 files changed

+37
-9
lines changed

library/std/src/thread/spawnhook.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,23 @@ where
113113
pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks {
114114
// Get a snapshot of the spawn hooks.
115115
// (Increments the refcount to the first node.)
116-
let hooks = SPAWN_HOOKS.with(|hooks| {
116+
if let Ok(hooks) = SPAWN_HOOKS.try_with(|hooks| {
117117
let snapshot = hooks.take();
118118
hooks.set(snapshot.clone());
119119
snapshot
120-
});
121-
// Iterate over the hooks, run them, and collect the results in a vector.
122-
let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref())
123-
.map(|hook| (hook.hook)(thread))
124-
.collect();
125-
// Pass on the snapshot of the hooks and the results to the new thread,
126-
// which will then run SpawnHookResults::run().
127-
ChildSpawnHooks { hooks, to_run }
120+
}) {
121+
// Iterate over the hooks, run them, and collect the results in a vector.
122+
let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref())
123+
.map(|hook| (hook.hook)(thread))
124+
.collect();
125+
// Pass on the snapshot of the hooks and the results to the new thread,
126+
// which will then run SpawnHookResults::run().
127+
ChildSpawnHooks { hooks, to_run }
128+
} else {
129+
// TLS has been destroyed. Skip running the hooks.
130+
// See https://github.com/rust-lang/rust/issues/138696
131+
ChildSpawnHooks::default()
132+
}
128133
}
129134

130135
/// The results of running the spawn hooks.
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Regression test for https://github.com/rust-lang/rust/issues/138696
2+
//@ needs-threads
3+
//@ run-pass
4+
5+
#![feature(rustc_private)]
6+
7+
extern crate libc;
8+
9+
fn main() {
10+
std::thread::spawn(|| {
11+
unsafe { libc::atexit(spawn_in_atexit) };
12+
})
13+
.join()
14+
.unwrap();
15+
}
16+
17+
extern "C" fn spawn_in_atexit() {
18+
std::thread::spawn(|| {
19+
println!("Thread spawned in atexit");
20+
})
21+
.join()
22+
.unwrap();
23+
}

0 commit comments

Comments
 (0)