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

#
std/sys/thread_local/
mod.rs

    1//! Implementation of the `thread_local` macro.
    2//!
    3//! There are three different thread-local implementations:
    4//! * Some targets lack threading support, and hence have only one thread, so
    5//!   the TLS data is stored in a normal `static`.
    6//! * Some targets support TLS natively via the dynamic linker and C runtime.
    7//! * On some targets, the OS provides a library-based TLS implementation. The
    8//!   TLS data is heap-allocated and referenced using a TLS key.
    9//!
    10//! Each implementation provides a macro which generates the `LocalKey` `const`
    11//! used to reference the TLS variable, along with the necessary helper structs
    12//! to track the initialization/destruction state of the variable.
    13//!
    14//! Additionally, this module contains abstractions for the OS interfaces used
    15//! for these implementations.
    16
    17#![cfg_attr(test, allow(unused))]
    18#![doc(hidden)]
    19#![forbid(unsafe_op_in_unsafe_fn)]
    20#![unstable(
    21    feature = "thread_local_internals",
    22    reason = "internal details of the thread_local macro",
    23    issue = "none"
    24)]
    25
    26cfg_select! {
    27    any(
    28        all(target_family = "wasm", not(target_feature = "atomics")),
    29        target_os = "uefi",
    30        target_os = "zkvm",
    31        target_os = "trusty",
    32        target_os = "vexos",
    33    ) => {
    34        mod no_threads;
    35        pub use no_threads::{EagerStorage, LazyStorage, thread_local_inner};
    36        pub(crate) use no_threads::{LocalPointer, local_pointer};
    37    }
    38    target_thread_local => {
    39        mod native;
    40        pub use native::{EagerStorage, LazyStorage, thread_local_inner};
    41        pub(crate) use native::{LocalPointer, local_pointer};
    42    }
    43    _ => {
    44        mod os;
    45        pub use os::{Storage, thread_local_inner, value_align};
    46        pub(crate) use os::{LocalPointer, local_pointer};
    47    }
    48}
    49
    50/// The native TLS implementation needs a way to register destructors for its data.
    51/// This module contains platform-specific implementations of that register.
    52///
    53/// It turns out however that most platforms don't have a way to register a
    54/// destructor for each variable. On these platforms, we keep track of the
    55/// destructors ourselves and register (through the [`guard`] module) only a
    56/// single callback that runs all of the destructors in the list.
    57#[cfg(all(target_thread_local, not(all(target_family = "wasm", not(target_feature = "atomics")))))]
    58pub(crate) mod destructors {
    59    cfg_select! {
    60        any(
    61            target_os = "linux",
    62            target_os = "android",
    63            target_os = "fuchsia",
    64            target_os = "redox",
    65            target_os = "hurd",
    66            target_os = "netbsd",
    67            target_os = "dragonfly"
    68        ) => {
    69            mod linux_like;
    70            mod list;
    71            pub(super) use linux_like::register;
    72            pub(super) use list::run;
    73        }
    74        _ => {
    75            mod list;
    76            pub(super) use list::register;
    77            pub(crate) use list::run;
    78        }
    79    }
    80}
    81
    82/// This module provides a way to schedule the execution of the destructor list
    83/// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling `enable`
    84/// should ensure that these functions are called at the right times.
    85pub(crate) mod guard {
    86    cfg_select! {
    87        all(target_thread_local, target_vendor = "apple") => {
    88            mod apple;
    89            pub(crate) use apple::enable;
    90        }
    91        target_os = "windows" => {
    92            mod windows;
    93            pub(crate) use windows::enable;
    94        }
    95        any(
    96            all(target_family = "wasm", not(
    97                all(target_os = "wasi", target_env = "p1", target_feature = "atomics")
    98            )),
    99            target_os = "uefi",
    100            target_os = "zkvm",
    101            target_os = "trusty",
    102            target_os = "vexos",
    103        ) => {
    104            pub(crate) fn enable() {
    105                // FIXME: Right now there is no concept of "thread exit" on
    106                // wasm, but this is likely going to show up at some point in
    107                // the form of an exported symbol that the wasm runtime is going
    108                // to be expected to call. For now we just leak everything, but
    109                // if such a function starts to exist it will probably need to
    110                // iterate the destructor list with these functions:
    111                #[cfg(all(target_family = "wasm", target_feature = "atomics"))]
    112                #[allow(unused)]
    113                use super::destructors::run;
    114                #[allow(unused)]
    115                use crate::rt::thread_cleanup;
    116            }
    117        }
    118        any(
    119            target_os = "hermit",
    120            target_os = "xous",
    121        ) => {
    122            // `std` is the only runtime, so it just calls the destructor functions
    123            // itself when the time comes.
    124            pub(crate) fn enable() {}
    125        }
    126        target_os = "solid_asp3" => {
    127            mod solid;
    128            pub(crate) use solid::enable;
    129        }
    130        _ => {
    131            mod key;
    132            pub(crate) use key::enable;
    133        }
    134    }
    135}
    136
    137/// `const`-creatable TLS keys.
    138///
    139/// Most OSs without native TLS will provide a library-based way to create TLS
    140/// storage. For each TLS variable, we create a key, which can then be used to
    141/// reference an entry in a thread-local table. This then associates each key
    142/// with a pointer which we can get and set to store our data.
    143pub(crate) mod key {
    144    cfg_select! {
    145        any(
    146            all(
    147                not(target_vendor = "apple"),
    148                not(target_family = "wasm"),
    149                target_family = "unix",
    150            ),
    151            all(not(target_thread_local), target_vendor = "apple"),
    152            target_os = "teeos",
    153            all(target_os = "wasi", target_env = "p1", target_feature = "atomics"),
    154        ) => {
    155            mod racy;
    156            mod unix;
    157            #[cfg(test)]
    158            mod tests;
    159            pub(super) use racy::LazyKey;
    160            pub(super) use unix::{Key, set};
    161            #[cfg(any(not(target_thread_local), test))]
    162            pub(super) use unix::get;
    163            use unix::{create, destroy};
    164        }
    165        all(not(target_thread_local), target_os = "windows") => {
    166            #[cfg(test)]
    167            mod tests;
    168            mod windows;
    169            pub(super) use windows::{Key, LazyKey, get, run_dtors, set};
    170        }
    171        all(target_vendor = "fortanix", target_env = "sgx") => {
    172            mod racy;
    173            mod sgx;
    174            #[cfg(test)]
    175            mod tests;
    176            pub(super) use racy::LazyKey;
    177            pub(super) use sgx::{Key, get, set};
    178            use sgx::{create, destroy};
    179        }
    180        target_os = "xous" => {
    181            mod racy;
    182            #[cfg(test)]
    183            mod tests;
    184            mod xous;
    185            pub(super) use racy::LazyKey;
    186            pub(crate) use xous::destroy_tls;
    187            pub(super) use xous::{Key, get, set};
    188            use xous::{create, destroy};
    189        }
    190        target_os = "motor" => {
    191            mod racy;
    192            #[cfg(test)]
    193            mod tests;
    194            pub(super) use racy::LazyKey;
    195            pub(super) use moto_rt::tls::{Key, get, set};
    196            use moto_rt::tls::{create, destroy};
    197        }
    198        _ => {}
    199    }
    200}
    201
    202/// Run a callback in a scenario which must not unwind (such as a `extern "C"
    203/// fn` declared in a user crate). If the callback unwinds anyway, then
    204/// `rtabort` with a message about thread local panicking on drop.
    205#[inline]
    206#[allow(dead_code)]
    207fn abort_on_dtor_unwind(f: impl FnOnce()) {
    208    // Using a guard like this is lower cost.
    209    let guard = DtorUnwindGuard;
    210    f();
    211    core::mem::forget(guard);
    212
    213    struct DtorUnwindGuard;
    214    impl Drop for DtorUnwindGuard {
    215        #[inline]
    216        fn drop(&mut self) {
    217            // This is not terribly descriptive, but it doesn't need to be as we'll
    218            // already have printed a panic message at this point.
    219            rtabort!("thread local panicked on drop");
    220        }
    221    }
    222}