//! Thread-local destructor //! //! Besides thread-local "keys" (pointer-sized non-addressable thread-local store //! with an associated destructor), many platforms also provide thread-local //! destructors that are not associated with any particular data. These are //! often more efficient. //! //! This module provides a fallback implementation for that interface, based //! on the less efficient thread-local "keys". Each platform provides //! a `thread_local_dtor` module which will either re-export the fallback, //! or implement something more efficient. #![unstable(feature = "thread_local_internals", issue = "none")] #![allow(dead_code)] use crate::ptr; use crate::sys_common::thread_local_key::StaticKey; pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { // The fallback implementation uses a vanilla OS-based TLS key to track // the list of destructors that need to be run for this thread. The key // then has its own destructor which runs all the other destructors. // // The destructor for DTORS is a little special in that it has a `while` // loop to continuously drain the list of registered destructors. It // *should* be the case that this loop always terminates because we // provide the guarantee that a TLS key cannot be set after it is // flagged for destruction. static DTORS: StaticKey = StaticKey::new(Some(run_dtors)); type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; if DTORS.get().is_null() { let v: Box = box Vec::new(); DTORS.set(Box::into_raw(v) as *mut u8); } let list: &mut List = &mut *(DTORS.get() as *mut List); list.push((t, dtor)); unsafe extern "C" fn run_dtors(mut ptr: *mut u8) { while !ptr.is_null() { let list: Box = Box::from_raw(ptr as *mut List); for (ptr, dtor) in list.into_iter() { dtor(ptr); } ptr = DTORS.get(); DTORS.set(ptr::null_mut()); } } }