std/thread/
current.rs

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