]>
Commit | Line | Data |
---|---|---|
c30ab7b3 SL |
1 | // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | #![cfg(target_thread_local)] | |
12 | #![unstable(feature = "thread_local_internals", issue = "0")] | |
13 | ||
c30ab7b3 SL |
14 | // Since what appears to be glibc 2.18 this symbol has been shipped which |
15 | // GCC and clang both use to invoke destructors in thread_local globals, so | |
16 | // let's do the same! | |
17 | // | |
18 | // Note, however, that we run on lots older linuxes, as well as cross | |
19 | // compiling from a newer linux to an older linux, so we also have a | |
20 | // fallback implementation to use as well. | |
21 | // | |
22 | // Due to rust-lang/rust#18804, make sure this is not generic! | |
23 | #[cfg(target_os = "linux")] | |
041b39d2 | 24 | pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { |
c30ab7b3 | 25 | use libc; |
041b39d2 XL |
26 | use mem; |
27 | use sys_common::thread_local::register_dtor_fallback; | |
c30ab7b3 SL |
28 | |
29 | extern { | |
30 | #[linkage = "extern_weak"] | |
31 | static __dso_handle: *mut u8; | |
32 | #[linkage = "extern_weak"] | |
33 | static __cxa_thread_atexit_impl: *const libc::c_void; | |
34 | } | |
35 | if !__cxa_thread_atexit_impl.is_null() { | |
36 | type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), | |
37 | arg: *mut u8, | |
38 | dso_handle: *mut u8) -> libc::c_int; | |
39 | mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) | |
40 | (dtor, t, &__dso_handle as *const _ as *mut _); | |
41 | return | |
42 | } | |
43 | register_dtor_fallback(t, dtor); | |
44 | } | |
45 | ||
cc61c64b | 46 | // macOS's analog of the above linux function is this _tlv_atexit function. |
c30ab7b3 SL |
47 | // The disassembly of thread_local globals in C++ (at least produced by |
48 | // clang) will have this show up in the output. | |
49 | #[cfg(target_os = "macos")] | |
041b39d2 | 50 | pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { |
c30ab7b3 SL |
51 | extern { |
52 | fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), | |
53 | arg: *mut u8); | |
54 | } | |
55 | _tlv_atexit(dtor, t); | |
56 | } | |
57 | ||
58 | // Just use the thread_local fallback implementation, at least until there's | |
59 | // a more direct implementation. | |
60 | #[cfg(target_os = "fuchsia")] | |
041b39d2 | 61 | pub use sys_common::thread_local::register_dtor_fallback as register_dtor; |
c30ab7b3 | 62 | |
041b39d2 | 63 | pub fn requires_move_before_drop() -> bool { |
cc61c64b | 64 | // The macOS implementation of TLS apparently had an odd aspect to it |
c30ab7b3 SL |
65 | // where the pointer we have may be overwritten while this destructor |
66 | // is running. Specifically if a TLS destructor re-accesses TLS it may | |
67 | // trigger a re-initialization of all TLS variables, paving over at | |
68 | // least some destroyed ones with initial values. | |
69 | // | |
cc61c64b | 70 | // This means that if we drop a TLS value in place on macOS that we could |
c30ab7b3 SL |
71 | // revert the value to its original state halfway through the |
72 | // destructor, which would be bad! | |
73 | // | |
cc61c64b | 74 | // Hence, we use `ptr::read` on macOS (to move to a "safe" location) |
c30ab7b3 | 75 | // instead of drop_in_place. |
041b39d2 | 76 | cfg!(target_os = "macos") |
c30ab7b3 | 77 | } |