Skip to content

Commit 9212f40

Browse files
committed
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).
1 parent 68b554e commit 9212f40

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed
Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,39 @@
1+
//! Implements thread-local destructors that are not associated with any
2+
//! particular data.
3+
14
#![unstable(feature = "thread_local_internals", issue = "none")]
25
#![cfg(target_thread_local)]
6+
use super::c;
7+
8+
// Using a per-thread list avoids the problems in synchronizing global state.
9+
#[thread_local]
10+
static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
11+
12+
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
13+
DESTRUCTORS.push((t, dtor));
14+
}
15+
16+
// See windows/thread_local_keys.rs for an explanation of this callback function.
17+
// The short version is that all the function pointers in the `.CRT$XL*` array
18+
// will be called whenever a thread or process starts or ends.
19+
20+
#[link_section = ".CRT$XLD"]
21+
#[doc(hidden)]
22+
#[used]
23+
pub static TLS_CALLBACK: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) = tls_callback;
324

4-
pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor;
25+
unsafe extern "system" fn tls_callback(_: c::LPVOID, reason: c::DWORD, _: c::LPVOID) {
26+
if reason == c::DLL_THREAD_DETACH || reason == c::DLL_PROCESS_DETACH {
27+
// Drop all the destructors.
28+
//
29+
// Note: While this is potentially an infinite loop, it *should* be
30+
// the case that this loop always terminates because we provide the
31+
// guarantee that a TLS key cannot be set after it is flagged for
32+
// destruction.
33+
while let Some((ptr, dtor)) = DESTRUCTORS.pop() {
34+
(dtor)(ptr);
35+
}
36+
// We're done so free the memory.
37+
DESTRUCTORS.shrink_to_fit();
38+
}
39+
}

0 commit comments

Comments
 (0)