Skip to content

Rollup of 9 pull requests #129729

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6ed283b
rustdoc-json: Add test for `Self` type
aDotInTheVoid Aug 15, 2024
42a901a
Don't use TyKind in lint
compiler-errors Aug 24, 2024
af05882
Deny wasm_c_abi lint to nudge the last 25%
workingjubilee Aug 24, 2024
c61f85b
Don't make pattern nonterminals match statement nonterminals
compiler-errors Jan 22, 2024
f1e2991
std: make `thread::current` available in all `thread_local!` destructors
joboet Jul 18, 2024
cfbd250
bless miri tests
joboet Jul 20, 2024
a1c36c6
linker: Synchronize native library search in rustc and linker
petrochenkov Aug 14, 2024
05bd36d
linker: Better support alternative static library naming on MSVC
petrochenkov Aug 21, 2024
ac8f132
docs: Update docs for the rustc's `-L` option
petrochenkov Aug 27, 2024
ee05de8
Re-enable android tests/benches in alloc
saethlin Aug 27, 2024
83de14c
Enable some ilog2 tests as well
saethlin Aug 27, 2024
ae6f8a7
allow BufReader::peek to be called on unsized types
lolbinarycat Aug 28, 2024
0cac915
Improve `isqrt` tests and add benchmarks
ChaiTRex Aug 26, 2024
7af8e21
Speed up `checked_isqrt` and `isqrt` methods
ChaiTRex Aug 26, 2024
120e437
Rollup merge of #120221 - compiler-errors:statements-are-not-patterns…
workingjubilee Aug 29, 2024
772a670
Rollup merge of #127912 - joboet:tls_dtor_thread_current, r=cupiver
workingjubilee Aug 29, 2024
0e039de
Rollup merge of #128166 - ChaiTRex:isqrt, r=tgross35
workingjubilee Aug 29, 2024
10db657
Rollup merge of #129123 - aDotInTheVoid:rustdoc-json-self, r=fmease
workingjubilee Aug 29, 2024
9d9c153
Rollup merge of #129366 - petrochenkov:libsearch, r=jieyouxu
workingjubilee Aug 29, 2024
8f2dad9
Rollup merge of #129527 - compiler-errors:lint-nit, r=Nadrieril
workingjubilee Aug 29, 2024
a4ae0e3
Rollup merge of #129534 - workingjubilee:ratchet-wasm-c-abi-fcw-to-de…
workingjubilee Aug 29, 2024
09a2515
Rollup merge of #129640 - saethlin:unignore-android-in-alloc, r=tgross35
workingjubilee Aug 29, 2024
6027230
Rollup merge of #129675 - lolbinarycat:bufreader_peek_unsized, r=work…
workingjubilee Aug 29, 2024
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
Prev Previous commit
Next Next commit
std: make thread::current available in all thread_local! destructors
  • Loading branch information
joboet committed Aug 27, 2024
commit f1e2991b7e052e359c0aaffd3b6abd9f479cdf17
34 changes: 25 additions & 9 deletions library/std/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ pub use crate::panicking::{begin_panic, panic_count};
pub use core::panicking::{panic_display, panic_fmt};

#[rustfmt::skip]
use crate::any::Any;
use crate::sync::Once;
use crate::sys;
use crate::thread::{self, Thread};
use crate::{mem, panic, sys};

// Prints to the "panic output", depending on the platform this may be:
// - the standard error output
Expand Down Expand Up @@ -66,6 +67,11 @@ macro_rules! rtunwrap {
};
}

fn handle_rt_panic(e: Box<dyn Any + Send>) {
mem::forget(e);
rtabort!("initialization or cleanup bug");
}

// One-time runtime initialization.
// Runs before `main`.
// SAFETY: must be called only once during runtime initialization.
Expand Down Expand Up @@ -101,6 +107,20 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
thread::set_current(thread);
}

