From c6891dd7e504a5a3abeaca5052336ccb235fe0c9 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Tue, 3 Dec 2024 21:42:22 +0100 Subject: [PATCH 1/4] Run TLS destructors for main thread on UNIX platforms This calls TLS destructors on UNIX platforms other than Linux when the main thread exits. This is done by registering a process-wide atexit handler. --- library/std/src/lib.rs | 1 + library/std/src/sys/thread_local/guard/key.rs | 40 +++++++++++++++---- library/std/src/sys/thread_local/key/sgx.rs | 2 + library/std/src/sys/thread_local/key/unix.rs | 5 +++ .../std/src/sys/thread_local/key/windows.rs | 2 + library/std/src/sys/thread_local/key/xous.rs | 2 + library/std/src/sys/thread_local/mod.rs | 8 ++-- 7 files changed, 49 insertions(+), 11 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ee6fceb024fd7..390fb72d22171 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -282,6 +282,7 @@ #![feature(allow_internal_unstable)] #![feature(asm_experimental_arch)] #![feature(cfg_sanitizer_cfi)] +#![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(concat_idents)] diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs index 59581e6f281e6..4e6b6bdc99ec1 100644 --- a/library/std/src/sys/thread_local/guard/key.rs +++ b/library/std/src/sys/thread_local/guard/key.rs @@ -7,17 +7,38 @@ use crate::sys::thread_local::key::{LazyKey, set}; #[cfg(target_thread_local)] pub fn enable() { - use crate::sys::thread_local::destructors; + fn enable_thread() { + static DTORS: LazyKey = LazyKey::new(Some(run_thread)); - static DTORS: LazyKey = LazyKey::new(Some(run)); + // Setting the key value to something other than NULL will result in the + // destructor being run at thread exit. + unsafe { + set(DTORS.force(), ptr::without_provenance_mut(1)); + } + + unsafe extern "C" fn run_thread(_: *mut u8) { + run() + } + } + + #[cfg(target_has_atomic_load_store = "8")] + fn enable_process() { + use crate::sync::atomic::{AtomicBool, Ordering}; + use crate::sys::thread_local::key::at_process_exit; - // Setting the key value to something other than NULL will result in the - // destructor being run at thread exit. - unsafe { - set(DTORS.force(), ptr::without_provenance_mut(1)); + static REGISTERED: AtomicBool = AtomicBool::new(false); + if !REGISTERED.swap(true, Ordering::AcqRel) { + unsafe { at_process_exit(run_process) }; + } + + unsafe extern "C" fn run_process() { + run() + } } - unsafe extern "C" fn run(_: *mut u8) { + fn run() { + use crate::sys::thread_local::destructors; + unsafe { destructors::run(); // On platforms with `__cxa_thread_atexit_impl`, `destructors::run` @@ -28,6 +49,11 @@ pub fn enable() { crate::rt::thread_cleanup(); } } + + enable_thread(); + + #[cfg(target_has_atomic_load_store = "8")] + enable_process(); } /// On platforms with key-based TLS, the system runs the destructors for us. diff --git a/library/std/src/sys/thread_local/key/sgx.rs b/library/std/src/sys/thread_local/key/sgx.rs index 4aa2e5afa72ef..13c308edc5f15 100644 --- a/library/std/src/sys/thread_local/key/sgx.rs +++ b/library/std/src/sys/thread_local/key/sgx.rs @@ -21,3 +21,5 @@ pub unsafe fn get(key: Key) -> *mut u8 { pub unsafe fn destroy(key: Key) { Tls::destroy(AbiKey::from_usize(key)) } + +pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) {} diff --git a/library/std/src/sys/thread_local/key/unix.rs b/library/std/src/sys/thread_local/key/unix.rs index 28e48a750b9bf..d1bdc0dd9fdf5 100644 --- a/library/std/src/sys/thread_local/key/unix.rs +++ b/library/std/src/sys/thread_local/key/unix.rs @@ -26,3 +26,8 @@ pub unsafe fn destroy(key: Key) { let r = unsafe { libc::pthread_key_delete(key) }; debug_assert_eq!(r, 0); } + +#[inline] +pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) { + assert_eq!(unsafe { libc::atexit(mem::transmute(cb)) }, 0); +} diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs index f4e0f25a476ee..e6e3f7217daa5 100644 --- a/library/std/src/sys/thread_local/key/windows.rs +++ b/library/std/src/sys/thread_local/key/windows.rs @@ -202,3 +202,5 @@ pub unsafe fn run_dtors() { } } } + +pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) {} diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs index 2ab4bba7d8e98..9eff57e4feec9 100644 --- a/library/std/src/sys/thread_local/key/xous.rs +++ b/library/std/src/sys/thread_local/key/xous.rs @@ -215,3 +215,5 @@ unsafe fn run_dtors() { crate::rt::thread_cleanup(); } + +pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) {} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 31d3b43906004..2819d3e8a569f 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -141,7 +141,7 @@ pub(crate) mod key { #[cfg(test)] mod tests; pub(super) use racy::LazyKey; - pub(super) use unix::{Key, set}; + pub(super) use unix::{Key, set, at_process_exit}; #[cfg(any(not(target_thread_local), test))] pub(super) use unix::get; use unix::{create, destroy}; @@ -149,14 +149,14 @@ pub(crate) mod key { #[cfg(test)] mod tests; mod windows; - pub(super) use windows::{Key, LazyKey, get, run_dtors, set}; + pub(super) use windows::{Key, LazyKey, get, run_dtors, set, at_process_exit}; } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod racy; mod sgx; #[cfg(test)] mod tests; pub(super) use racy::LazyKey; - pub(super) use sgx::{Key, get, set}; + pub(super) use sgx::{Key, get, set, at_process_exit}; use sgx::{create, destroy}; } else if #[cfg(target_os = "xous")] { mod racy; @@ -165,7 +165,7 @@ pub(crate) mod key { mod xous; pub(super) use racy::LazyKey; pub(crate) use xous::destroy_tls; - pub(super) use xous::{Key, get, set}; + pub(super) use xous::{Key, get, set, at_process_exit}; use xous::{create, destroy}; } } From 0587715af0e983e6d72cc95f899b43a2dc76e89d Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Tue, 3 Dec 2024 22:24:42 +0100 Subject: [PATCH 2/4] Fix non-UNIX builds --- library/std/src/sys/thread_local/key/sgx.rs | 4 +++- library/std/src/sys/thread_local/key/windows.rs | 2 -- library/std/src/sys/thread_local/key/xous.rs | 2 -- library/std/src/sys/thread_local/mod.rs | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/thread_local/key/sgx.rs b/library/std/src/sys/thread_local/key/sgx.rs index 13c308edc5f15..71dcb00a323c3 100644 --- a/library/std/src/sys/thread_local/key/sgx.rs +++ b/library/std/src/sys/thread_local/key/sgx.rs @@ -22,4 +22,6 @@ pub unsafe fn destroy(key: Key) { Tls::destroy(AbiKey::from_usize(key)) } -pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) {} +pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) { + let _ = cb; +} diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs index e6e3f7217daa5..f4e0f25a476ee 100644 --- a/library/std/src/sys/thread_local/key/windows.rs +++ b/library/std/src/sys/thread_local/key/windows.rs @@ -202,5 +202,3 @@ pub unsafe fn run_dtors() { } } } - -pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) {} diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs index 9eff57e4feec9..2ab4bba7d8e98 100644 --- a/library/std/src/sys/thread_local/key/xous.rs +++ b/library/std/src/sys/thread_local/key/xous.rs @@ -215,5 +215,3 @@ unsafe fn run_dtors() { crate::rt::thread_cleanup(); } - -pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) {} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 2819d3e8a569f..c019d276a84d1 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -149,7 +149,7 @@ pub(crate) mod key { #[cfg(test)] mod tests; mod windows; - pub(super) use windows::{Key, LazyKey, get, run_dtors, set, at_process_exit}; + pub(super) use windows::{Key, LazyKey, get, run_dtors, set}; } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod racy; mod sgx; @@ -165,7 +165,7 @@ pub(crate) mod key { mod xous; pub(super) use racy::LazyKey; pub(crate) use xous::destroy_tls; - pub(super) use xous::{Key, get, set, at_process_exit}; + pub(super) use xous::{Key, get, set}; use xous::{create, destroy}; } } From 11191fc78757a73346ed31126b03ba005634ab3d Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Tue, 3 Dec 2024 23:08:56 +0100 Subject: [PATCH 3/4] Fix Miri build --- library/std/src/sys/thread_local/key/unix.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/std/src/sys/thread_local/key/unix.rs b/library/std/src/sys/thread_local/key/unix.rs index d1bdc0dd9fdf5..5df069eeb1163 100644 --- a/library/std/src/sys/thread_local/key/unix.rs +++ b/library/std/src/sys/thread_local/key/unix.rs @@ -29,5 +29,10 @@ pub unsafe fn destroy(key: Key) { #[inline] pub unsafe fn at_process_exit(cb: unsafe extern "C" fn()) { + // Miri does not support atexit. + #[cfg(not(miri))] assert_eq!(unsafe { libc::atexit(mem::transmute(cb)) }, 0); + + #[cfg(miri)] + let _ = cb; } From b5c2e83744f9e8ebf55d84e217dc2ef17255e5b2 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Wed, 4 Dec 2024 22:55:51 +0100 Subject: [PATCH 4/4] Use relaxed memory ordering --- library/std/src/sys/thread_local/guard/key.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs index 4e6b6bdc99ec1..4a2b7085af255 100644 --- a/library/std/src/sys/thread_local/guard/key.rs +++ b/library/std/src/sys/thread_local/guard/key.rs @@ -27,7 +27,7 @@ pub fn enable() { use crate::sys::thread_local::key::at_process_exit; static REGISTERED: AtomicBool = AtomicBool::new(false); - if !REGISTERED.swap(true, Ordering::AcqRel) { + if !REGISTERED.swap(true, Ordering::Relaxed) { unsafe { at_process_exit(run_process) }; }