Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions library/std/src/sync/lazy_lock.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::poison::once::ExclusiveState;
use super::once::OnceExclusiveState;
use crate::cell::UnsafeCell;
use crate::mem::ManuallyDrop;
use crate::ops::{Deref, DerefMut};
Expand Down Expand Up @@ -140,14 +140,18 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
pub fn into_inner(mut this: Self) -> Result<T, F> {
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!(),
}
}
}
Expand Down Expand Up @@ -189,7 +193,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
impl<T, F> Drop for PoisonOnPanic<'_, T, F> {
#[inline]
fn drop(&mut self) {
self.0.once.set_state(ExclusiveState::Poisoned);
self.0.once.set_state(OnceExclusiveState::Poisoned);
}
}

Expand All @@ -200,19 +204,19 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
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 }
}

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) },
}
}

Expand Down Expand Up @@ -293,7 +297,7 @@ impl<T, F> LazyLock<T, F> {
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,
}
}
Expand Down Expand Up @@ -332,11 +336,13 @@ impl<T, F> LazyLock<T, F> {
impl<T, F> Drop for LazyLock<T, F> {
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 => {}
}
}
}
Expand Down
66 changes: 36 additions & 30 deletions library/std/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -181,7 +181,24 @@ 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;

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::once::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")]
Expand All @@ -193,48 +210,37 @@ 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,
Condvar,
Once, OnceState,
TryLockError, TryLockResult,
Mutex, MutexGuard,
RwLock, RwLockReadGuard, RwLockWriteGuard,
Condvar,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like alphabetical ordering may have gotten flipped between Mutex and TryLockError. (would be nice if we could just remove the rustfmt::skip from this module but it does make things messy)

Copy link
Contributor Author

@connortsui20 connortsui20 Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually did this purposefully (though Condvar should probably come after RwLock now that I think about it because RwLock relies on TryLockError too). Once I finish revisions let me know if the ordering makes sense (commit 7b61403)

#[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.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()
}

Expand All @@ -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);
}
}
Expand Down
23 changes: 7 additions & 16 deletions library/std/src/sync/poison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
//!
Expand Down Expand Up @@ -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
Expand All @@ -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))]
Expand All @@ -69,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")]
Expand All @@ -88,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 {
Expand Down
18 changes: 9 additions & 9 deletions library/std/src/sys/sync/once/futex.rs
Original file line number Diff line number Diff line change
@@ -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::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.
Expand Down Expand Up @@ -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,
};
}

Expand Down
18 changes: 9 additions & 9 deletions library/std/src/sys/sync/once/no_threads.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::cell::Cell;
use crate::sync as public;
use crate::sync::poison::once::ExclusiveState;
use crate::sync::once::OnceExclusiveState;

pub struct Once {
state: Cell<State>,
Expand Down Expand Up @@ -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,
});
}

Expand Down
18 changes: 9 additions & 9 deletions library/std/src/sys/sync/once/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::once::OnceExclusiveState;
use crate::thread::{self, Thread};
use crate::{fmt, ptr, sync as public};

Expand Down Expand Up @@ -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),
};
}

Expand Down
Loading