/// Clean up the thread-local runtime state. This *should* be run after all other
/// code managed by the Rust runtime, but will not cause UB if that condition is
/// not fulfilled. Also note that this function is not guaranteed to be run, but
/// skipping it will cause leaks and therefore is to be avoided.
pub(crate) fn thread_cleanup() {
// This function is run in situations where unwinding leads to an abort
// (think `extern "C"` functions). Abort here instead so that we can
// print a nice message.
panic::catch_unwind(|| {
crate::thread::drop_current();
})
.unwrap_or_else(handle_rt_panic);
}

// One-time runtime cleanup.
// Runs after `main` or at program exit.
// NOTE: this is not guaranteed to run, for example when the program aborts.
Expand All @@ -123,11 +143,6 @@ fn lang_start_internal(
argv: *const *const u8,
sigpipe: u8,
) -> Result<isize, !> {
use crate::{mem, panic};
let rt_abort = move |e| {
mem::forget(e);
rtabort!("initialization or cleanup bug");
};
// Guard against the code called by this function from unwinding outside of the Rust-controlled
// code, which is UB. This is a requirement imposed by a combination of how the
// `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
Expand All @@ -139,16 +154,17 @@ fn lang_start_internal(
// prevent std from accidentally introducing a panic to these functions. Another is from
// user code from `main` or, more nefariously, as described in e.g. issue #86030.
// SAFETY: Only called once during runtime initialization.
panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) })
.unwrap_or_else(handle_rt_panic);
let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
.map_err(move |e| {
mem::forget(e);
rtabort!("drop of the panic payload panicked");
});
panic::catch_unwind(cleanup).map_err(rt_abort)?;
panic::catch_unwind(cleanup).unwrap_or_else(handle_rt_panic);
// Guard against multple threads calling `libc::exit` concurrently.
// See the documentation for `unique_thread_exit` for more information.
panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?;
panic::catch_unwind(crate::sys::exit_guard::unique_thread_exit).unwrap_or_else(handle_rt_panic);
ret_code
}

Expand Down
6 changes: 5 additions & 1 deletion library/std/src/sys/pal/hermit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ pub unsafe extern "C" fn runtime_entry(
unsafe {
crate::sys::thread_local::destructors::run();
}
unsafe { hermit_abi::exit(result) }
crate::rt::thread_cleanup();

unsafe {
hermit_abi::exit(result);
}
}

#[inline]
Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/pal/hermit/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ impl Thread {

// run all destructors
crate::sys::thread_local::destructors::run();
crate::rt::thread_cleanup();
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions library/std/src/sys/sync/rwlock/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ use crate::mem;
use crate::ptr::{self, null_mut, without_provenance_mut, NonNull};
use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
use crate::sync::atomic::{AtomicBool, AtomicPtr};
use crate::thread::{self, Thread};
use crate::thread::{self, Thread, ThreadId};

// Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the
// locking operation will be retried.
Expand Down Expand Up @@ -200,7 +200,9 @@ impl Node {
fn prepare(&mut self) {
// 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));
self.thread.get_or_init(|| {
thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new()))
});
self.completed = AtomicBool::new(false);
}

Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/thread_local/guard/apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub fn enable() {
unsafe extern "C" fn run_dtors(_: *mut u8) {
unsafe {
destructors::run();
crate::rt::thread_cleanup();
}
}
}
39 changes: 38 additions & 1 deletion library/std/src/sys/thread_local/guard/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
//! that will run all native TLS destructors in the destructor list.

use crate::ptr;
use crate::sys::thread_local::destructors;
use crate::sys::thread_local::key::{set, LazyKey};

