diff options
Diffstat (limited to 'ctr-std/src/sys/horizon/fast_thread_local.rs')
| -rw-r--r-- | ctr-std/src/sys/horizon/fast_thread_local.rs | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/ctr-std/src/sys/horizon/fast_thread_local.rs b/ctr-std/src/sys/horizon/fast_thread_local.rs new file mode 100644 index 0000000..6cdbe5d --- /dev/null +++ b/ctr-std/src/sys/horizon/fast_thread_local.rs @@ -0,0 +1,77 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(target_thread_local)] +#![unstable(feature = "thread_local_internals", issue = "0")] + +// Since what appears to be glibc 2.18 this symbol has been shipped which +// GCC and clang both use to invoke destructors in thread_local globals, so +// let's do the same! +// +// Note, however, that we run on lots older linuxes, as well as cross +// compiling from a newer linux to an older linux, so we also have a +// fallback implementation to use as well. +// +// Due to rust-lang/rust#18804, make sure this is not generic! +#[cfg(target_os = "linux")] +pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + use libc; + use mem; + use sys_common::thread_local::register_dtor_fallback; + + extern { + #[linkage = "extern_weak"] + static __dso_handle: *mut u8; + #[linkage = "extern_weak"] + static __cxa_thread_atexit_impl: *const libc::c_void; + } + if !__cxa_thread_atexit_impl.is_null() { + type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), + arg: *mut u8, + dso_handle: *mut u8) -> libc::c_int; + mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) + (dtor, t, &__dso_handle as *const _ as *mut _); + return + } + register_dtor_fallback(t, dtor); +} + +// macOS's analog of the above linux function is this _tlv_atexit function. +// The disassembly of thread_local globals in C++ (at least produced by +// clang) will have this show up in the output. +#[cfg(target_os = "macos")] +pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + extern { + fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), + arg: *mut u8); + } + _tlv_atexit(dtor, t); +} + +// Just use the thread_local fallback implementation, at least until there's +// a more direct implementation. +#[cfg(target_os = "fuchsia")] +pub use sys_common::thread_local::register_dtor_fallback as register_dtor; + +pub fn requires_move_before_drop() -> bool { + // The macOS implementation of TLS apparently had an odd aspect to it + // where the pointer we have may be overwritten while this destructor + // is running. Specifically if a TLS destructor re-accesses TLS it may + // trigger a re-initialization of all TLS variables, paving over at + // least some destroyed ones with initial values. + // + // This means that if we drop a TLS value in place on macOS that we could + // revert the value to its original state halfway through the + // destructor, which would be bad! + // + // Hence, we use `ptr::read` on macOS (to move to a "safe" location) + // instead of drop_in_place. + cfg!(target_os = "macos") +} |