|
| 1 | +//! Implements thread-local destructors that are not associated with any |
| 2 | +//! particular data. |
| 3 | +
|
1 | 4 | #![unstable(feature = "thread_local_internals", issue = "none")]
|
2 | 5 | #![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; |
3 | 24 |
|
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