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}