std/sys/thread_local/
no_threads.rs

1//! On some targets like wasm there's no threads, so no need to generate
2//! thread locals and we can instead just use plain statics!
3
4use crate::cell::{Cell, UnsafeCell};
5use crate::ptr;
6
7#[doc(hidden)]
8#[allow_internal_unstable(thread_local_internals)]
9#[allow_internal_unsafe]
10#[unstable(feature = "thread_local_internals", issue = "none")]
11#[rustc_macro_transparency = "semitransparent"]
12pub macro thread_local_inner {
13    // used to generate the `LocalKey` value for const-initialized thread locals
14    (@key $t:ty, const $init:expr) => {{
15        const __INIT: $t = $init;
16
17        // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed.
18        unsafe {
19            $crate::thread::LocalKey::new(|_| {
20                static VAL: $crate::thread::local_impl::EagerStorage<$t> =
21                    $crate::thread::local_impl::EagerStorage { value: __INIT };
22                &VAL.value
23            })
24        }
25    }},
26
27    // used to generate the `LocalKey` value for `thread_local!`
28    (@key $t:ty, $init:expr) => {{
29        #[inline]
30        fn __init() -> $t { $init }
31
32        unsafe {
33            use $crate::thread::LocalKey;
34            use $crate::thread::local_impl::LazyStorage;
35
36            LocalKey::new(|init| {
37                static VAL: LazyStorage<$t> = LazyStorage::new();
38                VAL.get(init, __init)
39            })
40        }
41    }},
42    ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
43        $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
44            $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
45    },
46}
47
48#[allow(missing_debug_implementations)]
49pub struct EagerStorage<T> {
50    pub value: T,
51}
52
53// SAFETY: the target doesn't have threads.
54unsafe impl<T> Sync for EagerStorage<T> {}
55
56#[allow(missing_debug_implementations)]
57pub struct LazyStorage<T> {
58    value: UnsafeCell<Option<T>>,
59}
60
61impl<T> LazyStorage<T> {
62    pub const fn new() -> LazyStorage<T> {
63        LazyStorage { value: UnsafeCell::new(None) }
64    }
65
66    /// Gets a pointer to the TLS value, potentially initializing it with the
67    /// provided parameters.
68    ///
69    /// The resulting pointer may not be used after reentrant inialialization
70    /// has occurred.
71    #[inline]
72    pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
73        let value = unsafe { &*self.value.get() };
74        match value {
75            Some(v) => v,
76            None => self.initialize(i, f),
77        }
78    }
79
80    #[cold]
81    fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
82        let value = i.and_then(Option::take).unwrap_or_else(f);
83        // Destroy the old value, after updating the TLS variable as the
84        // destructor might reference it.
85        // FIXME(#110897): maybe panic on recursive initialization.
86        unsafe {
87            self.value.get().replace(Some(value));
88        }
89        // SAFETY: we just set this to `Some`.
90        unsafe { (*self.value.get()).as_ref().unwrap_unchecked() }
91    }
92}
93
94// SAFETY: the target doesn't have threads.
95unsafe impl<T> Sync for LazyStorage<T> {}
96
97#[rustc_macro_transparency = "semitransparent"]
98pub(crate) macro local_pointer {
99    () => {},
100    ($vis:vis static $name:ident; $($rest:tt)*) => {
101        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
102        $crate::sys::thread_local::local_pointer! { $($rest)* }
103    },
104}
105
106pub(crate) struct LocalPointer {
107    p: Cell<*mut ()>,
108}
109
110impl LocalPointer {
111    pub const fn __new() -> LocalPointer {
112        LocalPointer { p: Cell::new(ptr::null_mut()) }
113    }
114
115    pub fn get(&self) -> *mut () {
116        self.p.get()
117    }
118
119    pub fn set(&self, p: *mut ()) {
120        self.p.set(p)
121    }
122}
123
124// SAFETY: the target doesn't have threads.
125unsafe impl Sync for LocalPointer {}