| 1 | //! Thread local support for platforms with native TLS. |
| 2 | //! |
| 3 | //! To achieve the best performance, we choose from four different types for |
| 4 | //! the TLS variable, depending on the method of initialization used (`const` |
| 5 | //! or lazy) and the drop requirements of the stored type: |
| 6 | //! |
| 7 | //! | | `Drop` | `!Drop` | |
| 8 | //! |--------:|:--------------------:|:-------------------:| |
| 9 | //! | `const` | `EagerStorage<T>` | `T` | |
| 10 | //! | lazy | `LazyStorage<T, ()>` | `LazyStorage<T, !>` | |
| 11 | //! |
| 12 | //! For `const` initialization and `!Drop` types, we simply use `T` directly, |
| 13 | //! but for other situations, we implement a state machine to handle |
| 14 | //! initialization of the variable and its destructor and destruction. |
| 15 | //! Upon accessing the TLS variable, the current state is compared: |
| 16 | //! |
| 17 | //! 1. If the state is `Initial`, initialize the storage, transition the state |
| 18 | //! to `Alive` and (if applicable) register the destructor, and return a |
| 19 | //! reference to the value. |
| 20 | //! 2. If the state is `Alive`, initialization was previously completed, so |
| 21 | //! return a reference to the value. |
| 22 | //! 3. If the state is `Destroyed`, the destructor has been run already, so |
| 23 | //! return [`None`]. |
| 24 | //! |
| 25 | //! The TLS destructor sets the state to `Destroyed` and drops the current value. |
| 26 | //! |
| 27 | //! To simplify the code, we make `LazyStorage` generic over the destroyed state |
| 28 | //! and use the `!` type (never type) as type parameter for `!Drop` types. This |
| 29 | //! eliminates the `Destroyed` state for these values, which can allow more niche |
| 30 | //! optimizations to occur for the `State` enum. For `Drop` types, `()` is used. |
| 31 | |
| 32 | use crate::cell::Cell; |
| 33 | use crate::ptr; |
| 34 | |
| 35 | mod eager; |
| 36 | mod lazy; |
| 37 | |
| 38 | pub use eager::Storage as EagerStorage; |
| 39 | pub use lazy::Storage as LazyStorage; |
| 40 | |
| 41 | #[doc (hidden)] |
| 42 | #[allow_internal_unstable ( |
| 43 | thread_local_internals, |
| 44 | cfg_target_thread_local, |
| 45 | thread_local, |
| 46 | never_type |
| 47 | )] |
| 48 | #[allow_internal_unsafe ] |
| 49 | #[unstable (feature = "thread_local_internals" , issue = "none" )] |
| 50 | #[rustc_macro_transparency = "semitransparent" ] |
| 51 | pub macro thread_local_inner { |
| 52 | // NOTE: we cannot import `LocalKey`, `LazyStorage` or `EagerStorage` with a `use` because that |
| 53 | // can shadow user provided type or type alias with a matching name. Please update the shadowing |
| 54 | // test in `tests/thread.rs` if these types are renamed. |
| 55 | |
| 56 | // Used to generate the `LocalKey` value for const-initialized thread locals. |
| 57 | (@key $t:ty, const $init:expr) => {{ |
| 58 | const __INIT: $t = $init; |
| 59 | |
| 60 | unsafe { |
| 61 | $crate::thread::LocalKey::new(const { |
| 62 | if $crate::mem::needs_drop::<$t>() { |
| 63 | |_| { |
| 64 | #[thread_local] |
| 65 | static VAL: $crate::thread::local_impl::EagerStorage<$t> |
| 66 | = $crate::thread::local_impl::EagerStorage::new(__INIT); |
| 67 | VAL.get() |
| 68 | } |
| 69 | } else { |
| 70 | |_| { |
| 71 | #[thread_local] |
| 72 | static VAL: $t = __INIT; |
| 73 | &VAL |
| 74 | } |
| 75 | } |
| 76 | }) |
| 77 | } |
| 78 | }}, |
| 79 | |
| 80 | // used to generate the `LocalKey` value for `thread_local!` |
| 81 | (@key $t:ty, $init:expr) => {{ |
| 82 | #[inline] |
| 83 | fn __init() -> $t { |
| 84 | $init |
| 85 | } |
| 86 | |
| 87 | unsafe { |
| 88 | $crate::thread::LocalKey::new(const { |
| 89 | if $crate::mem::needs_drop::<$t>() { |
| 90 | |init| { |
| 91 | #[thread_local] |
| 92 | static VAL: $crate::thread::local_impl::LazyStorage<$t, ()> |
| 93 | = $crate::thread::local_impl::LazyStorage::new(); |
| 94 | VAL.get_or_init(init, __init) |
| 95 | } |
| 96 | } else { |
| 97 | |init| { |
| 98 | #[thread_local] |
| 99 | static VAL: $crate::thread::local_impl::LazyStorage<$t, !> |
| 100 | = $crate::thread::local_impl::LazyStorage::new(); |
| 101 | VAL.get_or_init(init, __init) |
| 102 | } |
| 103 | } |
| 104 | }) |
| 105 | } |
| 106 | }}, |
| 107 | ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { |
| 108 | $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = |
| 109 | $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); |
| 110 | }, |
| 111 | } |
| 112 | |
| 113 | #[rustc_macro_transparency = "semitransparent" ] |
| 114 | pub(crate) macro local_pointer { |
| 115 | () => {}, |
| 116 | ($vis:vis static $name:ident; $($rest:tt)*) => { |
| 117 | #[thread_local] |
| 118 | $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new(); |
| 119 | $crate::sys::thread_local::local_pointer! { $($rest)* } |
| 120 | }, |
| 121 | } |
| 122 | |
| 123 | pub(crate) struct LocalPointer { |
| 124 | p: Cell<*mut ()>, |
| 125 | } |
| 126 | |
| 127 | impl LocalPointer { |
| 128 | pub const fn __new() -> LocalPointer { |
| 129 | LocalPointer { p: Cell::new(ptr::null_mut()) } |
| 130 | } |
| 131 | |
| 132 | pub fn get(&self) -> *mut () { |
| 133 | self.p.get() |
| 134 | } |
| 135 | |
| 136 | pub fn set(&self, p: *mut ()) { |
| 137 | self.p.set(val:p) |
| 138 | } |
| 139 | } |
| 140 | |