Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions library/std/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,16 @@ fn handle_rt_panic<T>(e: Box<dyn Any + Send>) -> T {
// `compiler/rustc_session/src/config/sigpipe.rs`.
#[cfg_attr(test, allow(dead_code))]
unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
// Remember the main thread ID to give it the correct name. Do this
// immediately to make sure the correct name available to the platform
// functions.
// SAFETY: this is the only time and place where we call this function.
unsafe { main_thread::set(thread::current_id()) };

#[cfg_attr(target_os = "teeos", allow(unused_unsafe))]
unsafe {
sys::init(argc, argv, sigpipe)
};

// Remember the main thread ID to give it the correct name.
// SAFETY: this is the only time and place where we call this function.
unsafe { main_thread::set(thread::current_id()) };
}

/// Clean up the thread-local runtime state. This *should* be run after all other
Expand Down
33 changes: 17 additions & 16 deletions library/std/src/sys/pal/unix/stack_overflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ pub struct Handler {
}

impl Handler {
pub unsafe fn new(thread_name: Option<Box<str>>) -> Handler {
make_handler(false, thread_name)
pub unsafe fn new() -> Handler {
make_handler(false)
}

fn null() -> Handler {
Expand Down Expand Up @@ -118,8 +118,15 @@ mod imp {
if let Some(thread_info) = thread_info
&& thread_info.guard_page_range.contains(&fault_addr)
{
let name = thread_info.thread_name.as_deref().unwrap_or("<unknown>");
let tid = crate::thread::current_os_id();
// Hey you! Yes, you modifying the stack overflow message!
// Please make sure that all functions called here are
// actually async-signal-safe. If they're not, try retrieving
// the information beforehand and storing it in `ThreadInfo`.
// Thank you!
// - says Jonas after having had to watch his carefully
// written code get made unsound again.
let tid = thread_info.tid;
let name = thread_info.name.as_deref().unwrap_or("<unknown>");
rtprintpanic!("\nthread '{name}' ({tid}) has overflowed its stack\n");
rtabort!("stack overflow");
}
Expand Down Expand Up @@ -158,12 +165,12 @@ mod imp {
if !NEED_ALTSTACK.load(Ordering::Relaxed) {
// haven't set up our sigaltstack yet
NEED_ALTSTACK.store(true, Ordering::Release);
let handler = unsafe { make_handler(true, None) };
let handler = unsafe { make_handler(true) };
MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
mem::forget(handler);

if let Some(guard_page_range) = guard_page_range.take() {
set_current_info(guard_page_range, Some(Box::from("main")));
set_current_info(guard_page_range);
}
}

Expand Down Expand Up @@ -229,14 +236,14 @@ mod imp {
/// # Safety
/// Mutates the alternate signal stack
#[forbid(unsafe_op_in_unsafe_fn)]
pub unsafe fn make_handler(main_thread: bool, thread_name: Option<Box<str>>) -> Handler {
pub unsafe fn make_handler(main_thread: bool) -> Handler {
if !NEED_ALTSTACK.load(Ordering::Acquire) {
return Handler::null();
}

if !main_thread {
if let Some(guard_page_range) = unsafe { current_guard() } {
set_current_info(guard_page_range, thread_name);
set_current_info(guard_page_range);
}
}

Expand Down Expand Up @@ -632,10 +639,7 @@ mod imp {

pub unsafe fn cleanup() {}

pub unsafe fn make_handler(
_main_thread: bool,
_thread_name: Option<Box<str>>,
) -> super::Handler {
pub unsafe fn make_handler(_main_thread: bool) -> super::Handler {
super::Handler::null()
}

Expand Down Expand Up @@ -719,10 +723,7 @@ mod imp {

pub unsafe fn cleanup() {}

pub unsafe fn make_handler(
main_thread: bool,
_thread_name: Option<Box<str>>,
) -> super::Handler {
pub unsafe fn make_handler(main_thread: bool) -> super::Handler {
if !main_thread {
reserve_stack();
}
Expand Down
10 changes: 7 additions & 3 deletions library/std/src/sys/pal/unix/stack_overflow/thread_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sys::os::errno_location;

pub struct ThreadInfo {
pub tid: u64,
pub name: Option<Box<str>>,
pub guard_page_range: Range<usize>,
pub thread_name: Option<Box<str>>,
}

static LOCK: Mutex<()> = Mutex::new(());
Expand Down Expand Up @@ -108,14 +109,17 @@ fn spin_lock_in_setup(this: usize) -> UnlockOnDrop {
}
}

pub fn set_current_info(guard_page_range: Range<usize>, thread_name: Option<Box<str>>) {
pub fn set_current_info(guard_page_range: Range<usize>) {
let tid = crate::thread::current_os_id();
let name = crate::thread::with_current_name(|name| name.map(Box::from));

let this = errno_location().addr();
let _lock_guard = LOCK.lock();
let _spin_guard = spin_lock_in_setup(this);

// SAFETY: we own the spin lock, so `THREAD_INFO` cannot be aliased.
let thread_info = unsafe { &mut *(&raw mut THREAD_INFO) };
thread_info.insert(this, ThreadInfo { guard_page_range, thread_name });
thread_info.insert(this, ThreadInfo { tid, name, guard_page_range });
}

pub fn delete_current_info() {
Expand Down
41 changes: 25 additions & 16 deletions library/std/src/sys/thread/hermit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,53 +13,62 @@ unsafe impl Sync for Thread {}

pub const DEFAULT_MIN_STACK_SIZE: usize = 1 << 20;

struct ThreadData {
handle: crate::thread::Thread,
main: Box<dyn FnOnce()>,
}

impl Thread {
pub unsafe fn new_with_coreid(
stack: usize,
p: Box<dyn FnOnce()>,
handle: crate::thread::Thread,
main: Box<dyn FnOnce()>,
core_id: isize,
) -> io::Result<Thread> {
let p = Box::into_raw(Box::new(p));
let data = Box::into_raw(Box::new(ThreadData { handle, main }));
let tid = unsafe {
hermit_abi::spawn2(
thread_start,
p.expose_provenance(),
data.expose_provenance(),
hermit_abi::Priority::into(hermit_abi::NORMAL_PRIO),
stack,
core_id,
)
};

return if tid == 0 {
// The thread failed to start and as a result p was not consumed. Therefore, it is
// safe to reconstruct the box so that it gets deallocated.
// The thread failed to start and as a result data was not consumed.
// Therefore, it is safe to reconstruct the box so that it gets
// deallocated.
unsafe {
drop(Box::from_raw(p));
drop(Box::from_raw(data));
}
Err(io::const_error!(io::ErrorKind::Uncategorized, "unable to create thread!"))
} else {
Ok(Thread { tid })
};

extern "C" fn thread_start(main: usize) {
unsafe {
// Finally, let's run some code.
Box::from_raw(ptr::with_exposed_provenance::<Box<dyn FnOnce()>>(main).cast_mut())();
let data = unsafe {
Box::from_raw(ptr::with_exposed_provenance::<ThreadData>(main).cast_mut())
};

// run all destructors
crate::sys::thread_local::destructors::run();
crate::rt::thread_cleanup();
}
crate::thread::set_current(data.handle);
(data.main)();

// run all destructors
unsafe { crate::sys::thread_local::destructors::run() };
crate::rt::thread_cleanup();
}
}

pub unsafe fn new(
stack: usize,
_name: Option<&str>,
p: Box<dyn FnOnce()>,
handle: crate::thread::Thread,
main: Box<dyn FnOnce()>,
) -> io::Result<Thread> {
unsafe {
Thread::new_with_coreid(stack, p, -1 /* = no specific core */)
Thread::new_with_coreid(stack, handle, main, -1 /* = no specific core */)
}
}

Expand Down
44 changes: 13 additions & 31 deletions library/std/src/sys/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cfg_select! {
pub use hermit::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{current_os_id, set_name};
pub use unsupported::current_os_id;
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
Expand All @@ -21,41 +21,32 @@ cfg_select! {
// as-is with the SGX target.
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{available_parallelism, set_name};
pub use unsupported::available_parallelism;
}
target_os = "solid_asp3" => {
mod solid;
pub use solid::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{available_parallelism, current_os_id, set_name};
pub use unsupported::{available_parallelism, current_os_id};
}
target_os = "teeos" => {
mod teeos;
pub use teeos::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{available_parallelism, current_os_id, set_name};
pub use unsupported::{available_parallelism, current_os_id};
}
target_os = "uefi" => {
mod uefi;
pub use uefi::{available_parallelism, sleep};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
pub use unsupported::{Thread, current_os_id, yield_now, DEFAULT_MIN_STACK_SIZE};
}
target_family = "unix" => {
mod unix;
pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[cfg(not(any(
target_env = "newlib",
target_os = "l4re",
target_os = "emscripten",
target_os = "redox",
target_os = "hurd",
target_os = "aix",
)))]
pub use unix::set_name;
#[cfg(any(
target_os = "freebsd",
target_os = "netbsd",
Expand All @@ -69,17 +60,8 @@ cfg_select! {
target_os = "vxworks",
))]
pub use unix::sleep_until;
#[expect(dead_code)]
mod unsupported;
#[cfg(any(
target_env = "newlib",
target_os = "l4re",
target_os = "emscripten",
target_os = "redox",
target_os = "hurd",
target_os = "aix",
))]
pub use unsupported::set_name;
// This is used to name the main thread in the platform init function.
pub(super) use unix::set_name;
}
all(target_os = "wasi", target_env = "p1") => {
mod wasip1;
Expand All @@ -88,7 +70,7 @@ cfg_select! {
pub use wasip1::{Thread, available_parallelism};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{current_os_id, set_name};
pub use unsupported::current_os_id;
#[cfg(not(target_feature = "atomics"))]
pub use unsupported::{Thread, available_parallelism};
}
Expand All @@ -100,31 +82,31 @@ cfg_select! {
// Note that unlike WASIp1 even if the wasm `atomics` feature is enabled
// there is no support for threads, not even experimentally, not even in
// wasi-libc. Thus this is unconditionally unsupported.
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
pub use unsupported::{Thread, available_parallelism, current_os_id, yield_now, DEFAULT_MIN_STACK_SIZE};
}
all(target_family = "wasm", target_feature = "atomics") => {
mod wasm;
pub use wasm::sleep;

#[expect(dead_code)]
mod unsupported;
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
pub use unsupported::{Thread, available_parallelism, current_os_id, yield_now, DEFAULT_MIN_STACK_SIZE};
}
target_os = "windows" => {
mod windows;
pub use windows::{Thread, available_parallelism, current_os_id, set_name, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
pub use windows::{Thread, available_parallelism, current_os_id, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
}
target_os = "xous" => {
mod xous;
pub use xous::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};

#[expect(dead_code)]
mod unsupported;
pub use unsupported::{current_os_id, set_name};
pub use unsupported::current_os_id;
}
_ => {
mod unsupported;
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
pub use unsupported::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
}
}

Expand Down
19 changes: 12 additions & 7 deletions library/std/src/sys/thread/sgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,24 @@ mod task_queue {
}

pub(super) struct Task {
p: Box<dyn FnOnce() + Send>,
handle: crate::thread::Thread,
main: Box<dyn FnOnce() + Send>,
done: JoinNotifier,
}

impl Task {
pub(super) fn new(p: Box<dyn FnOnce() + Send>) -> (Task, JoinHandle) {
pub(super) fn new(
handle: crate::thread::Thread,
main: Box<dyn FnOnce() + Send>,
) -> (Task, JoinHandle) {
let (done, recv) = wait_notify::new();
let done = JoinNotifier(Some(done));
(Task { p, done }, recv)
(Task { handle, main, done }, recv)
}

pub(super) fn run(self) -> JoinNotifier {
(self.p)();
crate::thread::set_current(self.handle);
(self.main)();
self.done
}
}
Expand Down Expand Up @@ -95,12 +100,12 @@ impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(
_stack: usize,
_name: Option<&str>,
p: Box<dyn FnOnce() + Send>,
handle: crate::thread::Thread,
main: Box<dyn FnOnce() + Send>,
) -> io::Result<Thread> {
let mut queue_lock = task_queue::lock();
unsafe { usercalls::launch_thread()? };
let (task, handle) = task_queue::Task::new(p);
let (task, handle) = task_queue::Task::new(handle, main);
queue_lock.push(task);
Ok(Thread(handle))
}
Expand Down
Loading
Loading