From a61c8be2699eb09bd8e621d84b811b0514a89b57 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Fri, 17 Oct 2025 10:57:39 -0400 Subject: [PATCH 1/4] rename `once::ExclusiveState` to `OnceExclusiveState` It is a bit confusing when reading code that uses this type since it is not immediately obvious that it is specific to `Once`. Signed-off-by: Connor Tsui --- library/std/src/sync/lazy_lock.rs | 34 ++++++++++++--------- library/std/src/sync/poison/once.rs | 8 +++-- library/std/src/sys/sync/once/futex.rs | 18 +++++------ library/std/src/sys/sync/once/no_threads.rs | 18 +++++------ library/std/src/sys/sync/once/queue.rs | 18 +++++------ 5 files changed, 52 insertions(+), 44 deletions(-) diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 3231125f7a13a..16081d43cd49f 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -1,4 +1,4 @@ -use super::poison::once::ExclusiveState; +use super::poison::once::OnceExclusiveState; use crate::cell::UnsafeCell; use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; @@ -140,14 +140,18 @@ impl T> LazyLock { pub fn into_inner(mut this: Self) -> Result { let state = this.once.state(); match state { - ExclusiveState::Poisoned => panic_poisoned(), + OnceExclusiveState::Poisoned => panic_poisoned(), state => { let this = ManuallyDrop::new(this); let data = unsafe { ptr::read(&this.data) }.into_inner(); match state { - ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })), - ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })), - ExclusiveState::Poisoned => unreachable!(), + OnceExclusiveState::Incomplete => { + Err(ManuallyDrop::into_inner(unsafe { data.f })) + } + OnceExclusiveState::Complete => { + Ok(ManuallyDrop::into_inner(unsafe { data.value })) + } + OnceExclusiveState::Poisoned => unreachable!(), } } } @@ -189,7 +193,7 @@ impl T> LazyLock { impl Drop for PoisonOnPanic<'_, T, F> { #[inline] fn drop(&mut self) { - self.0.once.set_state(ExclusiveState::Poisoned); + self.0.once.set_state(OnceExclusiveState::Poisoned); } } @@ -200,7 +204,7 @@ impl T> LazyLock { let guard = PoisonOnPanic(this); let data = f(); guard.0.data.get_mut().value = ManuallyDrop::new(data); - guard.0.once.set_state(ExclusiveState::Complete); + guard.0.once.set_state(OnceExclusiveState::Complete); core::mem::forget(guard); // SAFETY: We put the value there above. unsafe { &mut this.data.get_mut().value } @@ -208,11 +212,11 @@ impl T> LazyLock { let state = this.once.state(); match state { - ExclusiveState::Poisoned => panic_poisoned(), + OnceExclusiveState::Poisoned => panic_poisoned(), // SAFETY: The `Once` states we completed the initialization. - ExclusiveState::Complete => unsafe { &mut this.data.get_mut().value }, + OnceExclusiveState::Complete => unsafe { &mut this.data.get_mut().value }, // SAFETY: The state is `Incomplete`. - ExclusiveState::Incomplete => unsafe { really_init_mut(this) }, + OnceExclusiveState::Incomplete => unsafe { really_init_mut(this) }, } } @@ -293,7 +297,7 @@ impl LazyLock { match state { // SAFETY: // The closure has been run successfully, so `value` has been initialized. - ExclusiveState::Complete => Some(unsafe { &mut this.data.get_mut().value }), + OnceExclusiveState::Complete => Some(unsafe { &mut this.data.get_mut().value }), _ => None, } } @@ -332,11 +336,13 @@ impl LazyLock { impl Drop for LazyLock { fn drop(&mut self) { match self.once.state() { - ExclusiveState::Incomplete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) }, - ExclusiveState::Complete => unsafe { + OnceExclusiveState::Incomplete => unsafe { + ManuallyDrop::drop(&mut self.data.get_mut().f) + }, + OnceExclusiveState::Complete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().value) }, - ExclusiveState::Poisoned => {} + OnceExclusiveState::Poisoned => {} } } } diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs index faf2913c54730..12cc32f381d18 100644 --- a/library/std/src/sync/poison/once.rs +++ b/library/std/src/sync/poison/once.rs @@ -49,7 +49,9 @@ pub struct OnceState { pub(crate) inner: sys::OnceState, } -pub(crate) enum ExclusiveState { +/// Used for the internal implementation of `sys::sync::once` on different platforms and the +/// [`LazyLock`](crate::sync::LazyLock) implementation. +pub(crate) enum OnceExclusiveState { Incomplete, Poisoned, Complete, @@ -310,7 +312,7 @@ impl Once { /// be running, so the state must be either "incomplete", "poisoned" or /// "complete". #[inline] - pub(crate) fn state(&mut self) -> ExclusiveState { + pub(crate) fn state(&mut self) -> OnceExclusiveState { self.inner.state() } @@ -320,7 +322,7 @@ impl Once { /// be running, so the state must be either "incomplete", "poisoned" or /// "complete". #[inline] - pub(crate) fn set_state(&mut self, new_state: ExclusiveState) { + pub(crate) fn set_state(&mut self, new_state: OnceExclusiveState) { self.inner.set_state(new_state); } } diff --git a/library/std/src/sys/sync/once/futex.rs b/library/std/src/sys/sync/once/futex.rs index 407fdcebcf5cc..18f7f5d3d5f71 100644 --- a/library/std/src/sys/sync/once/futex.rs +++ b/library/std/src/sys/sync/once/futex.rs @@ -1,7 +1,7 @@ use crate::cell::Cell; use crate::sync as public; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; -use crate::sync::poison::once::ExclusiveState; +use crate::sync::poison::once::OnceExclusiveState; use crate::sys::futex::{Futex, Primitive, futex_wait, futex_wake_all}; // On some platforms, the OS is very nice and handles the waiter queue for us. @@ -83,21 +83,21 @@ impl Once { } #[inline] - pub(crate) fn state(&mut self) -> ExclusiveState { + pub(crate) fn state(&mut self) -> OnceExclusiveState { match *self.state_and_queued.get_mut() { - INCOMPLETE => ExclusiveState::Incomplete, - POISONED => ExclusiveState::Poisoned, - COMPLETE => ExclusiveState::Complete, + INCOMPLETE => OnceExclusiveState::Incomplete, + POISONED => OnceExclusiveState::Poisoned, + COMPLETE => OnceExclusiveState::Complete, _ => unreachable!("invalid Once state"), } } #[inline] - pub(crate) fn set_state(&mut self, new_state: ExclusiveState) { + pub(crate) fn set_state(&mut self, new_state: OnceExclusiveState) { *self.state_and_queued.get_mut() = match new_state { - ExclusiveState::Incomplete => INCOMPLETE, - ExclusiveState::Poisoned => POISONED, - ExclusiveState::Complete => COMPLETE, + OnceExclusiveState::Incomplete => INCOMPLETE, + OnceExclusiveState::Poisoned => POISONED, + OnceExclusiveState::Complete => COMPLETE, }; } diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs index 2568059cfe3a8..7c4cd1a5715d8 100644 --- a/library/std/src/sys/sync/once/no_threads.rs +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -1,6 +1,6 @@ use crate::cell::Cell; use crate::sync as public; -use crate::sync::poison::once::ExclusiveState; +use crate::sync::poison::once::OnceExclusiveState; pub struct Once { state: Cell, @@ -45,21 +45,21 @@ impl Once { } #[inline] - pub(crate) fn state(&mut self) -> ExclusiveState { + pub(crate) fn state(&mut self) -> OnceExclusiveState { match self.state.get() { - State::Incomplete => ExclusiveState::Incomplete, - State::Poisoned => ExclusiveState::Poisoned, - State::Complete => ExclusiveState::Complete, + State::Incomplete => OnceExclusiveState::Incomplete, + State::Poisoned => OnceExclusiveState::Poisoned, + State::Complete => OnceExclusiveState::Complete, _ => unreachable!("invalid Once state"), } } #[inline] - pub(crate) fn set_state(&mut self, new_state: ExclusiveState) { + pub(crate) fn set_state(&mut self, new_state: OnceExclusiveState) { self.state.set(match new_state { - ExclusiveState::Incomplete => State::Incomplete, - ExclusiveState::Poisoned => State::Poisoned, - ExclusiveState::Complete => State::Complete, + OnceExclusiveState::Incomplete => State::Incomplete, + OnceExclusiveState::Poisoned => State::Poisoned, + OnceExclusiveState::Complete => State::Complete, }); } diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index 17d99cdb38595..d2663f7771de8 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -58,7 +58,7 @@ use crate::cell::Cell; use crate::sync::atomic::Ordering::{AcqRel, Acquire, Release}; use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr}; -use crate::sync::poison::once::ExclusiveState; +use crate::sync::poison::once::OnceExclusiveState; use crate::thread::{self, Thread}; use crate::{fmt, ptr, sync as public}; @@ -131,21 +131,21 @@ impl Once { } #[inline] - pub(crate) fn state(&mut self) -> ExclusiveState { + pub(crate) fn state(&mut self) -> OnceExclusiveState { match self.state_and_queue.get_mut().addr() { - INCOMPLETE => ExclusiveState::Incomplete, - POISONED => ExclusiveState::Poisoned, - COMPLETE => ExclusiveState::Complete, + INCOMPLETE => OnceExclusiveState::Incomplete, + POISONED => OnceExclusiveState::Poisoned, + COMPLETE => OnceExclusiveState::Complete, _ => unreachable!("invalid Once state"), } } #[inline] - pub(crate) fn set_state(&mut self, new_state: ExclusiveState) { + pub(crate) fn set_state(&mut self, new_state: OnceExclusiveState) { *self.state_and_queue.get_mut() = match new_state { - ExclusiveState::Incomplete => ptr::without_provenance_mut(INCOMPLETE), - ExclusiveState::Poisoned => ptr::without_provenance_mut(POISONED), - ExclusiveState::Complete => ptr::without_provenance_mut(COMPLETE), + OnceExclusiveState::Incomplete => ptr::without_provenance_mut(INCOMPLETE), + OnceExclusiveState::Poisoned => ptr::without_provenance_mut(POISONED), + OnceExclusiveState::Complete => ptr::without_provenance_mut(COMPLETE), }; } From 0758e191d518fc9dc6861e4c43ab6fc11bb9e678 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Fri, 17 Oct 2025 11:02:47 -0400 Subject: [PATCH 2/4] clean up some documentation Signed-off-by: Connor Tsui --- library/std/src/sync/mod.rs | 2 +- library/std/src/sync/poison.rs | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 97c04d07eaf1d..00aac71e2d1c1 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -142,7 +142,7 @@ //! most one thread at a time is able to access some data. //! //! - [`Once`]: Used for a thread-safe, one-time global initialization routine. -//! Mostly useful for implementing other types like `OnceLock`. +//! Mostly useful for implementing other types like [`OnceLock`]. //! //! - [`OnceLock`]: Used for thread-safe, one-time initialization of a //! variable, with potentially different initializers based on the caller. diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 5517082033380..b4f18e755392f 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -13,8 +13,8 @@ //! the panics are recognized reliably or on a best-effort basis depend on the //! primitive. See [Overview](#overview) below. //! -//! For the alternative implementations that do not employ poisoning, -//! see [`std::sync::nonpoison`]. +//! The synchronization objects in this module have alternative implementations that do not employ +//! poisoning in the [`std::sync::nonpoison`] module. //! //! [`std::sync::nonpoison`]: crate::sync::nonpoison //! @@ -42,14 +42,6 @@ //! [`Mutex::lock()`] returns a [`LockResult`], providing a way to deal with //! the poisoned state. See [`Mutex`'s documentation](Mutex#poisoning) for more. //! -//! - [`Once`]: A thread-safe way to run a piece of code only once. -//! Mostly useful for implementing one-time global initialization. -//! -//! [`Once`] is reliably poisoned if the piece of code passed to -//! [`Once::call_once()`] or [`Once::call_once_force()`] panics. -//! When in poisoned state, subsequent calls to [`Once::call_once()`] will panic too. -//! [`Once::call_once_force()`] can be used to clear the poisoned state. -//! //! - [`RwLock`]: Provides a mutual exclusion mechanism which allows //! multiple readers at the same time, while allowing only one //! writer at a time. In some cases, this can be more efficient than @@ -59,6 +51,11 @@ //! Note, however, that an `RwLock` may only be poisoned if a panic occurs //! while it is locked exclusively (write mode). If a panic occurs in any reader, //! then the lock will not be poisoned. +//! +//! Note that the [`Once`] type also employs poisoning, but since it has non-poisoning `force` +//! methods available on it, there is no separate `nonpoison` and `poison` version. +//! +//! [`Once`]: crate::sync::Once // If we are not unwinding, `PoisonError` is uninhabited. #![cfg_attr(not(panic = "unwind"), expect(unreachable_code))] From 7b61403c507a9fe511735e238cd6cdc1e9225b8c Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Fri, 17 Oct 2025 11:16:30 -0400 Subject: [PATCH 3/4] reorganize `library/std/src/sync/mod.rs` file Moves things around to make a bit more sense (plus prepare moving `once` out of `poison`. Signed-off-by: Connor Tsui --- library/std/src/sync/mod.rs | 59 +++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 00aac71e2d1c1..7374f09efdcf6 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -181,7 +181,20 @@ pub use alloc_crate::sync::UniqueArc; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::sync::{Arc, Weak}; -// FIXME(sync_nonpoison,sync_poison_mod): remove all `#[doc(inline)]` once the modules are stabilized. +#[unstable(feature = "mpmc_channel", issue = "126840")] +pub mod mpmc; +pub mod mpsc; + +// TODO: Make this `self::once::ONCE_INIT`. +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(inline)] +#[expect(deprecated)] +pub use self::poison::ONCE_INIT; + +mod barrier; +mod lazy_lock; +mod once_lock; +mod reentrant_lock; // These exist only in one flavor: no poisoning. #[stable(feature = "rust1", since = "1.0.0")] @@ -193,48 +206,38 @@ pub use self::once_lock::OnceLock; #[unstable(feature = "reentrant_lock", issue = "121440")] pub use self::reentrant_lock::{ReentrantLock, ReentrantLockGuard}; -// These make sense and exist only with poisoning. +// Note: in the future we will change the default version in `std::sync` to the non-poisoning +// version over an edition. +// See https://github.com/rust-lang/rust/issues/134645#issuecomment-3324577500 for more details. + +#[unstable(feature = "sync_nonpoison", issue = "134645")] +pub mod nonpoison; +#[unstable(feature = "sync_poison_mod", issue = "134646")] +pub mod poison; + +// FIXME(sync_poison_mod): remove all `#[doc(inline)]` once the modules are stabilized. + +// These exist only with poisoning. #[stable(feature = "rust1", since = "1.0.0")] #[doc(inline)] pub use self::poison::{LockResult, PoisonError}; -// These (should) exist in both flavors: with and without poisoning. -// FIXME(sync_nonpoison): implement nonpoison versions: -// * Mutex (nonpoison_mutex) -// * Condvar (nonpoison_condvar) -// * Once (nonpoison_once) -// * RwLock (nonpoison_rwlock) +// These exist in both flavors: with and without poisoning. // The historical default is the version with poisoning. #[stable(feature = "rust1", since = "1.0.0")] #[doc(inline)] pub use self::poison::{ - Mutex, MutexGuard, TryLockError, TryLockResult, + TryLockError, TryLockResult, + Mutex, MutexGuard, + RwLock, RwLockReadGuard, RwLockWriteGuard, Condvar, Once, OnceState, - RwLock, RwLockReadGuard, RwLockWriteGuard, }; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(inline)] -#[expect(deprecated)] -pub use self::poison::ONCE_INIT; + #[unstable(feature = "mapped_lock_guards", issue = "117108")] #[doc(inline)] pub use self::poison::{MappedMutexGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard}; -#[unstable(feature = "mpmc_channel", issue = "126840")] -pub mod mpmc; -pub mod mpsc; - -#[unstable(feature = "sync_nonpoison", issue = "134645")] -pub mod nonpoison; -#[unstable(feature = "sync_poison_mod", issue = "134646")] -pub mod poison; - -mod barrier; -mod lazy_lock; -mod once_lock; -mod reentrant_lock; - /// A type indicating whether a timed wait on a condition variable returned /// due to a time out or not. /// From 3a9c521285684a45338670d329ba1472f069c0b9 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Fri, 17 Oct 2025 11:35:47 -0400 Subject: [PATCH 4/4] move `once` module out of `poison` Since `Once` will not have a non-poisoning variant, we remove it from the `poison` module. Signed-off-by: Connor Tsui --- library/std/src/sync/lazy_lock.rs | 2 +- library/std/src/sync/mod.rs | 9 ++++++--- library/std/src/sync/{poison => }/once.rs | 0 library/std/src/sync/poison.rs | 6 ------ library/std/src/sys/sync/once/futex.rs | 2 +- library/std/src/sys/sync/once/no_threads.rs | 2 +- library/std/src/sys/sync/once/queue.rs | 2 +- 7 files changed, 10 insertions(+), 13 deletions(-) rename library/std/src/sync/{poison => }/once.rs (100%) diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 16081d43cd49f..f1cae4b207c9a 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -1,4 +1,4 @@ -use super::poison::once::OnceExclusiveState; +use super::once::OnceExclusiveState; use crate::cell::UnsafeCell; use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 7374f09efdcf6..19b3040dcb279 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -185,11 +185,15 @@ pub use alloc_crate::sync::{Arc, Weak}; pub mod mpmc; pub mod mpsc; -// TODO: Make this `self::once::ONCE_INIT`. +pub(crate) mod once; // `pub(crate)` for the `sys::sync::once` implementations and `LazyLock`. + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::once::{Once, OnceState}; + #[stable(feature = "rust1", since = "1.0.0")] #[doc(inline)] #[expect(deprecated)] -pub use self::poison::ONCE_INIT; +pub use self::once::ONCE_INIT; mod barrier; mod lazy_lock; @@ -231,7 +235,6 @@ pub use self::poison::{ Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard, Condvar, - Once, OnceState, }; #[unstable(feature = "mapped_lock_guards", issue = "117108")] diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/once.rs similarity index 100% rename from library/std/src/sync/poison/once.rs rename to library/std/src/sync/once.rs diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index b4f18e755392f..9f40c01546632 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -66,11 +66,6 @@ pub use self::condvar::Condvar; pub use self::mutex::MappedMutexGuard; #[stable(feature = "rust1", since = "1.0.0")] pub use self::mutex::{Mutex, MutexGuard}; -#[stable(feature = "rust1", since = "1.0.0")] -#[expect(deprecated)] -pub use self::once::ONCE_INIT; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::once::{Once, OnceState}; #[unstable(feature = "mapped_lock_guards", issue = "117108")] pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; #[stable(feature = "rust1", since = "1.0.0")] @@ -85,7 +80,6 @@ use crate::thread; mod condvar; #[stable(feature = "rust1", since = "1.0.0")] mod mutex; -pub(crate) mod once; mod rwlock; pub(crate) struct Flag { diff --git a/library/std/src/sys/sync/once/futex.rs b/library/std/src/sys/sync/once/futex.rs index 18f7f5d3d5f71..096f1d879ef26 100644 --- a/library/std/src/sys/sync/once/futex.rs +++ b/library/std/src/sys/sync/once/futex.rs @@ -1,7 +1,7 @@ use crate::cell::Cell; use crate::sync as public; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; -use crate::sync::poison::once::OnceExclusiveState; +use crate::sync::once::OnceExclusiveState; use crate::sys::futex::{Futex, Primitive, futex_wait, futex_wake_all}; // On some platforms, the OS is very nice and handles the waiter queue for us. diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs index 7c4cd1a5715d8..576bbf644cbed 100644 --- a/library/std/src/sys/sync/once/no_threads.rs +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -1,6 +1,6 @@ use crate::cell::Cell; use crate::sync as public; -use crate::sync::poison::once::OnceExclusiveState; +use crate::sync::once::OnceExclusiveState; pub struct Once { state: Cell, diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index d2663f7771de8..d7219a7361cff 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -58,7 +58,7 @@ use crate::cell::Cell; use crate::sync::atomic::Ordering::{AcqRel, Acquire, Release}; use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr}; -use crate::sync::poison::once::OnceExclusiveState; +use crate::sync::once::OnceExclusiveState; use crate::thread::{self, Thread}; use crate::{fmt, ptr, sync as public};