1//! Store the ID of the main thread.
2//!
3//! The thread handle for the main thread is created lazily, and this might even
4//! happen pre-main. Since not every platform has a way to identify the main
5//! thread when that happens – macOS's `pthread_main_np` function being a notable
6//! exception – we cannot assign it the right name right then. Instead, in our
7//! runtime startup code, we remember the thread ID of the main thread (through
8//! this modules `set` function) and use it to identify the main thread from then
9//! on. This works reliably and has the additional advantage that we can report
10//! the right thread name on main even after the thread handle has been destroyed.
11//! Note however that this also means that the name reported in pre-main functions
12//! will be incorrect, but that's just something we have to live with.
13
14cfg_select! {
15 target_has_atomic = "64" => {
16 use super::id::ThreadId;
17 use crate::sync::atomic::{Atomic, AtomicU64};
18 use crate::sync::atomic::Ordering::Relaxed;
19
20 static MAIN: Atomic<u64> = AtomicU64::new(0);
21
22 pub(super) fn get() -> Option<ThreadId> {
23 ThreadId::from_u64(MAIN.load(Relaxed))
24 }
25
26 /// # Safety
27 /// May only be called once.
28 pub(crate) unsafe fn set(id: ThreadId) {
29 MAIN.store(id.as_u64().get(), Relaxed)
30 }
31 }
32 _ => {
33 use super::id::ThreadId;
34 use crate::mem::MaybeUninit;
35 use crate::sync::atomic::{Atomic, AtomicBool};
36 use crate::sync::atomic::Ordering::{Acquire, Release};
37
38 static INIT: Atomic<bool> = AtomicBool::new(false);
39 static mut MAIN: MaybeUninit<ThreadId> = MaybeUninit::uninit();
40
41 pub(super) fn get() -> Option<ThreadId> {
42 if INIT.load(Acquire) {
43 Some(unsafe { MAIN.assume_init() })
44 } else {
45 None
46 }
47 }
48
49 /// # Safety
50 /// May only be called once.
51 pub(crate) unsafe fn set(id: ThreadId) {
52 unsafe { MAIN = MaybeUninit::new(id) };
53 INIT.store(true, Release);
54 }
55 }
56}
57