| 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 | |