current.rs - source
Description: Source of the Rust file `library/std/src/thread/current.rs`.

#
std/thread/
current.rs

    1use super::id::ThreadId;
    2use super::main_thread;
    3use super::thread::Thread;
    4use crate::mem::ManuallyDrop;
    5use crate::ptr;
    6use crate::sys::thread as imp;
    7use crate::sys::thread_local::local_pointer;
    8
    9const NONE: *mut () = ptr::null_mut();
    10const BUSY: *mut () = ptr::without_provenance_mut(1);
    11const DESTROYED: *mut () = ptr::without_provenance_mut(2);
    12
    13local_pointer! {
    14    static CURRENT;
    15}
    16
    17/// Persistent storage for the thread ID.
    18///
    19/// We store the thread ID so that it never gets destroyed during the lifetime
    20/// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s.
    21pub(super) mod id {
    22    use super::*;
    23
    24    cfg_select! {
    25        target_thread_local => {
    26            use crate::cell::Cell;
    27
    28            #[thread_local]
    29            static ID: Cell<Option<ThreadId>> = Cell::new(None);
    30
    31            pub(super) const CHEAP: bool = true;
    32
    33            pub(crate) fn get() -> Option<ThreadId> {
    34                ID.get()
    35            }
    36
    37            pub(super) fn set(id: ThreadId) {
    38                ID.set(Some(id))
    39            }
    40        }
    41        target_pointer_width = "16" => {
    42            local_pointer! {
    43                static ID0;
    44                static ID16;
    45                static ID32;
    46                static ID48;
    47            }
    48
    49            pub(super) const CHEAP: bool = false;
    50
    51            pub(crate) fn get() -> Option<ThreadId> {
    52                let id0 = ID0.get().addr() as u64;
    53                let id16 = ID16.get().addr() as u64;
    54                let id32 = ID32.get().addr() as u64;
    55                let id48 = ID48.get().addr() as u64;
    56                ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0)
    57            }
    58
    59            pub(super) fn set(id: ThreadId) {
    60                let val = id.as_u64().get();
    61                ID0.set(ptr::without_provenance_mut(val as usize));
    62                ID16.set(ptr::without_provenance_mut((val >> 16) as usize));
    63                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
    64                ID48.set(ptr::without_provenance_mut((val >> 48) as usize));
    65            }
    66        }
    67        target_pointer_width = "32" => {
    68            local_pointer! {
    69                static ID0;
    70                static ID32;
    71            }
    72
    73            pub(super) const CHEAP: bool = false;
    74
    75            pub(crate) fn get() -> Option<ThreadId> {
    76                let id0 = ID0.get().addr() as u64;
    77                let id32 = ID32.get().addr() as u64;
    78                ThreadId::from_u64((id32 << 32) + id0)
    79            }
    80
    81            pub(super) fn set(id: ThreadId) {
    82                let val = id.as_u64().get();
    83                ID0.set(ptr::without_provenance_mut(val as usize));
    84                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
    85            }
    86        }
    87        _ => {
    88            local_pointer! {
    89                static ID;
    90            }
    91
    92            pub(super) const CHEAP: bool = true;
    93
    94            pub(crate) fn get() -> Option<ThreadId> {
    95                let id = ID.get().addr() as u64;
    96                ThreadId::from_u64(id)
    97            }
    98
    99            pub(super) fn set(id: ThreadId) {
    100                let val = id.as_u64().get();
    101                ID.set(ptr::without_provenance_mut(val as usize));
    102            }
    103        }
    104    }
    105
    106    #[inline]
    107    pub(super) fn get_or_init() -> ThreadId {
    108        get().unwrap_or_else(
    109            #[cold]
    110            || {
    111                let id = ThreadId::new();
    112                id::set(id);
    113                id
    114            },
    115        )
    116    }
    117}
    118
    119/// Tries to set the thread handle for the current thread. Fails if a handle was
    120/// already set or if the thread ID of `thread` would change an already-set ID.
    121pub(super) fn set_current(thread: Thread) -> Result<(), Thread> {
    122    if CURRENT.get() != NONE {
    123        return Err(thread);
    124    }
    125
    126    match id::get() {
    127        Some(id) if id == thread.id() => {}
    128        None => id::set(thread.id()),
    129        _ => return Err(thread),
    130    }
    131
    132    // Make sure that `crate::rt::thread_cleanup` will be run, which will
    133    // call `drop_current`.
    134    crate::sys::thread_local::guard::enable();
    135    CURRENT.set(thread.into_raw().cast_mut());
    136    Ok(())
    137}
    138
    139/// Gets the unique identifier of the thread which invokes it.
    140///
    141/// Calling this function may be more efficient than accessing the current
    142/// thread id through the current thread handle. i.e. `thread::current().id()`.
    143///
    144/// This function will always succeed, will always return the same value for
    145/// one thread and is guaranteed not to call the global allocator.
    146///
    147/// # Examples
    148///
    149/// ```
    150/// #![feature(current_thread_id)]
    151///
    152/// use std::thread;
    153///
    154/// let other_thread = thread::spawn(|| {
    155///     thread::current_id()
    156/// });
    157///
    158/// let other_thread_id = other_thread.join().unwrap();
    159/// assert_ne!(thread::current_id(), other_thread_id);
    160/// ```
    161#[inline]
    162#[must_use]
    163#[unstable(feature = "current_thread_id", issue = "147194")]
    164pub fn current_id() -> ThreadId {
    165    // If accessing the persistent thread ID takes multiple TLS accesses, try
    166    // to retrieve it from the current thread handle, which will only take one
    167    // TLS access.
    168    if !id::CHEAP {
    169        if let Some(id) = try_with_current(|t| t.map(|t| t.id())) {
    170            return id;
    171        }
    172    }
    173
    174    id::get_or_init()
    175}
    176
    177/// Gets the OS thread ID of the thread that invokes it, if available. If not, return the Rust
    178/// thread ID.
    179///
    180/// We use a `u64` to all possible platform IDs without excess `cfg`; most use `int`, some use a
    181/// pointer, and Apple uses `uint64_t`. This is a "best effort" approach for diagnostics and is
    182/// allowed to fall back to a non-OS ID (such as the Rust thread ID) or a non-unique ID (such as a
    183/// PID) if the thread ID cannot be retrieved.
    184pub(crate) fn current_os_id() -> u64 {
    185    imp::current_os_id().unwrap_or_else(|| current_id().as_u64().get())
    186}
    187
    188/// Gets a reference to the handle of the thread that invokes it, if the handle
    189/// has been initialized.
    190fn try_with_current<F, R>(f: F) -> R
    191where
    192    F: FnOnce(Option<&Thread>) -> R,
    193{
    194    let current = CURRENT.get();
    195    if current > DESTROYED {
    196        // SAFETY: `Arc` does not contain interior mutability, so it does not
    197        // matter that the address of the handle might be different depending
    198        // on where this is called.
    199        unsafe {
    200            let current = ManuallyDrop::new(Thread::from_raw(current));
    201            f(Some(&current))
    202        }
    203    } else {
    204        f(None)
    205    }
    206}
    207
    208/// Run a function with the current thread's name.
    209///
    210/// Modulo thread local accesses, this function is safe to call from signal
    211/// handlers and in similar circumstances where allocations are not possible.
    212pub(crate) fn with_current_name<F, R>(f: F) -> R
    213where
    214    F: FnOnce(Option<&str>) -> R,
    215{
    216    try_with_current(|thread| {
    217        let name = if let Some(thread) = thread {
    218            // If there is a current thread handle, try to use the name stored
    219            // there.
    220            thread.name()
    221        } else if let Some(main) = main_thread::get()
    222            && let Some(id) = id::get()
    223            && id == main
    224        {
    225            // The main thread doesn't always have a thread handle, we must
    226            // identify it through its ID instead. The checks are ordered so
    227            // that the current ID is only loaded if it is actually needed,
    228            // since loading it from TLS might need multiple expensive accesses.
    229            Some("main")
    230        } else {
    231            None
    232        };
    233
    234        f(name)
    235    })
    236}
    237
    238/// Gets a handle to the thread that invokes it. If the handle stored in thread-
    239/// local storage was already destroyed, this creates a new unnamed temporary
    240/// handle to allow thread parking in nearly all situations.
    241pub(crate) fn current_or_unnamed() -> Thread {
    242    let current = CURRENT.get();
    243    if current > DESTROYED {
    244        unsafe {
    245            let current = ManuallyDrop::new(Thread::from_raw(current));
    246            (*current).clone()
    247        }
    248    } else if current == DESTROYED {
    249        Thread::new(id::get_or_init(), None)
    250    } else {
    251        init_current(current)
    252    }
    253}
    254
    255/// Gets a handle to the thread that invokes it.
    256///
    257/// # Examples
    258///
    259/// Getting a handle to the current thread with `thread::current()`:
    260///
    261/// ```
    262/// use std::thread;
    263///
    264/// let handler = thread::Builder::new()
    265///     .name("named thread".into())
    266///     .spawn(|| {
    267///         let handle = thread::current();
    268///         assert_eq!(handle.name(), Some("named thread"));
    269///     })
    270///     .unwrap();
    271///
    272/// handler.join().unwrap();
    273/// ```
    274#[must_use]
    275#[stable(feature = "rust1", since = "1.0.0")]
    276pub fn current() -> Thread {
    277    let current = CURRENT.get();
    278    if current > DESTROYED {
    279        unsafe {
    280            let current = ManuallyDrop::new(Thread::from_raw(current));
    281            (*current).clone()
    282        }
    283    } else {
    284        init_current(current)
    285    }
    286}
    287
    288#[cold]
    289fn init_current(current: *mut ()) -> Thread {
    290    if current == NONE {
    291        CURRENT.set(BUSY);
    292        // If the thread ID was initialized already, use it.
    293        let id = id::get_or_init();
    294        let thread = Thread::new(id, None);
    295
    296        // Make sure that `crate::rt::thread_cleanup` will be run, which will
    297        // call `drop_current`.
    298        crate::sys::thread_local::guard::enable();
    299        CURRENT.set(thread.clone().into_raw().cast_mut());
    300        thread
    301    } else if current == BUSY {
    302        // BUSY exists solely for this check, but as it is in the slow path, the
    303        // extra TLS write above shouldn't matter. The alternative is nearly always
    304        // a stack overflow.
    305        //
    306        // If we reach this point it means our initialization routine ended up
    307        // calling current() either directly, or indirectly through the global
    308        // allocator, which is a bug either way as we may not call the global
    309        // allocator in current().
    310        rtabort!(
    311            "init_current() was re-entrant, which indicates a bug in the Rust threading implementation"
    312        )
    313    } else {
    314        debug_assert_eq!(current, DESTROYED);
    315        panic!(
    316            "use of std::thread::current() is not possible after the thread's \
    317            local data has been destroyed"
    318        )
    319    }
    320}
    321
    322/// This should be run in [`crate::rt::thread_cleanup`] to reset the thread
    323/// handle.
    324pub(crate) fn drop_current() {
    325    let current = CURRENT.get();
    326    if current > DESTROYED {
    327        unsafe {
    328            CURRENT.set(DESTROYED);
    329            drop(Thread::from_raw(current));
    330        }
    331    }
    332}