Skip to main content

std/sys/thread_local/
os.rs

1use super::key::{Key, LazyKey, get, set};
2use super::{abort_on_dtor_unwind, guard};
3use crate::alloc::{self, GlobalAlloc, Layout, System};
4use crate::cell::Cell;
5use crate::marker::PhantomData;
6use crate::mem::ManuallyDrop;
7use crate::ops::Deref;
8use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
9use crate::ptr::{self, NonNull};
10
11#[doc(hidden)]
12#[allow_internal_unstable(thread_local_internals)]
13#[allow_internal_unsafe]
14#[unstable(feature = "thread_local_internals", issue = "none")]
15#[rustc_macro_transparency = "semiopaque"]
16pub macro thread_local_inner {
17    // NOTE: we cannot import `Storage` or `LocalKey` with a `use` because that can shadow user
18    // provided type or type alias with a matching name. Please update the shadowing test in
19    // `tests/thread.rs` if these types are renamed.
20
21    // used to generate the `LocalKey` value for `thread_local!`.
22    (@key $t:ty, $($(#[$($align_attr:tt)*])+)?, $init:expr) => {{
23        #[inline]
24        fn __rust_std_internal_init_fn() -> $t { $init }
25
26        // NOTE: this cannot import `LocalKey` or `Storage` with a `use` because that can shadow
27        // user provided type or type alias with a matching name. Please update the shadowing test
28        // in `tests/thread.rs` if these types are renamed.
29        unsafe {
30            $crate::thread::LocalKey::new(|__rust_std_internal_init| {
31                static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::Storage<$t, {
32                    $({
33                        // Ensure that attributes have valid syntax
34                        // and that the proper feature gate is enabled
35                        $(#[$($align_attr)*])+
36                        #[allow(unused)]
37                        static DUMMY: () = ();
38                    })?
39
40                    #[allow(unused_mut)]
41                    let mut final_align = $crate::thread::local_impl::value_align::<$t>();
42                    $($($crate::thread::local_impl::thread_local_inner!(@align final_align, $($align_attr)*);)+)?
43                    final_align
44                }>
45                    = $crate::thread::local_impl::Storage::new();
46                __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, __rust_std_internal_init_fn)
47            })
48        }
49    }},
50
51    // process a single `rustc_align_static` attribute
52    (@align $final_align:ident, rustc_align_static($($align:tt)*) $(, $($attr_rest:tt)+)?) => {
53        let new_align: $crate::primitive::usize = $($align)*;
54        if new_align > $final_align {
55            $final_align = new_align;
56        }
57
58        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
59    },
60
61    // process a single `cfg_attr` attribute
62    // by translating it into a `cfg`ed block and recursing.
63    // https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate
64
65    (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
66        #[cfg(true)]
67        {
68            $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
69        }
70
71        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
72    },
73
74    (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
75        #[cfg(false)]
76        {
77            $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
78        }
79
80        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
81    },
82
83    (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
84        #[cfg($cfg_pred)]
85        {
86            $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
87        }
88
89        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
90    },
91}
92
93/// Use a regular global static to store this key; the state provided will then be
94/// thread-local.
95/// INVARIANT: ALIGN must be a valid alignment, and no less than `value_align::<T>`.
96#[allow(missing_debug_implementations)]
97pub struct Storage<T, const ALIGN: usize> {
98    key: LazyKey,
99    marker: PhantomData<Cell<T>>,
100}
101
102unsafe impl<T, const ALIGN: usize> Sync for Storage<T, ALIGN> {}
103
104#[repr(C)]
105struct Value<T: 'static> {
106    // This field must be first, for correctness of `#[rustc_align_static]`
107    value: T,
108    // INVARIANT: if this value is stored under a TLS key, `key` must be that `key`.
109    key: Key,
110}
111
112pub const fn value_align<T: 'static>() -> usize {
113    crate::mem::align_of::<Value<T>>()
114}
115
116/// Equivalent to `Box<Value<T>, System>`, but potentially over-aligned.
117struct AlignedSystemBox<T: 'static, const ALIGN: usize> {
118    ptr: NonNull<Value<T>>,
119}
120
121impl<T: 'static, const ALIGN: usize> AlignedSystemBox<T, ALIGN> {
122    #[inline]
123    fn new(v: Value<T>) -> Self {
124        let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap();
125
126        // We use the System allocator here to avoid interfering with a potential
127        // Global allocator using thread-local storage.
128        let ptr: *mut Value<T> = (unsafe { System.alloc(layout) }).cast();
129        let Some(ptr) = NonNull::new(ptr) else {
130            alloc::handle_alloc_error(layout);
131        };
132        unsafe { ptr.write(v) };
133        Self { ptr }
134    }
135
136    #[inline]
137    fn into_raw(b: Self) -> *mut Value<T> {
138        let md = ManuallyDrop::new(b);
139        md.ptr.as_ptr()
140    }
141
142    #[inline]
143    unsafe fn from_raw(ptr: *mut Value<T>) -> Self {
144        Self { ptr: unsafe { NonNull::new_unchecked(ptr) } }
145    }
146}
147
148impl<T: 'static, const ALIGN: usize> Deref for AlignedSystemBox<T, ALIGN> {
149    type Target = Value<T>;
150
151    #[inline]
152    fn deref(&self) -> &Self::Target {
153        unsafe { &*(self.ptr.as_ptr()) }
154    }
155}
156
157impl<T: 'static, const ALIGN: usize> Drop for AlignedSystemBox<T, ALIGN> {
158    #[inline]
159    fn drop(&mut self) {
160        let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap();
161
162        unsafe {
163            let unwind_result = catch_unwind(AssertUnwindSafe(|| self.ptr.drop_in_place()));
164            System.dealloc(self.ptr.as_ptr().cast(), layout);
165            if let Err(payload) = unwind_result {
166                resume_unwind(payload);
167            }
168        }
169    }
170}
171
172impl<T: 'static, const ALIGN: usize> Storage<T, ALIGN> {
173    pub const fn new() -> Storage<T, ALIGN> {
174        Storage { key: LazyKey::new(Some(destroy_value::<T, ALIGN>)), marker: PhantomData }
175    }
176
177    /// Gets a pointer to the TLS value, potentially initializing it with the
178    /// provided parameters. If the TLS variable has been destroyed, a null
179    /// pointer is returned.
180    ///
181    /// The resulting pointer may not be used after reentrant inialialization
182    /// or thread destruction has occurred.
183    pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
184        let key = self.key.force();
185        let ptr = unsafe { get(key) as *mut Value<T> };
186        if ptr.addr() > 1 {
187            // SAFETY: the check ensured the pointer is safe (its destructor
188            // is not running) + it is coming from a trusted source (self).
189            unsafe { &(*ptr).value }
190        } else {
191            // SAFETY: trivially correct.
192            unsafe { Self::try_initialize(key, ptr, i, f) }
193        }
194    }
195
196    /// # Safety
197    /// * `key` must be the result of calling `self.key.force()`
198    /// * `ptr` must be the current value associated with `key`.
199    unsafe fn try_initialize(
200        key: Key,
201        ptr: *mut Value<T>,
202        i: Option<&mut Option<T>>,
203        f: impl FnOnce() -> T,
204    ) -> *const T {
205        if ptr.addr() == 1 {
206            // destructor is running
207            return ptr::null();
208        }
209
210        let value = AlignedSystemBox::<T, ALIGN>::new(Value {
211            value: i.and_then(Option::take).unwrap_or_else(f),
212            key,
213        });
214        let ptr = AlignedSystemBox::into_raw(value);
215
216        // SAFETY:
217        // * key came from a `LazyKey` and is thus correct.
218        // * `ptr` is a correct pointer that can be destroyed by the key destructor.
219        // * the value is stored under the key that it contains.
220        let old = unsafe {
221            let old = get(key) as *mut Value<T>;
222            set(key, ptr as *mut u8);
223            old
224        };
225
226        if !old.is_null() {
227            // If the variable was recursively initialized, drop the old value.
228            // SAFETY: We cannot be inside a `LocalKey::with` scope, as the
229            // initializer has already returned and the next scope only starts
230            // after we return the pointer. Therefore, there can be no references
231            // to the old value.
232            drop(unsafe { AlignedSystemBox::<T, ALIGN>::from_raw(old) });
233        }
234
235        // SAFETY: We just created this value above.
236        unsafe { &(*ptr).value }
237    }
238}
239
240unsafe extern "C" fn destroy_value<T: 'static, const ALIGN: usize>(ptr: *mut u8) {
241    // SAFETY:
242    //
243    // The OS TLS ensures that this key contains a null value when this
244    // destructor starts to run. We set it back to a sentinel value of 1 to
245    // ensure that any future calls to `get` for this thread will return
246    // `None`.
247    //
248    // Note that to prevent an infinite loop we reset it back to null right
249    // before we return from the destructor ourselves.
250    abort_on_dtor_unwind(|| {
251        let ptr = unsafe { AlignedSystemBox::<T, ALIGN>::from_raw(ptr as *mut Value<T>) };
252        let key = ptr.key;
253        // SAFETY: `key` is the TLS key `ptr` was stored under.
254        unsafe { set(key, ptr::without_provenance_mut(1)) };
255        drop(ptr);
256        // SAFETY: `key` is the TLS key `ptr` was stored under.
257        unsafe { set(key, ptr::null_mut()) };
258        // Make sure that the runtime cleanup will be performed
259        // after the next round of TLS destruction.
260        guard::enable();
261    });
262}
263
264#[rustc_macro_transparency = "semiopaque"]
265pub(crate) macro local_pointer {
266    () => {},
267    ($vis:vis static $name:ident; $($rest:tt)*) => {
268        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
269        $crate::sys::thread_local::local_pointer! { $($rest)* }
270    },
271}
272
273pub(crate) struct LocalPointer {
274    key: LazyKey,
275}
276
277impl LocalPointer {
278    pub const fn __new() -> LocalPointer {
279        LocalPointer { key: LazyKey::new(None) }
280    }
281
282    pub fn get(&'static self) -> *mut () {
283        unsafe { get(self.key.force()) as *mut () }
284    }
285
286    pub fn set(&'static self, p: *mut ()) {
287        unsafe { set(self.key.force(), p as *mut u8) }
288    }
289}