| use super::{Thread, ThreadId}; |
| use crate::mem::ManuallyDrop; |
| use crate::ptr; |
| use crate::sys::thread_local::local_pointer; |
| |
| const NONE: *mut () = ptr::null_mut(); |
| const BUSY: *mut () = ptr::without_provenance_mut(1); |
| const DESTROYED: *mut () = ptr::without_provenance_mut(2); |
| |
| local_pointer! { |
| static CURRENT; |
| } |
| |
| /// Persistent storage for the thread ID. |
| /// |
| /// We store the thread ID so that it never gets destroyed during the lifetime |
| /// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s. |
| mod id { |
| use super::*; |
| |
| cfg_if::cfg_if! { |
| if #[cfg(target_thread_local)] { |
| use crate::cell::Cell; |
| |
| #[thread_local] |
| static ID: Cell<Option<ThreadId>> = Cell::new(None); |
| |
| pub(super) const CHEAP: bool = true; |
| |
| pub(super) fn get() -> Option<ThreadId> { |
| ID.get() |
| } |
| |
| pub(super) fn set(id: ThreadId) { |
| ID.set(Some(id)) |
| } |
| } else if #[cfg(target_pointer_width = "16")] { |
| local_pointer! { |
| static ID0; |
| static ID16; |
| static ID32; |
| static ID48; |
| } |
| |
| pub(super) const CHEAP: bool = false; |
| |
| pub(super) fn get() -> Option<ThreadId> { |
| let id0 = ID0.get().addr() as u64; |
| let id16 = ID16.get().addr() as u64; |
| let id32 = ID32.get().addr() as u64; |
| let id48 = ID48.get().addr() as u64; |
| ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0) |
| } |
| |
| pub(super) fn set(id: ThreadId) { |
| let val = id.as_u64().get(); |
| ID0.set(ptr::without_provenance_mut(val as usize)); |
| ID16.set(ptr::without_provenance_mut((val >> 16) as usize)); |
| ID32.set(ptr::without_provenance_mut((val >> 32) as usize)); |
| ID48.set(ptr::without_provenance_mut((val >> 48) as usize)); |
| } |
| } else if #[cfg(target_pointer_width = "32")] { |
| local_pointer! { |
| static ID0; |
| static ID32; |
| } |
| |
| pub(super) const CHEAP: bool = false; |
| |
| pub(super) fn get() -> Option<ThreadId> { |
| let id0 = ID0.get().addr() as u64; |
| let id32 = ID32.get().addr() as u64; |
| ThreadId::from_u64((id32 << 32) + id0) |
| } |
| |
| pub(super) fn set(id: ThreadId) { |
| let val = id.as_u64().get(); |
| ID0.set(ptr::without_provenance_mut(val as usize)); |
| ID32.set(ptr::without_provenance_mut((val >> 32) as usize)); |
| } |
| } else { |
| local_pointer! { |
| static ID; |
| } |
| |
| pub(super) const CHEAP: bool = true; |
| |
| pub(super) fn get() -> Option<ThreadId> { |
| let id = ID.get().addr() as u64; |
| ThreadId::from_u64(id) |
| } |
| |
| pub(super) fn set(id: ThreadId) { |
| let val = id.as_u64().get(); |
| ID.set(ptr::without_provenance_mut(val as usize)); |
| } |
| } |
| } |
| |
| #[inline] |
| pub(super) fn get_or_init() -> ThreadId { |
| get().unwrap_or_else( |
| #[cold] |
| || { |
| let id = ThreadId::new(); |
| id::set(id); |
| id |
| }, |
| ) |
| } |
| } |
| |
| /// Tries to set the thread handle for the current thread. Fails if a handle was |
| /// already set or if the thread ID of `thread` would change an already-set ID. |
| pub(crate) fn set_current(thread: Thread) -> Result<(), Thread> { |
| if CURRENT.get() != NONE { |
| return Err(thread); |
| } |
| |
| match id::get() { |
| Some(id) if id == thread.id() => {} |
| None => id::set(thread.id()), |
| _ => return Err(thread), |
| } |
| |
| // Make sure that `crate::rt::thread_cleanup` will be run, which will |
| // call `drop_current`. |
| crate::sys::thread_local::guard::enable(); |
| CURRENT.set(thread.into_raw().cast_mut()); |
| Ok(()) |
| } |
| |
| /// Gets the id of the thread that invokes it. |
| /// |
| /// This function will always succeed, will always return the same value for |
| /// one thread and is guaranteed not to call the global allocator. |
| #[inline] |
| pub(crate) fn current_id() -> ThreadId { |
| // If accessing the persistant thread ID takes multiple TLS accesses, try |
| // to retrieve it from the current thread handle, which will only take one |
| // TLS access. |
| if !id::CHEAP { |
| let current = CURRENT.get(); |
| if current > DESTROYED { |
| unsafe { |
| let current = ManuallyDrop::new(Thread::from_raw(current)); |
| return current.id(); |
| } |
| } |
| } |
| |
| id::get_or_init() |
| } |
| |
| /// Gets a handle to the thread that invokes it, if the handle has been initialized. |
| pub(crate) fn try_current() -> Option<Thread> { |
| let current = CURRENT.get(); |
| if current > DESTROYED { |
| unsafe { |
| let current = ManuallyDrop::new(Thread::from_raw(current)); |
| Some((*current).clone()) |
| } |
| } else { |
| None |
| } |
| } |
| |
| /// Gets a handle to the thread that invokes it. |
| /// |
| /// # Examples |
| /// |
| /// Getting a handle to the current thread with `thread::current()`: |
| /// |
| /// ``` |
| /// use std::thread; |
| /// |
| /// let handler = thread::Builder::new() |
| /// .name("named thread".into()) |
| /// .spawn(|| { |
| /// let handle = thread::current(); |
| /// assert_eq!(handle.name(), Some("named thread")); |
| /// }) |
| /// .unwrap(); |
| /// |
| /// handler.join().unwrap(); |
| /// ``` |
| #[must_use] |
| #[stable(feature = "rust1", since = "1.0.0")] |
| pub fn current() -> Thread { |
| let current = CURRENT.get(); |
| if current > DESTROYED { |
| unsafe { |
| let current = ManuallyDrop::new(Thread::from_raw(current)); |
| (*current).clone() |
| } |
| } else { |
| init_current(current) |
| } |
| } |
| |
| #[cold] |
| fn init_current(current: *mut ()) -> Thread { |
| if current == NONE { |
| CURRENT.set(BUSY); |
| // If the thread ID was initialized already, use it. |
| let id = id::get_or_init(); |
| let thread = Thread::new_unnamed(id); |
| |
| // Make sure that `crate::rt::thread_cleanup` will be run, which will |
| // call `drop_current`. |
| crate::sys::thread_local::guard::enable(); |
| CURRENT.set(thread.clone().into_raw().cast_mut()); |
| thread |
| } else if current == BUSY { |
| // BUSY exists solely for this check, but as it is in the slow path, the |
| // extra TLS write above shouldn't matter. The alternative is nearly always |
| // a stack overflow. |
| |
| // If you came across this message, contact the author of your allocator. |
| // If you are said author: A surprising amount of functions inside the |
| // standard library (e.g. `Mutex`, `thread_local!`, `File` when using long |
| // paths, even `panic!` when using unwinding), need memory allocation, so |
| // you'll get circular dependencies all over the place when using them. |
| // I (joboet) highly recommend using only APIs from core in your allocator |
| // and implementing your own system abstractions. Still, if you feel that |
| // a particular API should be entirely allocation-free, feel free to open |
| // an issue on the Rust repository, we'll see what we can do. |
| rtabort!( |
| "\n |
| Attempted to access thread-local data while allocating said data.\n |
| Do not access functions that allocate in the global allocator!\n |
| This is a bug in the global allocator.\n |
| " |
| ) |
| } else { |
| debug_assert_eq!(current, DESTROYED); |
| panic!( |
| "use of std::thread::current() is not possible after the thread's |
| local data has been destroyed" |
| ) |
| } |
| } |
| |
| /// This should be run in [`crate::rt::thread_cleanup`] to reset the thread |
| /// handle. |
| pub(crate) fn drop_current() { |
| let current = CURRENT.get(); |
| if current > DESTROYED { |
| unsafe { |
| CURRENT.set(DESTROYED); |
| drop(Thread::from_raw(current)); |
| } |
| } |
| } |