Skip to main content

std/sys/thread_local/native/
mod.rs

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
32use crate::cell::Cell;
33use crate::ptr;
34
35mod eager;
36mod lazy;
37
38pub use eager::Storage as EagerStorage;
39pub 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 = "semiopaque"]
51pub 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, $(#[$align_attr:meta])*, const $init:expr) => {{
58        const __RUST_STD_INTERNAL_INIT: $t = $init;
59
60        unsafe {
61            $crate::thread::LocalKey::new(const {
62                // We're okay to ignore `__rust_std_internal_init` as we never panic.
63                if $crate::mem::needs_drop::<$t>() {
64                    |__rust_std_internal_init| {
65                        #[thread_local]
66                        $(#[$align_attr])*
67                        static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::EagerStorage<$t>
68                            = $crate::thread::local_impl::EagerStorage::new(__RUST_STD_INTERNAL_INIT);
69                        __RUST_STD_INTERNAL_VAL.get()
70                    }
71                } else {
72                    |__rust_std_internal_init| {
73                        #[thread_local]
74                        $(#[$align_attr])*
75                        static __RUST_STD_INTERNAL_VAL: $t = __RUST_STD_INTERNAL_INIT;
76                        &__RUST_STD_INTERNAL_VAL
77                    }
78                }
79            })
80        }
81    }},
82
83    // used to generate the `LocalKey` value for `thread_local!`
84    (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
85        // We intentionally have an argument-position `'static` lifetime so that elided lifetimes in `$t`
86        // become `'static` like they do for `const`s and `static`s, including in the other two
87        // `thread_local!` implementations.
88        #[allow(mismatched_lifetime_syntaxes)]
89        #[inline]
90        fn __rust_std_internal_init_fn(_lifetime_elision: $crate::marker::PhantomData<&'static ()>) -> $t {
91            $init
92        }
93
94        unsafe {
95            $crate::thread::LocalKey::new(const {
96                // `__rust_std_internal_init_fn` may panic so we must only call it if there is no
97                // `__rust_std_internal_init`.
98                if $crate::mem::needs_drop::<$t>() {
99                    |__rust_std_internal_init| {
100                        #[thread_local]
101                        $(#[$align_attr])*
102                        static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::LazyStorage<$t, ()>
103                            = $crate::thread::local_impl::LazyStorage::new();
104                        __RUST_STD_INTERNAL_VAL.get_or_init(__rust_std_internal_init, || __rust_std_internal_init_fn($crate::marker::PhantomData))
105                    }
106                } else {
107                    |__rust_std_internal_init| {
108                        #[thread_local]
109                        $(#[$align_attr])*
110                        static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::LazyStorage<$t, !>
111                            = $crate::thread::local_impl::LazyStorage::new();
112                        __RUST_STD_INTERNAL_VAL.get_or_init(__rust_std_internal_init, || __rust_std_internal_init_fn($crate::marker::PhantomData))
113                    }
114                }
115            })
116        }
117    }},
118}
119
120#[rustc_macro_transparency = "semiopaque"]
121pub(crate) macro local_pointer {
122    () => {},
123    ($vis:vis static $name:ident; $($rest:tt)*) => {
124        #[thread_local]
125        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
126        $crate::sys::thread_local::local_pointer! { $($rest)* }
127    },
128}
129
130pub(crate) struct LocalPointer {
131    p: Cell<*mut ()>,
132}
133
134impl LocalPointer {
135    pub const fn __new() -> LocalPointer {
136        LocalPointer { p: Cell::new(ptr::null_mut()) }
137    }
138
139    pub fn get(&self) -> *mut () {
140        self.p.get()
141    }
142
143    pub fn set(&self, p: *mut ()) {
144        self.p.set(p)
145    }
146}