| 1 | use super::id::ThreadId; |
| 2 | use super::main_thread; |
| 3 | use super::thread::Thread; |
| 4 | use crate::mem::ManuallyDrop; |
| 5 | use crate::ptr; |
| 6 | use crate::sys::thread as imp; |
| 7 | use crate::sys::thread_local::local_pointer; |
| 8 | |
| 9 | const NONE: *mut () = ptr::null_mut(); |
| 10 | const BUSY: *mut () = ptr::without_provenance_mut(1); |
| 11 | const DESTROYED: *mut () = ptr::without_provenance_mut(2); |
| 12 | |
| 13 | local_pointer! { |
| 14 | static CURRENT; |
| 15 | } |
| 16 | |
| 17 | /// Persistent storage for the thread ID. |
| 18 | /// |
| 19 | /// We store the thread ID so that it never gets destroyed during the lifetime |
| 20 | /// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s. |
| 21 | pub(super) mod id { |
| 22 | use super::*; |
| 23 | |
| 24 | cfg_select! { |
| 25 | target_thread_local => { |
| 26 | use crate::cell::Cell; |
| 27 | |
| 28 | #[thread_local] |
| 29 | static ID: Cell<Option<ThreadId>> = Cell::new(None); |
| 30 | |
| 31 | pub(super) const CHEAP: bool = true; |
| 32 | |
| 33 | pub(crate) fn get() -> Option<ThreadId> { |
| 34 | ID.get() |
| 35 | } |
| 36 | |
| 37 | pub(super) fn set(id: ThreadId) { |
| 38 | ID.set(Some(id)) |
| 39 | } |
| 40 | } |
| 41 | target_pointer_width = "16" => { |
| 42 | local_pointer! { |
| 43 | static ID0; |
| 44 | static ID16; |
| 45 | static ID32; |
| 46 | static ID48; |
| 47 | } |
| 48 | |
| 49 | pub(super) const CHEAP: bool = false; |
| 50 | |
| 51 | pub(crate) fn get() -> Option<ThreadId> { |
| 52 | let id0 = ID0.get().addr() as u64; |
| 53 | let id16 = ID16.get().addr() as u64; |
| 54 | let id32 = ID32.get().addr() as u64; |
| 55 | let id48 = ID48.get().addr() as u64; |
| 56 | ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0) |
| 57 | } |
| 58 | |
| 59 | pub(super) fn set(id: ThreadId) { |
| 60 | let val = id.as_u64().get(); |
| 61 | ID0.set(ptr::without_provenance_mut(val as usize)); |
| 62 | ID16.set(ptr::without_provenance_mut((val >> 16) as usize)); |
| 63 | ID32.set(ptr::without_provenance_mut((val >> 32) as usize)); |
| 64 | ID48.set(ptr::without_provenance_mut((val >> 48) as usize)); |
| 65 | } |
| 66 | } |
| 67 | target_pointer_width = "32" => { |
| 68 | local_pointer! { |
| 69 | static ID0; |
| 70 | static ID32; |
| 71 | } |
| 72 | |
| 73 | pub(super) const CHEAP: bool = false; |
| 74 | |
| 75 | pub(crate) fn get() -> Option<ThreadId> { |
| 76 | let id0 = ID0.get().addr() as u64; |
| 77 | let id32 = ID32.get().addr() as u64; |
| 78 | ThreadId::from_u64((id32 << 32) + id0) |
| 79 | } |
| 80 | |
| 81 | pub(super) fn set(id: ThreadId) { |
| 82 | let val = id.as_u64().get(); |
| 83 | ID0.set(ptr::without_provenance_mut(val as usize)); |
| 84 | ID32.set(ptr::without_provenance_mut((val >> 32) as usize)); |
| 85 | } |
| 86 | } |
| 87 | _ => { |
| 88 | local_pointer! { |
| 89 | static ID; |
| 90 | } |
| 91 | |
| 92 | pub(super) const CHEAP: bool = true; |
| 93 | |
| 94 | pub(crate) fn get() -> Option<ThreadId> { |
| 95 | let id = ID.get().addr() as u64; |
| 96 | ThreadId::from_u64(id) |
| 97 | } |
| 98 | |
| 99 | pub(super) fn set(id: ThreadId) { |
| 100 | let val = id.as_u64().get(); |
| 101 | ID.set(ptr::without_provenance_mut(val as usize)); |
| 102 | } |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | #[inline ] |
| 107 | pub(super) fn get_or_init() -> ThreadId { |
| 108 | get().unwrap_or_else( |
| 109 | #[cold ] |
| 110 | || { |
| 111 | let id = ThreadId::new(); |
| 112 | id::set(id); |
| 113 | id |
| 114 | }, |
| 115 | ) |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | /// Tries to set the thread handle for the current thread. Fails if a handle was |
| 120 | /// already set or if the thread ID of `thread` would change an already-set ID. |
| 121 | pub(super) fn set_current(thread: Thread) -> Result<(), Thread> { |
| 122 | if CURRENT.get() != NONE { |
| 123 | return Err(thread); |
| 124 | } |
| 125 | |
| 126 | match id::get() { |
| 127 | Some(id) if id == thread.id() => {} |
| 128 | None => id::set(thread.id()), |
| 129 | _ => return Err(thread), |
| 130 | } |
| 131 | |
| 132 | // Make sure that `crate::rt::thread_cleanup` will be run, which will |
| 133 | // call `drop_current`. |
| 134 | crate::sys::thread_local::guard::enable(); |
| 135 | CURRENT.set(thread.into_raw().cast_mut()); |
| 136 | Ok(()) |
| 137 | } |
| 138 | |
| 139 | /// Gets the unique identifier of the thread which invokes it. |
| 140 | /// |
| 141 | /// Calling this function may be more efficient than accessing the current |
| 142 | /// thread id through the current thread handle. i.e. `thread::current().id()`. |
| 143 | /// |
| 144 | /// This function will always succeed, will always return the same value for |
| 145 | /// one thread and is guaranteed not to call the global allocator. |
| 146 | /// |
| 147 | /// # Examples |
| 148 | /// |
| 149 | /// ``` |
| 150 | /// #![feature(current_thread_id)] |
| 151 | /// |
| 152 | /// use std::thread; |
| 153 | /// |
| 154 | /// let other_thread = thread::spawn(|| { |
| 155 | /// thread::current_id() |
| 156 | /// }); |
| 157 | /// |
| 158 | /// let other_thread_id = other_thread.join().unwrap(); |
| 159 | /// assert_ne!(thread::current_id(), other_thread_id); |
| 160 | /// ``` |
| 161 | #[inline ] |
| 162 | #[must_use ] |
| 163 | #[unstable (feature = "current_thread_id" , issue = "147194" )] |
| 164 | pub fn current_id() -> ThreadId { |
| 165 | // If accessing the persistent thread ID takes multiple TLS accesses, try |
| 166 | // to retrieve it from the current thread handle, which will only take one |
| 167 | // TLS access. |
| 168 | if !id::CHEAP { |
| 169 | if let Some(id: ThreadId) = try_with_current(|t| t.map(|t| t.id())) { |
| 170 | return id; |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | id::get_or_init() |
| 175 | } |
| 176 | |
| 177 | /// Gets the OS thread ID of the thread that invokes it, if available. If not, return the Rust |
| 178 | /// thread ID. |
| 179 | /// |
| 180 | /// We use a `u64` to all possible platform IDs without excess `cfg`; most use `int`, some use a |
| 181 | /// pointer, and Apple uses `uint64_t`. This is a "best effort" approach for diagnostics and is |
| 182 | /// allowed to fall back to a non-OS ID (such as the Rust thread ID) or a non-unique ID (such as a |
| 183 | /// PID) if the thread ID cannot be retrieved. |
| 184 | pub(crate) fn current_os_id() -> u64 { |
| 185 | imp::current_os_id().unwrap_or_else(|| current_id().as_u64().get()) |
| 186 | } |
| 187 | |
| 188 | /// Gets a reference to the handle of the thread that invokes it, if the handle |
| 189 | /// has been initialized. |
| 190 | fn try_with_current<F, R>(f: F) -> R |
| 191 | where |
| 192 | F: FnOnce(Option<&Thread>) -> R, |
| 193 | { |
| 194 | let current: *const () = CURRENT.get(); |
| 195 | if current > DESTROYED { |
| 196 | // SAFETY: `Arc` does not contain interior mutability, so it does not |
| 197 | // matter that the address of the handle might be different depending |
| 198 | // on where this is called. |
| 199 | unsafe { |
| 200 | let current = ManuallyDrop::new(Thread::from_raw(ptr:current)); |
| 201 | f(Some(¤t)) |
| 202 | } |
| 203 | } else { |
| 204 | f(None) |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | /// Run a function with the current thread's name. |
| 209 | /// |
| 210 | /// Modulo thread local accesses, this function is safe to call from signal |
| 211 | /// handlers and in similar circumstances where allocations are not possible. |
| 212 | pub(crate) fn with_current_name<F, R>(f: F) -> R |
| 213 | where |
| 214 | F: FnOnce(Option<&str>) -> R, |
| 215 | { |
| 216 | try_with_current(|thread| { |
| 217 | let name = if let Some(thread) = thread { |
| 218 | // If there is a current thread handle, try to use the name stored |
| 219 | // there. |
| 220 | thread.name() |
| 221 | } else if let Some(main) = main_thread::get() |
| 222 | && let Some(id) = id::get() |
| 223 | && id == main |
| 224 | { |
| 225 | // The main thread doesn't always have a thread handle, we must |
| 226 | // identify it through its ID instead. The checks are ordered so |
| 227 | // that the current ID is only loaded if it is actually needed, |
| 228 | // since loading it from TLS might need multiple expensive accesses. |
| 229 | Some("main" ) |
| 230 | } else { |
| 231 | None |
| 232 | }; |
| 233 | |
| 234 | f(name) |
| 235 | }) |
| 236 | } |
| 237 | |
| 238 | /// Gets a handle to the thread that invokes it. If the handle stored in thread- |
| 239 | /// local storage was already destroyed, this creates a new unnamed temporary |
| 240 | /// handle to allow thread parking in nearly all situations. |
| 241 | pub(crate) fn current_or_unnamed() -> Thread { |
| 242 | let current: *const () = CURRENT.get(); |
| 243 | if current > DESTROYED { |
| 244 | unsafe { |
| 245 | let current = ManuallyDrop::new(Thread::from_raw(ptr:current)); |
| 246 | (*current).clone() |
| 247 | } |
| 248 | } else if current == DESTROYED { |
| 249 | Thread::new(id:id::get_or_init(), name:None) |
| 250 | } else { |
| 251 | init_current(current) |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | /// Gets a handle to the thread that invokes it. |
| 256 | /// |
| 257 | /// # Examples |
| 258 | /// |
| 259 | /// Getting a handle to the current thread with `thread::current()`: |
| 260 | /// |
| 261 | /// ``` |
| 262 | /// use std::thread; |
| 263 | /// |
| 264 | /// let handler = thread::Builder::new() |
| 265 | /// .name("named thread" .into()) |
| 266 | /// .spawn(|| { |
| 267 | /// let handle = thread::current(); |
| 268 | /// assert_eq!(handle.name(), Some("named thread" )); |
| 269 | /// }) |
| 270 | /// .unwrap(); |
| 271 | /// |
| 272 | /// handler.join().unwrap(); |
| 273 | /// ``` |
| 274 | #[must_use ] |
| 275 | #[stable (feature = "rust1" , since = "1.0.0" )] |
| 276 | pub fn current() -> Thread { |
| 277 | let current: *const () = CURRENT.get(); |
| 278 | if current > DESTROYED { |
| 279 | unsafe { |
| 280 | let current = ManuallyDrop::new(Thread::from_raw(ptr:current)); |
| 281 | (*current).clone() |
| 282 | } |
| 283 | } else { |
| 284 | init_current(current) |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | #[cold ] |
| 289 | fn init_current(current: *mut ()) -> Thread { |
| 290 | if current == NONE { |
| 291 | CURRENT.set(BUSY); |
| 292 | // If the thread ID was initialized already, use it. |
| 293 | let id = id::get_or_init(); |
| 294 | let thread = Thread::new(id, None); |
| 295 | |
| 296 | // Make sure that `crate::rt::thread_cleanup` will be run, which will |
| 297 | // call `drop_current`. |
| 298 | crate::sys::thread_local::guard::enable(); |
| 299 | CURRENT.set(thread.clone().into_raw().cast_mut()); |
| 300 | thread |
| 301 | } else if current == BUSY { |
| 302 | // BUSY exists solely for this check, but as it is in the slow path, the |
| 303 | // extra TLS write above shouldn't matter. The alternative is nearly always |
| 304 | // a stack overflow. |
| 305 | // |
| 306 | // If we reach this point it means our initialization routine ended up |
| 307 | // calling current() either directly, or indirectly through the global |
| 308 | // allocator, which is a bug either way as we may not call the global |
| 309 | // allocator in current(). |
| 310 | rtabort!( |
| 311 | "init_current() was re-entrant, which indicates a bug in the Rust threading implementation" |
| 312 | ) |
| 313 | } else { |
| 314 | debug_assert_eq!(current, DESTROYED); |
| 315 | panic!( |
| 316 | "use of std::thread::current() is not possible after the thread's \ |
| 317 | local data has been destroyed" |
| 318 | ) |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | /// This should be run in [`crate::rt::thread_cleanup`] to reset the thread |
| 323 | /// handle. |
| 324 | pub(crate) fn drop_current() { |
| 325 | let current: *const () = CURRENT.get(); |
| 326 | if current > DESTROYED { |
| 327 | unsafe { |
| 328 | CURRENT.set(DESTROYED); |
| 329 | drop(Thread::from_raw(ptr:current)); |
| 330 | } |
| 331 | } |
| 332 | } |
| 333 | |