Skip to content

Commit 6bc27a8

Browse files
committed
std: pass the Thread for the newly spawned thread to the platform
1 parent ce6daf3 commit 6bc27a8

File tree

13 files changed

+204
-160
lines changed

13 files changed

+204
-160
lines changed

library/std/src/rt.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,16 @@ fn handle_rt_panic<T>(e: Box<dyn Any + Send>) -> T {
109109
// `compiler/rustc_session/src/config/sigpipe.rs`.
110110
#[cfg_attr(test, allow(dead_code))]
111111
unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
112+
// Remember the main thread ID to give it the correct name. Do this
113+
// immediately to make sure the correct name available to the platform
114+
// functions.
115+
// SAFETY: this is the only time and place where we call this function.
116+
unsafe { main_thread::set(thread::current_id()) };
117+
112118
#[cfg_attr(target_os = "teeos", allow(unused_unsafe))]
113119
unsafe {
114120
sys::init(argc, argv, sigpipe)
115121
};
116-
117-
// Remember the main thread ID to give it the correct name.
118-
// SAFETY: this is the only time and place where we call this function.
119-
unsafe { main_thread::set(thread::current_id()) };
120122
}
121123

122124
/// Clean up the thread-local runtime state. This *should* be run after all other

library/std/src/sys/thread/hermit.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,53 +13,62 @@ unsafe impl Sync for Thread {}
1313

1414
pub const DEFAULT_MIN_STACK_SIZE: usize = 1 << 20;
1515

