Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 24a0765

Browse files
committedNov 19, 2024
Add std::thread::add_spawn_hook.
1 parent 36cfa4e commit 24a0765

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed
 

‎std/src/thread/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ mod current;
188188
pub use current::current;
189189
pub(crate) use current::{current_id, drop_current, set_current, try_current};
190190

191+
mod spawnhook;
192+
193+
#[unstable(feature = "thread_spawn_hook", issue = "none")]
194+
pub use spawnhook::add_spawn_hook;
195+
191196
////////////////////////////////////////////////////////////////////////////////
192197
// Thread-local storage
193198
////////////////////////////////////////////////////////////////////////////////
@@ -485,6 +490,9 @@ impl Builder {
485490
Some(name) => Thread::new(id, name.into()),
486491
None => Thread::new_unnamed(id),
487492
};
493+
494+
let hooks = spawnhook::run_spawn_hooks(&my_thread)?;
495+
488496
let their_thread = my_thread.clone();
489497

490498
let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
@@ -535,6 +543,9 @@ impl Builder {
535543
}
536544

537545
crate::io::set_output_capture(output_capture);
546+
for hook in hooks {
547+
hook();
548+
}
538549

539550
let f = f.into_inner();
540551
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {

‎std/src/thread/spawnhook.rs

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use crate::io;
2+
use crate::sync::RwLock;
3+
use crate::thread::Thread;
4+
5+
static SPAWN_HOOKS: RwLock<
6+
Vec<&'static (dyn Fn(&Thread) -> io::Result<Box<dyn FnOnce() + Send>> + Sync)>,
7+
> = RwLock::new(Vec::new());
8+
9+
/// Registers a function to run for every new thread spawned.
10+
///
11+
/// The hook is executed in the parent thread, and returns a function
12+
/// that will be executed in the new thread.
13+
///
14+
/// The hook is called with the `Thread` handle for the new thread.
15+
///
16+
/// If the hook returns an `Err`, thread spawning is aborted. In that case, the
17+
/// function used to spawn the thread (e.g. `std::thread::spawn`) will return
18+
/// the error returned by the hook.
19+
///
20+
/// Hooks can only be added, not removed.
21+
///
22+
/// The hooks will run in order, starting with the most recently added.
23+
///
24+
/// # Usage
25+
///
26+
/// ```
27+
/// #![feature(thread_spawn_hook)]
28+
///
29+
/// std::thread::add_spawn_hook(|_| {
30+
/// ..; // This will run in the parent (spawning) thread.
31+
/// Ok(move || {
32+
/// ..; // This will run it the child (spawned) thread.
33+
/// })
34+
/// });
35+
/// ```
36+
///
37+
/// # Example
38+
///
39+
/// A spawn hook can be used to initialize thread locals from the parent thread:
40+
///
41+
/// ```
42+
/// #![feature(thread_spawn_hook)]
43+
///
44+
/// use std::cell::Cell;
45+
///
46+
/// thread_local! {
47+
/// static X: Cell<u32> = Cell::new(0);
48+
/// }
49+
///
50+
/// std::thread::add_spawn_hook(|_| {
51+
/// // Get the value of X in the spawning thread.
52+
/// let value = X.get();
53+
/// // Set the value of X in the newly spawned thread.
54+
/// Ok(move || {
55+
/// X.set(value);
56+
/// })
57+
/// });
58+
///
59+
/// X.set(123);
60+
///
61+
/// std::thread::spawn(|| {
62+
/// assert_eq!(X.get(), 123);
63+
/// }).join().unwrap();
64+
/// ```
65+
#[unstable(feature = "thread_spawn_hook", issue = "none")]
66+
pub fn add_spawn_hook<F, G>(hook: F)
67+
where
68+
F: 'static + Sync + Fn(&Thread) -> io::Result<G>,
69+
G: 'static + Send + FnOnce(),
70+
{
71+
SPAWN_HOOKS.write().unwrap_or_else(|e| e.into_inner()).push(Box::leak(Box::new(
72+
move |thread: &Thread| -> io::Result<_> {
73+
let f: Box<dyn FnOnce() + Send> = Box::new(hook(thread)?);
74+
Ok(f)
75+
},
76+
)));
77+
}
78+
79+
/// Runs all the spawn hooks.
80+
///
81+
/// Called on the parent thread.
82+
///
83+
/// Returns the functions to be called on the newly spawned thread.
84+
pub(super) fn run_spawn_hooks(thread: &Thread) -> io::Result<Vec<Box<dyn FnOnce() + Send>>> {
85+
SPAWN_HOOKS
86+
.read()
87+
.unwrap_or_else(|e| e.into_inner())
88+
.iter()
89+
.rev()
90+
.map(|hook| hook(thread))
91+
.collect()
92+
}

0 commit comments

Comments
 (0)
Failed to load comments.