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
14pub(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
116pub(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 crate::sys::thread_local::guard::enable();
132 CURRENT.set(thread.into_raw().cast_mut());
133 Ok(())
134}
135
136#[inline]
141pub(crate) fn current_id() -> ThreadId {
142 if !id::CHEAP {
146 if let Some(id) = try_with_current(|t| t.map(|t| t.id())) {
147 return id;
148 }
149 }
150
151 id::get_or_init()
152}
153
154pub(crate) fn current_os_id() -> u64 {
162 imp::current_os_id().unwrap_or_else(|| current_id().as_u64().get())
163}
164
165pub(super) fn try_with_current<F, R>(f: F) -> R
168where
169 F: FnOnce(Option<&Thread>) -> R,
170{
171 let current = CURRENT.get();
172 if current > DESTROYED {
173 unsafe {
177 let current = ManuallyDrop::new(Thread::from_raw(current));
178 f(Some(¤t))
179 }
180 } else {
181 f(None)
182 }
183}
184
185pub(crate) fn current_or_unnamed() -> Thread {
189 let current = CURRENT.get();
190 if current > DESTROYED {
191 unsafe {
192 let current = ManuallyDrop::new(Thread::from_raw(current));
193 (*current).clone()
194 }
195 } else if current == DESTROYED {
196 Thread::new(id::get_or_init(), None)
197 } else {
198 init_current(current)
199 }
200}
201
202#[must_use]
222#[stable(feature = "rust1", since = "1.0.0")]
223pub fn current() -> Thread {
224 let current = CURRENT.get();
225 if current > DESTROYED {
226 unsafe {
227 let current = ManuallyDrop::new(Thread::from_raw(current));
228 (*current).clone()
229 }
230 } else {
231 init_current(current)
232 }
233}
234
235#[cold]
236fn init_current(current: *mut ()) -> Thread {
237 if current == NONE {
238 CURRENT.set(BUSY);
239 let id = id::get_or_init();
241 let thread = Thread::new(id, None);
242
243 crate::sys::thread_local::guard::enable();
246 CURRENT.set(thread.clone().into_raw().cast_mut());
247 thread
248 } else if current == BUSY {
249 rtabort!(
263 "\n\
264 Attempted to access thread-local data while allocating said data.\n\
265 Do not access functions that allocate in the global allocator!\n\
266 This is a bug in the global allocator.\n\
267 "
268 )
269 } else {
270 debug_assert_eq!(current, DESTROYED);
271 panic!(
272 "use of std::thread::current() is not possible after the thread's \
273 local data has been destroyed"
274 )
275 }
276}
277
278pub(crate) fn drop_current() {
281 let current = CURRENT.get();
282 if current > DESTROYED {
283 unsafe {
284 CURRENT.set(DESTROYED);
285 drop(Thread::from_raw(current));
286 }
287 }
288}