|
1 | 1 | #![cfg(target_thread_local)] |
2 | 2 | #![unstable(feature = "thread_local_internals", issue = "none")] |
3 | 3 |
|
4 | | -//! Provides thread-local destructors without an associated "key", which |
5 | | -//! can be more efficient. |
6 | | -
|
7 | | -// Since what appears to be glibc 2.18 this symbol has been shipped which |
8 | | -// GCC and clang both use to invoke destructors in thread_local globals, so |
9 | | -// let's do the same! |
10 | | -// |
11 | | -// Note, however, that we run on lots older linuxes, as well as cross |
12 | | -// compiling from a newer linux to an older linux, so we also have a |
13 | | -// fallback implementation to use as well. |
14 | | -#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))] |
15 | | -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { |
16 | | - use crate::mem; |
17 | | - use crate::sys_common::thread_local_dtor::register_dtor_fallback; |
18 | | - |
19 | | - extern "C" { |
20 | | - #[linkage = "extern_weak"] |
21 | | - static __dso_handle: *mut u8; |
22 | | - #[linkage = "extern_weak"] |
23 | | - static __cxa_thread_atexit_impl: *const libc::c_void; |
24 | | - } |
25 | | - if !__cxa_thread_atexit_impl.is_null() { |
26 | | - type F = unsafe extern "C" fn( |
27 | | - dtor: unsafe extern "C" fn(*mut u8), |
28 | | - arg: *mut u8, |
29 | | - dso_handle: *mut u8, |
30 | | - ) -> libc::c_int; |
31 | | - mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)( |
32 | | - dtor, |
33 | | - t, |
34 | | - &__dso_handle as *const _ as *mut _, |
35 | | - ); |
36 | | - return; |
37 | | - } |
38 | | - register_dtor_fallback(t, dtor); |
39 | | -} |
40 | | - |
41 | | -// This implementation is very similar to register_dtor_fallback in |
42 | | -// sys_common/thread_local.rs. The main difference is that we want to hook into |
43 | | -// macOS's analog of the above linux function, _tlv_atexit. OSX will run the |
44 | | -// registered dtors before any TLS slots get freed, and when the main thread |
45 | | -// exits. |
46 | | -// |
47 | | -// Unfortunately, calling _tlv_atexit while tls dtors are running is UB. The |
48 | | -// workaround below is to register, via _tlv_atexit, a custom DTOR list once per |
49 | | -// thread. thread_local dtors are pushed to the DTOR list without calling |
50 | | -// _tlv_atexit. |
51 | | -#[cfg(target_os = "macos")] |
52 | | -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { |
53 | | - use crate::cell::Cell; |
54 | | - use crate::mem; |
55 | | - use crate::ptr; |
56 | | - |
57 | | - #[thread_local] |
58 | | - static REGISTERED: Cell<bool> = Cell::new(false); |
59 | | - |
60 | | - #[thread_local] |
61 | | - static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new(); |
62 | | - |
63 | | - if !REGISTERED.get() { |
64 | | - _tlv_atexit(run_dtors, ptr::null_mut()); |
65 | | - REGISTERED.set(true); |
66 | | - } |
67 | | - |
68 | | - extern "C" { |
69 | | - fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8); |
70 | | - } |
71 | | - |
72 | | - let list = &mut DTORS; |
73 | | - list.push((t, dtor)); |
74 | | - |
75 | | - unsafe extern "C" fn run_dtors(_: *mut u8) { |
76 | | - let mut list = mem::take(&mut DTORS); |
77 | | - while !list.is_empty() { |
78 | | - for (ptr, dtor) in list { |
79 | | - dtor(ptr); |
80 | | - } |
81 | | - list = mem::take(&mut DTORS); |
82 | | - } |
83 | | - } |
84 | | -} |
85 | | - |
86 | | -#[cfg(any(target_os = "vxworks", target_os = "horizon", target_os = "emscripten"))] |
87 | | -#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten) |
88 | | -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { |
89 | | - use crate::sys_common::thread_local_dtor::register_dtor_fallback; |
90 | | - register_dtor_fallback(t, dtor); |
91 | | -} |
| 4 | +pub use crate::sys_common::thread_local_dtor::{ |
| 5 | + register_dtor_fallback as register_dtor, run_dtors, |
| 6 | +}; |
0 commit comments