16+
struct ThreadData {
17+
handle: crate::thread::Thread,
18+
main: Box<dyn FnOnce()>,
19+
}
20+
1621
impl Thread {
1722
pub unsafe fn new_with_coreid(
1823
stack: usize,
19-
p: Box<dyn FnOnce()>,
24+
handle: crate::thread::Thread,
25+
main: Box<dyn FnOnce()>,
2026
core_id: isize,
2127
) -> io::Result<Thread> {
22-
let p = Box::into_raw(Box::new(p));
28+
let data = Box::into_raw(Box::new(ThreadData { handle, main }));
2329
let tid = unsafe {
2430
hermit_abi::spawn2(
2531
thread_start,
26-
p.expose_provenance(),
32+
data.expose_provenance(),
2733
hermit_abi::Priority::into(hermit_abi::NORMAL_PRIO),
2834
stack,
2935
core_id,
3036
)
3137
};
3238

3339
return if tid == 0 {
34-
// The thread failed to start and as a result p was not consumed. Therefore, it is
35-
// safe to reconstruct the box so that it gets deallocated.
40+
// The thread failed to start and as a result data was not consumed.
41+
// Therefore, it is safe to reconstruct the box so that it gets
42+
// deallocated.
3643
unsafe {
37-
drop(Box::from_raw(p));
44+
drop(Box::from_raw(data));
3845
}
3946
Err(io::const_error!(io::ErrorKind::Uncategorized, "unable to create thread!"))
4047
} else {
4148
Ok(Thread { tid })
4249
};
4350

4451
extern "C" fn thread_start(main: usize) {
45-
unsafe {
46-
// Finally, let's run some code.
47-
Box::from_raw(ptr::with_exposed_provenance::<Box<dyn FnOnce()>>(main).cast_mut())();
52+
let data = unsafe {
53+
Box::from_raw(ptr::with_exposed_provenance::<ThreadData>(main).cast_mut())
54+
};
4855

49-
// run all destructors
50-
crate::sys::thread_local::destructors::run();
51-
crate::rt::thread_cleanup();
52-
}
56+
crate::thread::set_current(data.handle);
57+
(data.main)();
58+
59+
// run all destructors
60+
unsafe { crate::sys::thread_local::destructors::run() };
61+
crate::rt::thread_cleanup();
5362
}
5463
}
5564

5665
pub unsafe fn new(
5766
stack: usize,
58-
_name: Option<&str>,
59-
p: Box<dyn FnOnce()>,
67+
handle: crate::thread::Thread,
68+
main: Box<dyn FnOnce()>,
6069
) -> io::Result<Thread> {
6170
unsafe {
62-
Thread::new_with_coreid(stack, p, -1 /* = no specific core */)
71+
Thread::new_with_coreid(stack, handle, main, -1 /* = no specific core */)
6372
}
6473
}
6574

library/std/src/sys/thread/mod.rs

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cfg_select! {
44
pub use hermit::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
55
#[expect(dead_code)]
66
mod unsupported;
7-
pub use unsupported::{current_os_id, set_name};
7+
pub use unsupported::current_os_id;
88
}
99
all(target_vendor = "fortanix", target_env = "sgx") => {
1010
mod sgx;
@@ -21,41 +21,32 @@ cfg_select! {
2121
// as-is with the SGX target.
2222
#[expect(dead_code)]
2323
mod unsupported;
24-
pub use unsupported::{available_parallelism, set_name};
24+
pub use unsupported::available_parallelism;
2525
}
2626
target_os = "solid_asp3" => {
2727
mod solid;
2828
pub use solid::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
2929
#[expect(dead_code)]
3030
mod unsupported;
31-
pub use unsupported::{available_parallelism, current_os_id, set_name};
31+
pub use unsupported::{available_parallelism, current_os_id};
3232
}
3333
target_os = "teeos" => {
3434
mod teeos;
3535
pub use teeos::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
3636
#[expect(dead_code)]
3737
mod unsupported;
38-
pub use unsupported::{available_parallelism, current_os_id, set_name};
38+
pub use unsupported::{available_parallelism, current_os_id};
3939
}
4040
target_os = "uefi" => {
4141
mod uefi;
4242
pub use uefi::{available_parallelism, sleep};
4343
#[expect(dead_code)]
4444
mod unsupported;
45-
pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
45+
pub use unsupported::{Thread, current_os_id, yield_now, DEFAULT_MIN_STACK_SIZE};
4646
}
4747
target_family = "unix" => {
4848
mod unix;
4949
pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
50-
#[cfg(not(any(
51-
target_env = "newlib",
52-
target_os = "l4re",
53-
target_os = "emscripten",
54-
target_os = "redox",
55-
target_os = "hurd",
56-
target_os = "aix",
57-
)))]
58-
pub use unix::set_name;
5950
#[cfg(any(
6051
target_os = "freebsd",
6152
target_os = "netbsd",
@@ -69,17 +60,8 @@ cfg_select! {
6960
target_os = "vxworks",
7061
))]
7162
pub use unix::sleep_until;
72-
#[expect(dead_code)]
73-
mod unsupported;
74-
#[cfg(any(
75-
target_env = "newlib",
76-
target_os = "l4re",
77-
target_os = "emscripten",
78-
target_os = "redox",
79-
target_os = "hurd",
80-
target_os = "aix",
81-
))]
82-
pub use unsupported::set_name;
63+
// This is used to name the main thread in the platform init function.
64+
pub(super) use unix::set_name;
8365
}
8466
all(target_os = "wasi", target_env = "p1") => {
8567
mod wasip1;
@@ -88,7 +70,7 @@ cfg_select! {
8870
pub use wasip1::{Thread, available_parallelism};
8971
#[expect(dead_code)]
9072
mod unsupported;
91-
pub use unsupported::{current_os_id, set_name};
73+
pub use unsupported::current_os_id;
9274
#[cfg(not(target_feature = "atomics"))]
9375
pub use unsupported::{Thread, available_parallelism};
9476
}
@@ -100,31 +82,31 @@ cfg_select! {
10082
// Note that unlike WASIp1 even if the wasm `atomics` feature is enabled
10183
// there is no support for threads, not even experimentally, not even in
10284
// wasi-libc. Thus this is unconditionally unsupported.
103-
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
85+
pub use unsupported::{Thread, available_parallelism, current_os_id, yield_now, DEFAULT_MIN_STACK_SIZE};
10486
}
10587
all(target_family = "wasm", target_feature = "atomics") => {
10688
mod wasm;
10789
pub use wasm::sleep;
10890

10991
#[expect(dead_code)]
11092
mod unsupported;
111-
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
93+
pub use unsupported::{Thread, available_parallelism, current_os_id, yield_now, DEFAULT_MIN_STACK_SIZE};
11294
}
11395
target_os = "windows" => {
11496
mod windows;
115-
pub use windows::{Thread, available_parallelism, current_os_id, set_name, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
97+
pub use windows::{Thread, available_parallelism, current_os_id, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
11698
}
11799
target_os = "xous" => {
118100
mod xous;
119101
pub use xous::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
120102

121103
#[expect(dead_code)]
122104
mod unsupported;
123-
pub use unsupported::{current_os_id, set_name};
105+
pub use unsupported::current_os_id;
124106
}
125107
_ => {
126108
mod unsupported;
127-
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
109+
pub use unsupported::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
128110
}
129111
}
130112

library/std/src/sys/thread/sgx.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,24 @@ mod task_queue {
2525
}
2626

2727
pub(super) struct Task {
28-
p: Box<dyn FnOnce() + Send>,
28+
handle: crate::thread::Thread,
29+
main: Box<dyn FnOnce() + Send>,
2930
done: JoinNotifier,
3031
}
3132

3233
impl Task {
33-
pub(super) fn new(p: Box<dyn FnOnce() + Send>) -> (Task, JoinHandle) {
34+
pub(super) fn new(
35+
handle: crate::thread::Thread,
36+
main: Box<dyn FnOnce() + Send>,
37+
) -> (Task, JoinHandle) {
3438
let (done, recv) = wait_notify::new();
3539
let done = JoinNotifier(Some(done));
36-
(Task { p, done }, recv)
40+
(Task { handle, main, done }, recv)
3741
}
3842

3943
pub(super) fn run(self) -> JoinNotifier {
40-
(self.p)();
44+
crate::thread::set_current(self.handle);
45+
(self.main)();
4146
self.done
4247
}
4348
}
@@ -95,12 +100,12 @@ impl Thread {
95100
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
96101
pub unsafe fn new(
97102
_stack: usize,
98-
_name: Option<&str>,
99-
p: Box<dyn FnOnce() + Send>,
103+
handle: crate::thread::Thread,
104+
main: Box<dyn FnOnce() + Send>,
100105
) -> io::Result<Thread> {
101106
let mut queue_lock = task_queue::lock();
102107
unsafe { usercalls::launch_thread()? };
103-
let (task, handle) = task_queue::Task::new(p);
108+
let (task, handle) = task_queue::Task::new(handle, main);
104109
queue_lock.push(task);
105110
Ok(Thread(handle))
106111
}

library/std/src/sys/thread/solid.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ unsafe impl Sync for Thread {}
2727
/// State data shared between a parent thread and child thread. It's dropped on
2828
/// a transition to one of the final states.
2929
struct ThreadInner {
30-
/// This field is used on thread creation to pass a closure from
31-
/// `Thread::new` to the created task.
32-
start: UnsafeCell<ManuallyDrop<Box<dyn FnOnce()>>>,
30+
/// This field is used on thread creation to pass the thread handle and closure
31+
/// to the newly created thread.
32+
data: UnsafeCell<ManuallyDrop<(crate::thread::Thread, Box<dyn FnOnce()>)>>,
3333

3434
/// A state machine. Each transition is annotated with `[...]` in the
3535
/// source code.
@@ -65,7 +65,7 @@ struct ThreadInner {
6565
lifecycle: Atomic<usize>,
6666
}
6767

68-
// Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
68+
// Safety: The only `!Sync` field, `ThreadInner::data`, is only touched by
6969
// the task represented by `ThreadInner`.
7070
unsafe impl Sync for ThreadInner {}
7171

@@ -86,11 +86,11 @@ impl Thread {
8686
/// See `thread::Builder::spawn_unchecked` for safety requirements.
8787
pub unsafe fn new(
8888
stack: usize,
89-
_name: Option<&str>,
90-
p: Box<dyn FnOnce()>,
89+
handle: crate::thread::Thread,
90+
main: Box<dyn FnOnce()>,
9191
) -> io::Result<Thread> {
9292
let inner = Box::new(ThreadInner {
93-
start: UnsafeCell::new(ManuallyDrop::new(p)),
93+
data: UnsafeCell::new(ManuallyDrop::new((handle, main))),
9494
lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
9595
});
9696

@@ -100,10 +100,11 @@ impl Thread {
100100
let inner = unsafe { &*p_inner };
101101

102102
// Safety: Since `trampoline` is called only once for each
103-
// `ThreadInner` and only `trampoline` touches `start`,
104-
// `start` contains contents and is safe to mutably borrow.
105-
let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) };
106-
p();
103+
// `ThreadInner` and only `trampoline` touches `data`,
104+
// `data` contains contents and is safe to mutably borrow.
105+
let (handle, main) = unsafe { ManuallyDrop::take(&mut *inner.data.get()) };
106+
crate::thread::set_current(handle);
107+
main();
107108

108109
// Fix the current thread's state just in case, so that the
109110
// destructors won't abort

library/std/src/sys/thread/teeos.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@ pub struct Thread {
2222
unsafe impl Send for Thread {}
2323
unsafe impl Sync for Thread {}
2424

25+
struct ThreadData {
26+
handle: crate::thread::Thread,
27+
main: Box<dyn FnOnce()>,
28+
}
29+
2530
impl Thread {
2631
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
2732
pub unsafe fn new(
2833
stack: usize,
29-
_name: Option<&str>,
30-
p: Box<dyn FnOnce()>,
34+
handle: crate::thread::Thread,
35+
main: Box<dyn FnOnce()>,
3136
) -> io::Result<Thread> {
32-
let p = Box::into_raw(Box::new(p));
37+
let data = Box::into_raw(Box::new(ThreadData { handle, main }));
3338
let mut native: libc::pthread_t = unsafe { mem::zeroed() };
3439
let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
3540
assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
@@ -62,16 +67,17 @@ impl Thread {
6267
}
6368
};
6469

65-
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
66-
// Note: if the thread creation fails and this assert fails, then p will
67-
// be leaked. However, an alternative design could cause double-free
70+
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, data as *mut _) };
71+
// Note: if the thread creation fails and this assert fails, then data
72+
// will be leaked. However, an alternative design could cause double-free
6873
// which is clearly worse.
6974
assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0);
7075

7176
return if ret != 0 {
72-
// The thread failed to start and as a result p was not consumed. Therefore, it is
73-
// safe to reconstruct the box so that it gets deallocated.
74-
drop(unsafe { Box::from_raw(p) });
77+
// The thread failed to start and as a result data was not consumed.
78+
// Therefore, it is safe to reconstruct the box so that it gets
79+
// deallocated.
80+
drop(unsafe { Box::from_raw(data) });
7581
Err(io::Error::from_raw_os_error(ret))
7682
} else {
7783
// The new thread will start running earliest after the next yield.
@@ -80,15 +86,10 @@ impl Thread {
8086
Ok(Thread { id: native })
8187
};
8288

83-
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
84-
unsafe {
85-
// Next, set up our stack overflow handler which may get triggered if we run
86-
// out of stack.
87-
// this is not necessary in TEE.
88-
//let _handler = stack_overflow::Handler::new();
89-
// Finally, let's run some code.
90-
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
91-
}
89+
extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void {
90+
let data = unsafe { Box::from_raw(data as *mut ThreadData) };
91+
crate::thread::set_current(data.handle);
92+
(data.main)();
9293
ptr::null_mut()
9394
}
9495
}

0 commit comments

Comments
 (0)