1 | use super::{Thread, ThreadId}; |
2 | use crate::mem::ManuallyDrop; |
3 | use crate::ptr; |
4 | use crate::sys::thread_local::local_pointer; |
5 | |
6 | const NONE: *mut () = ptr::null_mut(); |
7 | const BUSY: *mut () = ptr::without_provenance_mut(addr:1); |
8 | const DESTROYED: *mut () = ptr::without_provenance_mut(addr:2); |
9 | |
10 | local_pointer! { |
11 | static CURRENT; |
12 | } |
13 | |
14 | /// Persistent storage for the thread ID. |
15 | /// |
16 | /// We store the thread ID so that it never gets destroyed during the lifetime |
17 | /// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s. |
18 | pub(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 | |
113 | /// Tries to set the thread handle for the current thread. Fails if a handle was |
114 | /// already set or if the thread ID of `thread` would change an already-set ID. |
115 | pub(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: ThreadId) if id == thread.id() => {} |
122 | None => id::set(thread.id()), |
123 | _ => return Err(thread), |
124 | } |
125 | |
126 | // Make sure that `crate::rt::thread_cleanup` will be run, which will |
127 | // call `drop_current`. |
128 | crate::sys::thread_local::guard::enable(); |
129 | CURRENT.set(thread.into_raw().cast_mut()); |
130 | Ok(()) |
131 | } |
132 | |
133 | /// Gets the id of the thread that invokes it. |
134 | /// |
135 | /// This function will always succeed, will always return the same value for |
136 | /// one thread and is guaranteed not to call the global allocator. |
137 | #[inline ] |
138 | pub(crate) fn current_id() -> ThreadId { |
139 | // If accessing the persistent thread ID takes multiple TLS accesses, try |
140 | // to retrieve it from the current thread handle, which will only take one |
141 | // TLS access. |
142 | if !id::CHEAP { |
143 | if let Some(id: ThreadId) = try_with_current(|t: Option<&Thread>| t.map(|t: &Thread| t.id())) { |
144 | return id; |
145 | } |
146 | } |
147 | |
148 | id::get_or_init() |
149 | } |
150 | |
151 | /// Gets a reference to the handle of the thread that invokes it, if the handle |
152 | /// has been initialized. |
153 | pub(super) fn try_with_current<F, R>(f: F) -> R |
154 | where |
155 | F: FnOnce(Option<&Thread>) -> R, |
156 | { |
157 | let current: *mut () = CURRENT.get(); |
158 | if current > DESTROYED { |
159 | // SAFETY: `Arc` does not contain interior mutability, so it does not |
160 | // matter that the address of the handle might be different depending |
161 | // on where this is called. |
162 | unsafe { |
163 | let current: ManuallyDrop = ManuallyDrop::new(Thread::from_raw(ptr:current)); |
164 | f(Some(¤t)) |
165 | } |
166 | } else { |
167 | f(None) |
168 | } |
169 | } |
170 | |
171 | /// Gets a handle to the thread that invokes it. If the handle stored in thread- |
172 | /// local storage was already destroyed, this creates a new unnamed temporary |
173 | /// handle to allow thread parking in nearly all situations. |
174 | pub(crate) fn current_or_unnamed() -> Thread { |
175 | let current: *mut () = CURRENT.get(); |
176 | if current > DESTROYED { |
177 | unsafe { |
178 | let current: ManuallyDrop = ManuallyDrop::new(Thread::from_raw(ptr:current)); |
179 | (*current).clone() |
180 | } |
181 | } else if current == DESTROYED { |
182 | Thread::new(id:id::get_or_init(), name:None) |
183 | } else { |
184 | init_current(current) |
185 | } |
186 | } |
187 | |
188 | /// Gets a handle to the thread that invokes it. |
189 | /// |
190 | /// # Examples |
191 | /// |
192 | /// Getting a handle to the current thread with `thread::current()`: |
193 | /// |
194 | /// ``` |
195 | /// use std::thread; |
196 | /// |
197 | /// let handler = thread::Builder::new() |
198 | /// .name("named thread" .into()) |
199 | /// .spawn(|| { |
200 | /// let handle = thread::current(); |
201 | /// assert_eq!(handle.name(), Some("named thread" )); |
202 | /// }) |
203 | /// .unwrap(); |
204 | /// |
205 | /// handler.join().unwrap(); |
206 | /// ``` |
207 | #[must_use ] |
208 | #[stable (feature = "rust1" , since = "1.0.0" )] |
209 | pub fn current() -> Thread { |
210 | let current: *mut () = CURRENT.get(); |
211 | if current > DESTROYED { |
212 | unsafe { |
213 | let current: ManuallyDrop = ManuallyDrop::new(Thread::from_raw(ptr:current)); |
214 | (*current).clone() |
215 | } |
216 | } else { |
217 | init_current(current) |
218 | } |
219 | } |
220 | |
221 | #[cold ] |
222 | fn init_current(current: *mut ()) -> Thread { |
223 | if current == NONE { |
224 | CURRENT.set(BUSY); |
225 | // If the thread ID was initialized already, use it. |
226 | let id = id::get_or_init(); |
227 | let thread = Thread::new(id, None); |
228 | |
229 | // Make sure that `crate::rt::thread_cleanup` will be run, which will |
230 | // call `drop_current`. |
231 | crate::sys::thread_local::guard::enable(); |
232 | CURRENT.set(thread.clone().into_raw().cast_mut()); |
233 | thread |
234 | } else if current == BUSY { |
235 | // BUSY exists solely for this check, but as it is in the slow path, the |
236 | // extra TLS write above shouldn't matter. The alternative is nearly always |
237 | // a stack overflow. |
238 | |
239 | // If you came across this message, contact the author of your allocator. |
240 | // If you are said author: A surprising amount of functions inside the |
241 | // standard library (e.g. `Mutex`, `thread_local!`, `File` when using long |
242 | // paths, even `panic!` when using unwinding), need memory allocation, so |
243 | // you'll get circular dependencies all over the place when using them. |
244 | // I (joboet) highly recommend using only APIs from core in your allocator |
245 | // and implementing your own system abstractions. Still, if you feel that |
246 | // a particular API should be entirely allocation-free, feel free to open |
247 | // an issue on the Rust repository, we'll see what we can do. |
248 | 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 | |
264 | /// This should be run in [`crate::rt::thread_cleanup`] to reset the thread |
265 | /// handle. |
266 | pub(crate) fn drop_current() { |
267 | let current: *mut () = CURRENT.get(); |
268 | if current > DESTROYED { |
269 | unsafe { |
270 | CURRENT.set(DESTROYED); |
271 | drop(Thread::from_raw(ptr:current)); |
272 | } |
273 | } |
274 | } |
275 | |