1use super::{Thread, ThreadId};
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
14pub(super) mod id {
19    use super::*;
20
21    cfg_if::cfg_if! {
22        if #[cfg(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        } else if #[cfg(target_pointer_width = "16")] {
38            local_pointer! {
39                static ID0;
40                static ID16;
41                static ID32;
42                static ID48;
43            }
44
45            pub(super) const CHEAP: bool = false;
46
47            pub(crate) fn get() -> Option<ThreadId> {
48                let id0 = ID0.get().addr() as u64;
49                let id16 = ID16.get().addr() as u64;
50                let id32 = ID32.get().addr() as u64;
51                let id48 = ID48.get().addr() as u64;
52                ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0)
53            }
54
55            pub(super) fn set(id: ThreadId) {
56                let val = id.as_u64().get();
57                ID0.set(ptr::without_provenance_mut(val as usize));
58                ID16.set(ptr::without_provenance_mut((val >> 16) as usize));
59                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
60                ID48.set(ptr::without_provenance_mut((val >> 48) as usize));
61            }
62        } else if #[cfg(target_pointer_width = "32")] {
63            local_pointer! {
64                static ID0;
65                static ID32;
66            }
67
68            pub(super) const CHEAP: bool = false;
69
70            pub(crate) fn get() -> Option<ThreadId> {
71                let id0 = ID0.get().addr() as u64;
72                let id32 = ID32.get().addr() as u64;
73                ThreadId::from_u64((id32 << 32) + id0)
74            }
75
76            pub(super) fn set(id: ThreadId) {
77                let val = id.as_u64().get();
78                ID0.set(ptr::without_provenance_mut(val as usize));
79                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
80            }
81        } else {
82            local_pointer! {
83                static ID;
84            }
85
86            pub(super) const CHEAP: bool = true;
87
88            pub(crate) fn get() -> Option<ThreadId> {
89                let id = ID.get().addr() as u64;
90                ThreadId::from_u64(id)
91            }
92
93            pub(super) fn set(id: ThreadId) {
94                let val = id.as_u64().get();
95                ID.set(ptr::without_provenance_mut(val as usize));
96            }
97        }
98    }
99
100    #[inline]
101    pub(super) fn get_or_init() -> ThreadId {
102        get().unwrap_or_else(
103            #[cold]
104            || {
105                let id = ThreadId::new();
106                id::set(id);
107                id
108            },
109        )
110    }
111}
112
113pub(super) fn set_current(thread: Thread) -> Result<(), Thread> {
116    if CURRENT.get() != NONE {
117        return Err(thread);
118    }
119
120    match id::get() {
121        Some(id) if id == thread.id() => {}
122        None => id::set(thread.id()),
123        _ => return Err(thread),
124    }
125
126    crate::sys::thread_local::guard::enable();
129    CURRENT.set(thread.into_raw().cast_mut());
130    Ok(())
131}
132
133#[inline]
138pub(crate) fn current_id() -> ThreadId {
139    if !id::CHEAP {
143        if let Some(id) = try_with_current(|t| t.map(|t| t.id())) {
144            return id;
145        }
146    }
147
148    id::get_or_init()
149}
150
151pub(super) fn try_with_current<F, R>(f: F) -> R
154where
155    F: FnOnce(Option<&Thread>) -> R,
156{
157    let current = CURRENT.get();
158    if current > DESTROYED {
159        unsafe {
163            let current = ManuallyDrop::new(Thread::from_raw(current));
164            f(Some(¤t))
165        }
166    } else {
167        f(None)
168    }
169}
170
171pub(crate) fn current_or_unnamed() -> Thread {
175    let current = CURRENT.get();
176    if current > DESTROYED {
177        unsafe {
178            let current = ManuallyDrop::new(Thread::from_raw(current));
179            (*current).clone()
180        }
181    } else if current == DESTROYED {
182        Thread::new(id::get_or_init(), None)
183    } else {
184        init_current(current)
185    }
186}
187
188#[must_use]
208#[stable(feature = "rust1", since = "1.0.0")]
209pub fn current() -> Thread {
210    let current = CURRENT.get();
211    if current > DESTROYED {
212        unsafe {
213            let current = ManuallyDrop::new(Thread::from_raw(current));
214            (*current).clone()
215        }
216    } else {
217        init_current(current)
218    }
219}
220
221#[cold]
222fn init_current(current: *mut ()) -> Thread {
223    if current == NONE {
224        CURRENT.set(BUSY);
225        let id = id::get_or_init();
227        let thread = Thread::new(id, None);
228
229        crate::sys::thread_local::guard::enable();
232        CURRENT.set(thread.clone().into_raw().cast_mut());
233        thread
234    } else if current == BUSY {
235        rtabort!(
249            "\n\
250            Attempted to access thread-local data while allocating said data.\n\
251            Do not access functions that allocate in the global allocator!\n\
252            This is a bug in the global allocator.\n\
253            "
254        )
255    } else {
256        debug_assert_eq!(current, DESTROYED);
257        panic!(
258            "use of std::thread::current() is not possible after the thread's \
259            local data has been destroyed"
260        )
261    }
262}
263
264pub(crate) fn drop_current() {
267    let current = CURRENT.get();
268    if current > DESTROYED {
269        unsafe {
270            CURRENT.set(DESTROYED);
271            drop(Thread::from_raw(current));
272        }
273    }
274}