Skip to content

Commit 7586a9f

Browse files
committed
Auto merge of #138702 - m-ou-se:spawn-in-atexit, r=Mark-Simulacrum
Allow spawning threads after TLS destruction Fixes #138696
2 parents 3f55023 + 6c2161a commit 7586a9f

File tree

2 files changed

+38
-9
lines changed

2 files changed

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

0 commit comments

Comments
 (0)