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 = "semitransparent"]
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, 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"]
114pub(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
123pub(crate) struct LocalPointer {
124 p: Cell<*mut ()>,
125}
126
127impl 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(p)
138 }
139}