#[cfg(target_thread_local)]
pub fn enable() {
use crate::sys::thread_local::destructors;

static DTORS: LazyKey = LazyKey::new(Some(run));

// Setting the key value to something other than NULL will result in the
Expand All @@ -18,6 +20,41 @@ pub fn enable() {
unsafe extern "C" fn run(_: *mut u8) {
unsafe {
destructors::run();
// On platforms with `__cxa_thread_atexit_impl`, `destructors::run`
// does nothing on newer systems as the TLS destructors are
// registered with the system. But because all of those platforms
// call the destructors of TLS keys after the registered ones, this
// function will still be run last (at the time of writing).
crate::rt::thread_cleanup();
}
}
}

/// On platforms with key-based TLS, the system runs the destructors for us.
/// We still have to make sure that [`crate::rt::thread_cleanup`] is called,
/// however. This is done by defering the execution of a TLS destructor to
/// the next round of destruction inside the TLS destructors.
#[cfg(not(target_thread_local))]
pub fn enable() {
const DEFER: *mut u8 = ptr::without_provenance_mut(1);
const RUN: *mut u8 = ptr::without_provenance_mut(2);

static CLEANUP: LazyKey = LazyKey::new(Some(run));

unsafe { set(CLEANUP.force(), DEFER) }

unsafe extern "C" fn run(state: *mut u8) {
if state == DEFER {
// Make sure that this function is run again in the next round of
// TLS destruction. If there is no futher round, there will be leaks,
// but that's okay, `thread_cleanup` is not guaranteed to be called.
unsafe { set(CLEANUP.force(), RUN) }
} else {
debug_assert_eq!(state, RUN);
// If the state is still RUN in the next round of TLS destruction,
// it means that no other TLS destructors defined by this runtime
// have been run, as they would have set the state to DEFER.
crate::rt::thread_cleanup();
}
}
}
5 changes: 4 additions & 1 deletion library/std/src/sys/thread_local/guard/solid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub fn enable() {
}

unsafe extern "C" fn tls_dtor(_unused: *mut u8) {
unsafe { destructors::run() };
unsafe {
destructors::run();
crate::rt::thread_cleanup();
}
}
}
8 changes: 4 additions & 4 deletions library/std/src/sys/thread_local/guard/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) =

unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) {
if dw_reason == c::DLL_THREAD_DETACH || dw_reason == c::DLL_PROCESS_DETACH {
#[cfg(target_thread_local)]
unsafe {
#[cfg(target_thread_local)]
super::super::destructors::run();
}
#[cfg(not(target_thread_local))]
unsafe {
#[cfg(not(target_thread_local))]
super::super::key::run_dtors();

crate::rt::thread_cleanup();
}
}
}
2 changes: 2 additions & 0 deletions library/std/src/sys/thread_local/key/xous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,6 @@ unsafe fn run_dtors() {
unsafe { cur = (*cur).next };
}
}

crate::rt::thread_cleanup();
}
46 changes: 30 additions & 16 deletions library/std/src/sys/thread_local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,15 @@ cfg_if::cfg_if! {
))] {
mod statik;
pub use statik::{EagerStorage, LazyStorage, thread_local_inner};
pub(crate) use statik::{LocalPointer, local_pointer};
} else if #[cfg(target_thread_local)] {
mod native;
pub use native::{EagerStorage, LazyStorage, thread_local_inner};
pub(crate) use native::{LocalPointer, local_pointer};
} else {
mod os;
pub use os::{Storage, thread_local_inner};
pub(crate) use os::{LocalPointer, local_pointer};
}
}

Expand Down Expand Up @@ -72,36 +75,47 @@ pub(crate) mod destructors {
}

