|
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