about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-11-02 12:15:08 +0000
committerbors <bors@rust-lang.org>2021-11-02 12:15:08 +0000
commitc3190c1eb4c982b1d419ae0632bad07a3b306b48 (patch)
treee7b49a40ef2ca0d388583317a9bbe85a1f031e16
parent6384dca100f3cedfa031a9204586f94f8612eae5 (diff)
parent1048651fa3d0c8d5ac98a616810d1cf2b1fe80c0 (diff)
downloadrust-c3190c1eb4c982b1d419ae0632bad07a3b306b48.tar.gz
rust-c3190c1eb4c982b1d419ae0632bad07a3b306b48.zip
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`
-rw-r--r--library/std/src/sys/windows/thread_local_dtor.rs26
-rw-r--r--library/std/src/sys/windows/thread_local_key.rs2
2 files changed, 27 insertions, 1 deletions
diff --git a/library/std/src/sys/windows/thread_local_dtor.rs b/library/std/src/sys/windows/thread_local_dtor.rs
index 7be13bc4b2b..25d1c6e8e87 100644
--- a/library/std/src/sys/windows/thread_local_dtor.rs
+++ b/library/std/src/sys/windows/thread_local_dtor.rs
@@ -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();
+}
diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs
index 0bc51114665..ec670238e6f 100644
--- a/library/std/src/sys/windows/thread_local_key.rs
+++ b/library/std/src/sys/windows/thread_local_key.rs
@@ -196,6 +196,8 @@ pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::
 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