--- a/library/std/src/sys/thread_local/destructors/list.rs +++ b/library/std/src/sys/thread_local/destructors/list.rs @@ -1,9 +1,25 @@ use crate::cell::RefCell; use crate::sys::thread_local::guard; +#[cfg(not(target_enforce_emulated_tls))] #[thread_local] static DTORS: RefCell> = RefCell::new(Vec::new()); +#[cfg(target_enforce_emulated_tls)] +use crate::sys::thread_local::key::StaticKey; + +#[cfg(target_enforce_emulated_tls)] +static DTORS: StaticKey>> = + StaticKey::new(None); + +#[cfg(target_enforce_emulated_tls)] +fn dtors() -> &'static RefCell> { + unsafe { + DTORS.get() + .unwrap_or_else(|| rtabort!("DTORS not initialized")) + } +} + pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { let Ok(mut dtors) = DTORS.try_borrow_mut() else { // This point can only be reached if the global allocator calls this @@ -12,6 +28,12 @@ rtabort!("the global allocator may not use TLS with destructors"); }; + #[cfg(target_enforce_emulated_tls)] + if dtors.is_empty() { + // Initialize on first use + unsafe { DTORS.initialize(RefCell::new(Vec::new())) }; + } + guard::enable(); dtors.push((t, dtor)); @@ -25,6 +47,17 @@ /// May only be run on thread exit to guarantee that there are no live references /// to TLS variables while they are destroyed. pub unsafe fn run() { + #[cfg(target_enforce_emulated_tls)] + { + // For emulated TLS, check if DTORS is initialized + let Some(dtors_ref) = (unsafe { DTORS.get() }) else { + return; // Nothing to clean up + }; + run_impl(dtors_ref); + return; + } + + #[cfg(not(target_enforce_emulated_tls))] loop { let mut dtors = DTORS.borrow_mut(); match dtors.pop() { @@ -42,3 +75,23 @@ } } } + +#[cfg(target_enforce_emulated_tls)] +unsafe fn run_impl(dtors_ref: &RefCell>) { + loop { + let mut dtors = dtors_ref.borrow_mut(); + match dtors.pop() { + Some((t, dtor)) => { + drop(dtors); + unsafe { + dtor(t); + } + } + None => { + // Free the list memory. + *dtors = Vec::new(); + break; + } + } + } +}