diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 31a8711e0eb97..65f0e92c4e4cf 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -353,6 +353,7 @@ #![feature(str_internals)] #![feature(strict_provenance)] #![feature(strict_provenance_atomic_ptr)] +#![feature(sync_unsafe_cell)] // tidy-alphabetical-end // // Library features (alloc): diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index f792a27dd694d..b30dfb869c536 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -159,11 +159,13 @@ mod tests; use crate::any::Any; +use crate::cell::SyncUnsafeCell; use crate::cell::{OnceCell, UnsafeCell}; use crate::ffi::{CStr, CString}; use crate::fmt; use crate::io; use crate::marker::PhantomData; +use crate::mem::MaybeUninit; use crate::mem::{self, forget}; use crate::num::NonZero; use crate::panic; @@ -511,7 +513,7 @@ impl Builder { let f = MaybeDangling::new(f); let main = move || { - if let Some(name) = their_thread.cname() { + if let Some(name) = their_thread.0.name() { imp::Thread::set_name(name); } @@ -1143,7 +1145,7 @@ pub fn park_timeout(dur: Duration) { let guard = PanicGuard; // SAFETY: park_timeout is called on the parker owned by this thread. unsafe { - current().inner.as_ref().parker().park_timeout(dur); + current().0.parker().park_timeout(dur); } // No panic occurred, do not abort. forget(guard); @@ -1182,7 +1184,12 @@ pub fn park_timeout(dur: Duration) { pub struct ThreadId(NonZero); impl ThreadId { - // Generate a new unique thread ID. + /// Generate a new unique thread ID. + /// + /// The current implementation starts at 2 and increments from there. + /// + /// This is as `1` is the value for the main thread, so std::thread::Thread does not + /// have to store this value when creating the main thread's information. fn new() -> ThreadId { #[cold] fn exhausted() -> ! { @@ -1193,7 +1200,7 @@ impl ThreadId { if #[cfg(target_has_atomic = "64")] { use crate::sync::atomic::{AtomicU64, Ordering::Relaxed}; - static COUNTER: AtomicU64 = AtomicU64::new(0); + static COUNTER: AtomicU64 = AtomicU64::new(1); let mut last = COUNTER.load(Relaxed); loop { @@ -1209,7 +1216,7 @@ impl ThreadId { } else { use crate::sync::{Mutex, PoisonError}; - static COUNTER: Mutex = Mutex::new(0); + static COUNTER: Mutex = Mutex::new(1); let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner); let Some(id) = counter.checked_add(1) else { @@ -1226,6 +1233,11 @@ impl ThreadId { } } + /// Creates a ThreadId with the ID of the main thread. + fn new_main() -> Self { + Self(NonZero::::MIN) + } + /// This returns a numeric identifier for the thread identified by this /// `ThreadId`. /// @@ -1245,23 +1257,54 @@ impl ThreadId { // Thread //////////////////////////////////////////////////////////////////////////////// -/// The internal representation of a `Thread`'s name. -enum ThreadName { - Main, - Other(CString), - Unnamed, -} +/// The parker for the main thread. This avoids having to allocate an Arc in `fn main() {}`. +static MAIN_PARKER: SyncUnsafeCell> = + SyncUnsafeCell::new(MaybeUninit::uninit()); -/// The internal representation of a `Thread` handle -struct Inner { - name: ThreadName, // Guaranteed to be UTF-8 +/// The internal representation of a `Thread` that is not the main thread. +struct OtherInner { + name: Option, // Guaranteed to be UTF-8 id: ThreadId, parker: Parker, } +/// The internal representation of a `Thread` handle. +#[derive(Clone)] +enum Inner { + Main, + Other(Pin>), +} + impl Inner { - fn parker(self: Pin<&Self>) -> Pin<&Parker> { - unsafe { Pin::map_unchecked(self, |inner| &inner.parker) } + fn id(&self) -> ThreadId { + match self { + Self::Main => ThreadId::new_main(), + Self::Other(other) => other.id, + } + } + + fn name(&self) -> Option<&CStr> { + match self { + Self::Main => Some(c"main"), + Self::Other(other) => other.name.as_deref(), + } + } + + fn parker(&self) -> Pin<&Parker> { + match self { + Self::Main => { + // Safety: MAIN_PARKER only ever has a mutable reference when Inner::Main is initialised. + let uninit_ref: &'static MaybeUninit = unsafe { &*MAIN_PARKER.get() }; + + // Safety: MAIN_PARKER is initialised when Inner::Main is initialised. + let parker_ref = unsafe { uninit_ref.assume_init_ref() }; + + Pin::static_ref(parker_ref) + } + Self::Other(inner) => unsafe { + Pin::map_unchecked(inner.as_ref(), |inner| &inner.parker) + }, + } } } @@ -1285,33 +1328,18 @@ impl Inner { /// docs of [`Builder`] and [`spawn`] for more details. /// /// [`thread::current`]: current -pub struct Thread { - inner: Pin>, -} +pub struct Thread(Inner); impl Thread { // Used only internally to construct a thread object without spawning pub(crate) fn new(name: Option) -> Thread { - if let Some(name) = name { - Self::new_inner(ThreadName::Other(name)) - } else { - Self::new_inner(ThreadName::Unnamed) - } - } - - // Used in runtime to construct main thread - pub(crate) fn new_main() -> Thread { - Self::new_inner(ThreadName::Main) - } - - fn new_inner(name: ThreadName) -> Thread { // We have to use `unsafe` here to construct the `Parker` in-place, // which is required for the UNIX implementation. // // SAFETY: We pin the Arc immediately after creation, so its address never // changes. let inner = unsafe { - let mut arc = Arc::::new_uninit(); + let mut arc = Arc::::new_uninit(); let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr(); addr_of_mut!((*ptr).name).write(name); addr_of_mut!((*ptr).id).write(ThreadId::new()); @@ -1319,7 +1347,18 @@ impl Thread { Pin::new_unchecked(arc.assume_init()) }; - Thread { inner } + Self(Inner::Other(inner)) + } + + /// # Safety + /// + /// This must only ever be called once, and must be called on the main thread. + pub(crate) unsafe fn new_main() -> Thread { + // Safety: Caller responsible for holding the mutable invariant and + // Parker::new_in_place does not read from the uninit value. + unsafe { Parker::new_in_place(MAIN_PARKER.get().cast()) } + + Self(Inner::Main) } /// Like the public [`park`], but callable on any handle. This is used to @@ -1328,7 +1367,7 @@ impl Thread { /// # Safety /// May only be called from the thread to which this handle belongs. pub(crate) unsafe fn park(&self) { - unsafe { self.inner.as_ref().parker().park() } + unsafe { self.0.parker().park() } } /// Atomically makes the handle's token available if it is not already. @@ -1364,7 +1403,7 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn unpark(&self) { - self.inner.as_ref().parker().unpark(); + self.0.parker().unpark(); } /// Gets the thread's unique identifier. @@ -1384,7 +1423,7 @@ impl Thread { #[stable(feature = "thread_id", since = "1.19.0")] #[must_use] pub fn id(&self) -> ThreadId { - self.inner.id + self.0.id() } /// Gets the thread's name. @@ -1427,15 +1466,7 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub fn name(&self) -> Option<&str> { - self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) }) - } - - fn cname(&self) -> Option<&CStr> { - match &self.inner.name { - ThreadName::Main => Some(c"main"), - ThreadName::Other(other) => Some(&other), - ThreadName::Unnamed => None, - } + self.0.name().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) }) } } diff --git a/tests/rustdoc/demo-allocator-54478.rs b/tests/rustdoc/demo-allocator-54478.rs index dd98e80f03ade..db8b483e635c0 100644 --- a/tests/rustdoc/demo-allocator-54478.rs +++ b/tests/rustdoc/demo-allocator-54478.rs @@ -40,6 +40,7 @@ //! } //! //! fn main() { +//! drop(std::env::var("PWD")); //! assert!(unsafe { HIT }); //! } //! ```