no_threads.rs - source
Description: Source of the Rust file `library/std/src/sys/thread_local/no_threads.rs`.

#
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 {}