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_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(crate) fn current_os_id() -> u64 {
159 imp::current_os_id().unwrap_or_else(|| current_id().as_u64().get())
160}
161
162pub(super) fn try_with_current<F, R>(f: F) -> R
165where
166 F: FnOnce(Option<&Thread>) -> R,
167{
168 let current = CURRENT.get();
169 if current > DESTROYED {
170 unsafe {
174 let current = ManuallyDrop::new(Thread::from_raw(current));
175 f(Some(¤t))
176 }
177 } else {
178 f(None)
179 }
180}
181
182pub(crate) fn current_or_unnamed() -> Thread {
186 let current = CURRENT.get();
187 if current > DESTROYED {
188 unsafe {
189 let current = ManuallyDrop::new(Thread::from_raw(current));
190 (*current).clone()
191 }
192 } else if current == DESTROYED {
193 Thread::new(id::get_or_init(), None)
194 } else {
195 init_current(current)
196 }
197}
198
199#[must_use]
219#[stable(feature = "rust1", since = "1.0.0")]
220pub fn current() -> Thread {
221 let current = CURRENT.get();
222 if current > DESTROYED {
223 unsafe {
224 let current = ManuallyDrop::new(Thread::from_raw(current));
225 (*current).clone()
226 }
227 } else {
228 init_current(current)
229 }
230}
231
232#[cold]
233fn init_current(current: *mut ()) -> Thread {
234 if current == NONE {
235 CURRENT.set(BUSY);
236 let id = id::get_or_init();
238 let thread = Thread::new(id, None);
239
240 crate::sys::thread_local::guard::enable();
243 CURRENT.set(thread.clone().into_raw().cast_mut());
244 thread
245 } else if current == BUSY {
246 rtabort!(
260 "\n\
261 Attempted to access thread-local data while allocating said data.\n\
262 Do not access functions that allocate in the global allocator!\n\
263 This is a bug in the global allocator.\n\
264 "
265 )
266 } else {
267 debug_assert_eq!(current, DESTROYED);
268 panic!(
269 "use of std::thread::current() is not possible after the thread's \
270 local data has been destroyed"
271 )
272 }
273}
274
275pub(crate) fn drop_current() {
278 let current = CURRENT.get();
279 if current > DESTROYED {
280 unsafe {
281 CURRENT.set(DESTROYED);
282 drop(Thread::from_raw(current));
283 }
284 }
285}