Skip to content

Commit

Permalink
std: lazily allocate the main thread handle
Browse files Browse the repository at this point in the history
#123550 elimintated the allocation of the main thread handle, but at the cost of greatly increased complexity. This PR proposes another approach: Instead of creating the main thread handle itself, the runtime simply remembers the thread ID of the main thread. The main thread handle is then only allocated when it is used, using the same lazy-initialization mechanism as for non-runtime use of `thread::current`, and the `name` method uses the thread ID to identify the main thread handle and return the correct name ("main") for it.

Thereby, we also allow accessing `thread::current` before main: as the runtime no longer tries to install its own handle, this will no longer trigger an abort. Rather, the name returned from `name` will only be "main" after the runtime initialization code has run, but I think that is acceptable.

I've also moved the `Thread` code into its own module, the size of `thread/mod.rs` is just getting out of hand.
  • Loading branch information
joboet committed Nov 5, 2024
1 parent 3b0cbae commit d26cacf
Show file tree
Hide file tree
Showing 7 changed files with 326 additions and 325 deletions.
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(strict_provenance_atomic_ptr)]
#![feature(sync_unsafe_cell)]
#![feature(ub_checks)]
// tidy-alphabetical-end
//
Expand Down
23 changes: 5 additions & 18 deletions library/std/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use core::panicking::{panic_display, panic_fmt};
#[rustfmt::skip]
use crate::any::Any;
use crate::sync::Once;
use crate::thread::{self, Thread};
use crate::thread::{current_id, set_main_thread};
use crate::{mem, panic, sys};

// Prints to the "panic output", depending on the platform this may be:
Expand Down Expand Up @@ -102,23 +102,10 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
sys::init(argc, argv, sigpipe)
};

// Set up the current thread handle to give it the right name.
//
// When code running before main uses `ReentrantLock` (for example by
// using `println!`), the thread ID can become initialized before we
// create this handle. Since `set_current` fails when the ID of the
// handle does not match the current ID, we should attempt to use the
// current thread ID here instead of unconditionally creating a new
// one. Also see #130210.
let thread = Thread::new_main(thread::current_id());
if let Err(_thread) = thread::set_current(thread) {
// `thread::current` will create a new handle if none has been set yet.
// Thus, if someone uses it before main, this call will fail. That's a
// bad idea though, as we then cannot set the main thread name here.
//
// FIXME: detect the main thread in `thread::current` and use the
// correct name there.
rtabort!("code running before main must not use thread::current");
// Mark the current thread as main thread.
// SAFETY: this is the only place and time where this is called.
unsafe {
set_main_thread(current_id());
}
}

Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/sync/rwlock/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl Node {
// Fall back to creating an unnamed `Thread` handle to allow locking in
// TLS destructors.
self.thread.get_or_init(|| {
thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new()))
thread::try_current().unwrap_or_else(|| Thread::new(ThreadId::new(), None))
});
self.completed = AtomicBool::new(false);
}
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/thread/current.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ fn init_current(current: *mut ()) -> Thread {
CURRENT.set(BUSY);
// If the thread ID was initialized already, use it.
let id = id::get_or_init();
let thread = Thread::new_unnamed(id);
let thread = Thread::new(id, None);

// Make sure that `crate::rt::thread_cleanup` will be run, which will
// call `drop_current`.
Expand Down
Loading

0 comments on commit d26cacf

Please sign in to comment.