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::mem::MaybeUninit;
6use crate::ptr;
7
8#[doc(hidden)]
9#[allow_internal_unstable(thread_local_internals)]
10#[allow_internal_unsafe]
11#[unstable(feature = "thread_local_internals", issue = "none")]
12#[rustc_macro_transparency = "semiopaque"]
13pub macro thread_local_inner {
14    // used to generate the `LocalKey` value for const-initialized thread locals
15    (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{
16        const __RUST_STD_INTERNAL_INIT: $t = $init;
17
18        // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed.
19        unsafe {
20            $crate::thread::LocalKey::new(|_| {
21                $(#[$align_attr])*
22                static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::EagerStorage<$t> =
23                    $crate::thread::local_impl::EagerStorage { value: __RUST_STD_INTERNAL_INIT };
24                &__RUST_STD_INTERNAL_VAL.value
25            })
26        }
27    }},
28
29    // used to generate the `LocalKey` value for `thread_local!`
30    (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
31        #[inline]
32        fn __rust_std_internal_init_fn() -> $t { $init }
33
34        unsafe {
35            $crate::thread::LocalKey::new(|__rust_std_internal_init| {
36                $(#[$align_attr])*
37                static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new();
38                __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, __rust_std_internal_init_fn)
39            })
40        }
41    }},
42}
43
44#[allow(missing_debug_implementations)]
45#[repr(transparent)] // Required for correctness of `#[rustc_align_static]`
46pub struct EagerStorage<T> {
47    pub value: T,
48}
49
50// SAFETY: the target doesn't have threads.
51unsafe impl<T> Sync for EagerStorage<T> {}
52
53#[derive(Clone, Copy, PartialEq, Eq)]
54enum State {
55    Initial,
56    Alive,
57    Destroying,
58}
59
60#[allow(missing_debug_implementations)]
61#[repr(C)]
62pub struct LazyStorage<T> {
63    // This field must be first, for correctness of `#[rustc_align_static]`
64    value: UnsafeCell<MaybeUninit<T>>,
65    state: Cell<State>,
66}
67
68impl<T> LazyStorage<T> {
69    pub const fn new() -> LazyStorage<T> {
70        LazyStorage {
71            value: UnsafeCell::new(MaybeUninit::uninit()),
72            state: Cell::new(State::Initial),
73        }
74    }
75
76    /// Gets a pointer to the TLS value, potentially initializing it with the
77    /// provided parameters.
78    ///
79    /// The resulting pointer may not be used after reentrant inialialization
80    /// has occurred.
81    #[inline]
82    pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
83        if self.state.get() == State::Alive {
84            self.value.get() as *const T
85        } else {
86            self.initialize(i, f)
87        }
88    }
89
90    #[cold]
91    fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
92        let value = i.and_then(Option::take).unwrap_or_else(f);
93
94        // Destroy the old value if it is initialized
95        // FIXME(#110897): maybe panic on recursive initialization.
96        if self.state.get() == State::Alive {
97            self.state.set(State::Destroying);
98            // Safety: we check for no initialization during drop below
99            unsafe {
100                ptr::drop_in_place(self.value.get() as *mut T);
101            }
102            self.state.set(State::Initial);
103        }
104
105        // Guard against initialization during drop
106        if self.state.get() == State::Destroying {
107            panic!("Attempted to initialize thread-local while it is being dropped");
108        }
109
110        unsafe {
111            self.value.get().write(MaybeUninit::new(value));
112        }
113        self.state.set(State::Alive);
114
115        self.value.get() as *const T
116    }
117}
118
119// SAFETY: the target doesn't have threads.
120unsafe impl<T> Sync for LazyStorage<T> {}
121
122#[rustc_macro_transparency = "semiopaque"]
123pub(crate) macro local_pointer {
124    () => {},
125    ($vis:vis static $name:ident; $($rest:tt)*) => {
126        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
127        $crate::sys::thread_local::local_pointer! { $($rest)* }
128    },
129}
130
131pub(crate) struct LocalPointer {
132    p: Cell<*mut ()>,
133}
134
135impl LocalPointer {
136    pub const fn __new() -> LocalPointer {
137        LocalPointer { p: Cell::new(ptr::null_mut()) }
138    }
139
140    pub fn get(&self) -> *mut () {
141        self.p.get()
142    }
143
144    pub fn set(&self, p: *mut ()) {
145        self.p.set(p)
146    }
147}
148
149// SAFETY: the target doesn't have threads.
150unsafe impl Sync for LocalPointer {}