Skip to content
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,
};
#[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
Loading