/// This module provides a way to schedule the execution of the destructor list
/// on systems without a per-variable destructor system.
mod guard {
/// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling `enable`
/// should ensure that these functions are called at the right times.
pub(crate) mod guard {
cfg_if::cfg_if! {
if #[cfg(all(target_thread_local, target_vendor = "apple"))] {
mod apple;
pub(super) use apple::enable;
pub(crate) use apple::enable;
} else if #[cfg(target_os = "windows")] {
mod windows;
pub(super) use windows::enable;
pub(crate) use windows::enable;
} else if #[cfg(any(
all(target_family = "wasm", target_feature = "atomics"),
target_family = "wasm",
target_os = "uefi",
target_os = "zkvm",
))] {
pub(super) fn enable() {
// FIXME: Right now there is no concept of "thread exit", but
// this is likely going to show up at some point in the form of
// an exported symbol that the wasm runtime is going to be
// expected to call. For now we just leak everything, but if
// such a function starts to exist it will probably need to
pub(crate) fn enable() {
// FIXME: Right now there is no concept of "thread exit" on
// wasm, but this is likely going to show up at some point in
// the form of an exported symbol that the wasm runtime is going
// to be expected to call. For now we just leak everything, but
// if such a function starts to exist it will probably need to
// iterate the destructor list with this function:
#[allow(unused)]
#[cfg(not(all(target_family = "wasm", not(target_feature = "atomics"))))]
use super::destructors::run;
#[allow(unused)]
use crate::rt::thread_cleanup;
}
} else if #[cfg(target_os = "hermit")] {
pub(super) fn enable() {}
} else if #[cfg(any(
target_os = "hermit",
target_os = "xous",
))] {
// `std` is the only runtime, so it just calls the destructor functions
// itself when the time comes.
pub(crate) fn enable() {}
} else if #[cfg(target_os = "solid_asp3")] {
mod solid;
pub(super) use solid::enable;
} else if #[cfg(all(target_thread_local, not(target_family = "wasm")))] {
pub(crate) use solid::enable;
} else {
mod key;
pub(super) use key::enable;
pub(crate) use key::enable;
}
}
}
Expand Down
31 changes: 31 additions & 0 deletions library/std/src/sys/thread_local/native/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
//! eliminates the `Destroyed` state for these values, which can allow more niche
//! optimizations to occur for the `State` enum. For `Drop` types, `()` is used.

use crate::cell::Cell;
use crate::ptr;

mod eager;
mod lazy;

Expand Down Expand Up @@ -107,3 +110,31 @@ pub macro thread_local_inner {
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
},
}

#[rustc_macro_transparency = "semitransparent"]
pub(crate) macro local_pointer {
() => {},
($vis:vis static $name:ident; $($rest:tt)*) => {
#[thread_local]
$vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
$crate::sys::thread_local::local_pointer! { $($rest)* }
},
}

pub(crate) struct LocalPointer {
p: Cell<*mut ()>,
}

impl LocalPointer {
pub const fn __new() -> LocalPointer {
LocalPointer { p: Cell::new(ptr::null_mut()) }
}

pub fn get(&self) -> *mut () {
self.p.get()
}

pub fn set(&self, p: *mut ()) {
self.p.set(p)
}
}
34 changes: 32 additions & 2 deletions library/std/src/sys/thread_local/os.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::abort_on_dtor_unwind;
use super::key::{get, set, Key, LazyKey};
use super::{abort_on_dtor_unwind, guard};
use crate::cell::Cell;
use crate::marker::PhantomData;
use crate::ptr;
use crate::sys::thread_local::key::{get, set, Key, LazyKey};

#[doc(hidden)]
#[allow_internal_unstable(thread_local_internals)]
Expand Down Expand Up @@ -138,5 +138,35 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
drop(ptr);
// SAFETY: `key` is the TLS key `ptr` was stored under.
unsafe { set(key, ptr::null_mut()) };
// Make sure that the runtime cleanup will be performed
// after the next round of TLS destruction.
guard::enable();
});
}

#[rustc_macro_transparency = "semitransparent"]
pub(crate) macro local_pointer {
() => {},
($vis:vis static $name:ident; $($rest:tt)*) => {
$vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
$crate::sys::thread_local::local_pointer! { $($rest)* }
},
}

pub(crate) struct LocalPointer {
key: LazyKey,
}

impl LocalPointer {
pub const fn __new() -> LocalPointer {
LocalPointer { key: LazyKey::new(None) }
}

pub fn get(&'static self) -> *mut () {
unsafe { get(self.key.force()) as *mut () }
}

pub fn set(&'static self, p: *mut ()) {
unsafe { set(self.key.force(), p as *mut u8) }
}
}
Loading