//! Thread local support for platforms with native TLS. //! //! To achieve the best performance, we choose from four different types for //! the TLS variable, depending on the method of initialization used (`const` //! or lazy) and the drop requirements of the stored type: //! //! | | `Drop` | `!Drop` | //! |--------:|:--------------------:|:-------------------:| //! | `const` | `EagerStorage` | `T` | //! | lazy | `LazyStorage` | `LazyStorage` | //! //! For `const` initialization and `!Drop` types, we simply use `T` directly, //! but for other situations, we implement a state machine to handle //! initialization of the variable and its destructor and destruction. //! Upon accessing the TLS variable, the current state is compared: //! //! 1. If the state is `Initial`, initialize the storage, transition the state //! to `Alive` and (if applicable) register the destructor, and return a //! reference to the value. //! 2. If the state is `Alive`, initialization was previously completed, so //! return a reference to the value. //! 3. If the state is `Destroyed`, the destructor has been run already, so //! return [`None`]. //! //! The TLS destructor sets the state to `Destroyed` and drops the current value. //! //! To simplify the code, we make `LazyStorage` generic over the destroyed state //! and use the `!` type (never type) as type parameter for `!Drop` types. This //! eliminates the `Destroyed` state for these values, which can allow more niche //! optimizations to occur for the `State` enum. For `Drop` types, `()` is used. use crate::cell::Cell; use crate::ptr; mod eager; mod lazy; pub use eager::Storage as EagerStorage; pub use lazy::Storage as LazyStorage; #[doc(hidden)] #[allow_internal_unstable( thread_local_internals, cfg_target_thread_local, thread_local, never_type )] #[allow_internal_unsafe] #[unstable(feature = "thread_local_internals", issue = "none")] #[rustc_macro_transparency = "semitransparent"] pub macro thread_local_inner { // NOTE: we cannot import `LocalKey`, `LazyStorage` or `EagerStorage` with a `use` because that // can shadow user provided type or type alias with a matching name. Please update the shadowing // test in `tests/thread.rs` if these types are renamed. // Used to generate the `LocalKey` value for const-initialized thread locals. (@key $t:ty, const $init:expr) => {{ const __INIT: $t = $init; unsafe { $crate::thread::LocalKey::new(const { if $crate::mem::needs_drop::<$t>() { |_| { #[thread_local] static VAL: $crate::thread::local_impl::EagerStorage<$t> = $crate::thread::local_impl::EagerStorage::new(__INIT); VAL.get() } } else { |_| { #[thread_local] static VAL: $t = __INIT; &VAL } } }) } }}, // used to generate the `LocalKey` value for `thread_local!` (@key $t:ty, $init:expr) => {{ #[inline] fn __init() -> $t { $init } unsafe { $crate::thread::LocalKey::new(const { if $crate::mem::needs_drop::<$t>() { |init| { #[thread_local] static VAL: $crate::thread::local_impl::LazyStorage<$t, ()> = $crate::thread::local_impl::LazyStorage::new(); VAL.get_or_init(init, __init) } } else { |init| { #[thread_local] static VAL: $crate::thread::local_impl::LazyStorage<$t, !> = $crate::thread::local_impl::LazyStorage::new(); VAL.get_or_init(init, __init) } } }) } }}, ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); }, } #[rustc_macro_transparency = "semitransparent"] pub(crate) macro local_pointer { () => {}, ($vis:vis static $name:ident; $($rest:tt)*) => { #[thread_local] $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new(); $crate::sys::thread_local::local_pointer! { $($rest)* } }, } pub(crate) struct LocalPointer { p: Cell<*mut ()>, } impl LocalPointer { pub const fn __new() -> LocalPointer { LocalPointer { p: Cell::new(ptr::null_mut()) } } pub fn get(&self) -> *mut () { self.p.get() } pub fn set(&self, p: *mut ()) { self.p.set(p) } }