Auto merge of #90442 - ChrisDenton:win-tls-dtor, r=alexcrichton

Windows thread-local keyless drop

`#[thread_local]` allows us to maintain a per-thread list of destructors. This also avoids the need to synchronize global data (which is particularly tricky within the TLS callback function).

r? `@alexcrichton`
This commit is contained in:
bors 2021-11-02 12:15:08 +00:00
commit c3190c1eb4
2 changed files with 27 additions and 1 deletions

View File

@ -1,4 +1,28 @@
//! Implements thread-local destructors that are not associated with any
//! particular data.
#![unstable(feature = "thread_local_internals", issue = "none")]
#![cfg(target_thread_local)]
pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor;
// Using a per-thread list avoids the problems in synchronizing global state.
#[thread_local]
static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
DESTRUCTORS.push((t, dtor));
}
/// Runs destructors. This should not be called until thread exit.
pub unsafe fn run_keyless_dtors() {
// Drop all the destructors.
//
// Note: While this is potentially an infinite loop, 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.
while let Some((ptr, dtor)) = DESTRUCTORS.pop() {
(dtor)(ptr);
}
// We're done so free the memory.
DESTRUCTORS = Vec::new();
}

View File

@ -196,6 +196,8 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) {
unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) {
if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
run_dtors();
#[cfg(target_thread_local)]
super::thread_local_dtor::run_keyless_dtors();
}
// See comments above for what this is doing. Note that we don't need this