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}