Skip to content

Commit ac00fe8

Browse files
committed
Auto merge of #134692 - GrigorenkoPV:sync_poision, r=tgross35
Move some things to `std::sync::poison` and reexport them in `std::sync` Tracking issue: #134646 r? `@tgross35` I've used `sync_poison_mod` feature flag instead, because `sync_poison` had already been used back in 1.2. try-job: x86_64-msvc
2 parents 870c13d + ee2ad4d commit ac00fe8

21 files changed

+141
-37
lines changed

library/std/src/sync/barrier.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
mod tests;
33

44
use crate::fmt;
5+
// FIXME(nonpoison_mutex,nonpoison_condvar): switch to nonpoison versions once they are available
56
use crate::sync::{Condvar, Mutex};
67

78
/// A barrier enables multiple threads to synchronize the beginning

library/std/src/sync/lazy_lock.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::once::ExclusiveState;
1+
use super::poison::once::ExclusiveState;
22
use crate::cell::UnsafeCell;
33
use crate::mem::ManuallyDrop;
44
use crate::ops::Deref;
@@ -63,6 +63,7 @@ union Data<T, F> {
6363
/// ```
6464
#[stable(feature = "lazy_cell", since = "1.80.0")]
6565
pub struct LazyLock<T, F = fn() -> T> {
66+
// FIXME(nonpoison_once): if possible, switch to nonpoison version once it is available
6667
once: Once,
6768
data: UnsafeCell<Data<T, F>>,
6869
}

library/std/src/sync/mod.rs

+37-19
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@
167167
168168
#![stable(feature = "rust1", since = "1.0.0")]
169169

170+
// No formatting: this file is just re-exports, and their order is worth preserving.
171+
#![cfg_attr(rustfmt, rustfmt::skip)]
172+
173+
// These come from `core` & `alloc` and only in one flavor: no poisoning.
170174
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
171175
pub use core::sync::Exclusive;
172176
#[stable(feature = "rust1", since = "1.0.0")]
@@ -175,40 +179,54 @@ pub use core::sync::atomic;
175179
#[stable(feature = "rust1", since = "1.0.0")]
176180
pub use alloc_crate::sync::{Arc, Weak};
177181

182+
// FIXME(sync_nonpoison,sync_poison_mod): remove all `#[doc(inline)]` once the modules are stabilized.
183+
184+
// These exist only in one flavor: no poisoning.
178185
#[stable(feature = "rust1", since = "1.0.0")]
179186
pub use self::barrier::{Barrier, BarrierWaitResult};
180-
#[stable(feature = "rust1", since = "1.0.0")]
181-
pub use self::condvar::{Condvar, WaitTimeoutResult};
182187
#[stable(feature = "lazy_cell", since = "1.80.0")]
183188
pub use self::lazy_lock::LazyLock;
184-
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
185-
pub use self::mutex::MappedMutexGuard;
186-
#[stable(feature = "rust1", since = "1.0.0")]
187-
pub use self::mutex::{Mutex, MutexGuard};
188-
#[stable(feature = "rust1", since = "1.0.0")]
189-
#[allow(deprecated)]
190-
pub use self::once::{ONCE_INIT, Once, OnceState};
191189
#[stable(feature = "once_cell", since = "1.70.0")]
192190
pub use self::once_lock::OnceLock;
193-
#[stable(feature = "rust1", since = "1.0.0")]
194-
pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult};
195191
#[unstable(feature = "reentrant_lock", issue = "121440")]
196192
pub use self::reentrant_lock::{ReentrantLock, ReentrantLockGuard};
197-
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
198-
pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
193+
194+
// These make sense and exist only with poisoning.
199195
#[stable(feature = "rust1", since = "1.0.0")]
200-
pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
196+
#[doc(inline)]
197+
pub use self::poison::{LockResult, PoisonError};
198+
199+
// These (should) exist in both flavors: with and without poisoning.
200+
// FIXME(sync_nonpoison): implement nonpoison versions:
201+
// * Mutex (nonpoison_mutex)
202+
// * Condvar (nonpoison_condvar)
203+
// * Once (nonpoison_once)
204+
// * RwLock (nonpoison_rwlock)
205+
// The historical default is the version with poisoning.
206+
#[stable(feature = "rust1", since = "1.0.0")]
207+
#[doc(inline)]
208+
pub use self::poison::{
209+
Mutex, MutexGuard, TryLockError, TryLockResult,
210+
Condvar, WaitTimeoutResult,
211+
Once, OnceState,
212+
RwLock, RwLockReadGuard, RwLockWriteGuard,
213+
};
214+
#[stable(feature = "rust1", since = "1.0.0")]
215+
#[doc(inline)]
216+
#[expect(deprecated)]
217+
pub use self::poison::ONCE_INIT;
218+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
219+
#[doc(inline)]
220+
pub use self::poison::{MappedMutexGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard};
201221

202222
#[unstable(feature = "mpmc_channel", issue = "126840")]
203223
pub mod mpmc;
204224
pub mod mpsc;
205225

226+
#[unstable(feature = "sync_poison_mod", issue = "134646")]
227+
pub mod poison;
228+
206229
mod barrier;
207-
mod condvar;
208230
mod lazy_lock;
209-
mod mutex;
210-
pub(crate) mod once;
211231
mod once_lock;
212-
mod poison;
213232
mod reentrant_lock;
214-
mod rwlock;

library/std/src/sync/once_lock.rs

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ use crate::sync::Once;
101101
/// ```
102102
#[stable(feature = "once_cell", since = "1.70.0")]
103103
pub struct OnceLock<T> {
104+
// FIXME(nonpoison_once): switch to nonpoison version once it is available
104105
once: Once,
105106
// Whether or not the value is initialized is tracked by `once.is_completed()`.
106107
value: UnsafeCell<MaybeUninit<T>>,

library/std/src/sync/poison.rs

+84-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,92 @@
1+
//! Synchronization objects that employ poisoning.
2+
//!
3+
//! # Poisoning
4+
//!
5+
//! All synchronization objects in this module implement a strategy called "poisoning"
6+
//! where if a thread panics while holding the exclusive access granted by the primitive,
7+
//! the state of the primitive is set to "poisoned".
8+
//! This information is then propagated to all other threads
9+
//! to signify that the data protected by this primitive is likely tainted
10+
//! (some invariant is not being upheld).
11+
//!
12+
//! The specifics of how this "poisoned" state affects other threads
13+
//! depend on the primitive. See [#Overview] bellow.
14+
//!
15+
//! For the alternative implementations that do not employ poisoning,
16+
//! see `std::sys::nonpoisoning`.
17+
//!
18+
//! # Overview
19+
//!
20+
//! Below is a list of synchronization objects provided by this module
21+
//! with a high-level overview for each object and a description
22+
//! of how it employs "poisoning".
23+
//!
24+
//! - [`Condvar`]: Condition Variable, providing the ability to block
25+
//! a thread while waiting for an event to occur.
26+
//!
27+
//! Condition variables are typically associated with
28+
//! a boolean predicate (a condition) and a mutex.
29+
//! This implementation is associated with [`poison::Mutex`](Mutex),
30+
//! which employs poisoning.
31+
//! For this reason, [`Condvar::wait()`] will return a [`LockResult`],
32+
//! just like [`poison::Mutex::lock()`](Mutex::lock) does.
33+
//!
34+
//! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at
35+
//! most one thread at a time is able to access some data.
36+
//!
37+
//! [`Mutex::lock()`] returns a [`LockResult`],
38+
//! providing a way to deal with the poisoned state.
39+
//! See [`Mutex`'s documentation](Mutex#poisoning) for more.
40+
//!
41+
//! - [`Once`]: A thread-safe way to run a piece of code only once.
42+
//! Mostly useful for implementing one-time global initialization.
43+
//!
44+
//! [`Once`] is poisoned if the piece of code passed to
45+
//! [`Once::call_once()`] or [`Once::call_once_force()`] panics.
46+
//! When in poisoned state, subsequent calls to [`Once::call_once()`] will panic too.
47+
//! [`Once::call_once_force()`] can be used to clear the poisoned state.
48+
//!
49+
//! - [`RwLock`]: Provides a mutual exclusion mechanism which allows
50+
//! multiple readers at the same time, while allowing only one
51+
//! writer at a time. In some cases, this can be more efficient than
52+
//! a mutex.
53+
//!
54+
//! This implementation, like [`Mutex`], will become poisoned on a panic.
55+
//! Note, however, that an `RwLock` may only be poisoned if a panic occurs
56+
//! while it is locked exclusively (write mode). If a panic occurs in any reader,
57+
//! then the lock will not be poisoned.
58+
59+
// FIXME(sync_nonpoison) add links to sync::nonpoison to the doc comment above.
60+
61+
#[stable(feature = "rust1", since = "1.0.0")]
62+
pub use self::condvar::{Condvar, WaitTimeoutResult};
63+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
64+
pub use self::mutex::MappedMutexGuard;
65+
#[stable(feature = "rust1", since = "1.0.0")]
66+
pub use self::mutex::{Mutex, MutexGuard};
67+
#[stable(feature = "rust1", since = "1.0.0")]
68+
#[expect(deprecated)]
69+
pub use self::once::ONCE_INIT;
70+
#[stable(feature = "rust1", since = "1.0.0")]
71+
pub use self::once::{Once, OnceState};
72+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
73+
pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
74+
#[stable(feature = "rust1", since = "1.0.0")]
75+
pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
176
use crate::error::Error;
277
use crate::fmt;
378
#[cfg(panic = "unwind")]
479
use crate::sync::atomic::{AtomicBool, Ordering};
580
#[cfg(panic = "unwind")]
681
use crate::thread;
782

8-
pub struct Flag {
83+
mod condvar;
84+
#[stable(feature = "rust1", since = "1.0.0")]
85+
mod mutex;
86+
pub(crate) mod once;
87+
mod rwlock;
88+
89+
pub(crate) struct Flag {
990
#[cfg(panic = "unwind")]
1091
failed: AtomicBool,
1192
}
@@ -78,7 +159,7 @@ impl Flag {
78159
}
79160

80161
#[derive(Clone)]
81-
pub struct Guard {
162+
pub(crate) struct Guard {
82163
#[cfg(panic = "unwind")]
83164
panicking: bool,
84165
}
@@ -316,7 +397,7 @@ impl<T> Error for TryLockError<T> {
316397
}
317398
}
318399

319-
pub fn map_result<T, U, F>(result: LockResult<T>, f: F) -> LockResult<U>
400+
pub(crate) fn map_result<T, U, F>(result: LockResult<T>, f: F) -> LockResult<U>
320401
where
321402
F: FnOnce(T) -> U,
322403
{

library/std/src/sync/condvar.rs library/std/src/sync/poison/condvar.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
mod tests;
33

44
use crate::fmt;
5-
use crate::sync::{LockResult, MutexGuard, PoisonError, mutex, poison};
5+
use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex};
66
use crate::sys::sync as sys;
77
use crate::time::{Duration, Instant};
88

@@ -16,6 +16,8 @@ use crate::time::{Duration, Instant};
1616
#[stable(feature = "wait_timeout", since = "1.5.0")]
1717
pub struct WaitTimeoutResult(bool);
1818

19+
// FIXME(sync_nonpoison): `WaitTimeoutResult` is actually poisoning-agnostic, it seems.
20+
// Should we take advantage of this fact?
1921
impl WaitTimeoutResult {
2022
/// Returns `true` if the wait was known to have timed out.
2123
///
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

library/std/src/sys/sync/once/futex.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::cell::Cell;
22
use crate::sync as public;
33
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
4-
use crate::sync::once::ExclusiveState;
4+
use crate::sync::poison::once::ExclusiveState;
55
use crate::sys::futex::{Futex, Primitive, futex_wait, futex_wake_all};
66

77
// On some platforms, the OS is very nice and handles the waiter queue for us.

library/std/src/sys/sync/once/no_threads.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::cell::Cell;
22
use crate::sync as public;
3-
use crate::sync::once::ExclusiveState;
3+
use crate::sync::poison::once::ExclusiveState;
44

55
pub struct Once {
66
state: Cell<State>,

library/std/src/sys/sync/once/queue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
use crate::cell::Cell;
5959
use crate::sync::atomic::Ordering::{AcqRel, Acquire, Release};
6060
use crate::sync::atomic::{AtomicBool, AtomicPtr};
61-
use crate::sync::once::ExclusiveState;
61+
use crate::sync::poison::once::ExclusiveState;
6262
use crate::thread::{self, Thread};
6363
use crate::{fmt, ptr, sync as public};
6464

tests/debuginfo/mutex.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// cdb-command:g
1010
//
1111
// cdb-command:dx m,d
12-
// cdb-check:m,d [Type: std::sync::mutex::Mutex<i32>]
12+
// cdb-check:m,d [Type: std::sync::poison::mutex::Mutex<i32>]
1313
// cdb-check: [...] inner [Type: std::sys::sync::mutex::futex::Mutex]
1414
// cdb-check: [...] poison [Type: std::sync::poison::Flag]
1515
// cdb-check: [...] data : 0 [Type: core::cell::UnsafeCell<i32>]
@@ -21,8 +21,8 @@
2121

2222
//
2323
// cdb-command:dx _lock,d
24-
// cdb-check:_lock,d : Ok [Type: enum2$<core::result::Result<std::sync::mutex::MutexGuard<i32>,enum2$<std::sync::poison::TryLockError<std::sync::mutex::MutexGuard<i32> > > > >]
25-
// cdb-check: [...] __0 [Type: std::sync::mutex::MutexGuard<i32>]
24+
// cdb-check:_lock,d : Ok [Type: enum2$<core::result::Result<std::sync::poison::mutex::MutexGuard<i32>,enum2$<std::sync::poison::TryLockError<std::sync::poison::mutex::MutexGuard<i32> > > > >]
25+
// cdb-check: [...] __0 [Type: std::sync::poison::mutex::MutexGuard<i32>]
2626

2727
use std::sync::Mutex;
2828

tests/debuginfo/rwlock-read.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
// cdb-command:g
1010
//
1111
// cdb-command:dx l
12-
// cdb-check:l [Type: std::sync::rwlock::RwLock<i32>]
12+
// cdb-check:l [Type: std::sync::poison::rwlock::RwLock<i32>]
1313
// cdb-check: [...] poison [Type: std::sync::poison::Flag]
1414
// cdb-check: [...] data : 0 [Type: core::cell::UnsafeCell<i32>]
1515
//
1616
// cdb-command:dx r
17-
// cdb-check:r [Type: std::sync::rwlock::RwLockReadGuard<i32>]
17+
// cdb-check:r [Type: std::sync::poison::rwlock::RwLockReadGuard<i32>]
1818
// cdb-check: [...] data : NonNull([...]: 0) [Type: core::ptr::non_null::NonNull<i32>]
1919
// cdb-check: [...] inner_lock : [...] [Type: std::sys::sync::rwlock::futex::RwLock *]
2020

tests/debuginfo/rwlock-write.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
// cdb-command:g
1010
//
1111
// cdb-command:dx w
12-
// cdb-check:w [Type: std::sync::rwlock::RwLockWriteGuard<i32>]
13-
// cdb-check: [...] lock : [...] [Type: std::sync::rwlock::RwLock<i32> *]
12+
// cdb-check:w [Type: std::sync::poison::rwlock::RwLockWriteGuard<i32>]
13+
// cdb-check: [...] lock : [...] [Type: std::sync::poison::rwlock::RwLock<i32> *]
1414
// cdb-check: [...] poison [Type: std::sync::poison::Guard]
1515

1616
#[allow(unused_variables)]

tests/ui/traits/const-traits/span-bug-issue-121418.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ LL | pub const fn new() -> std::sync::Mutex<dyn T> {}
2727
|
2828
= help: within `Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)`
2929
note: required because it appears within the type `Mutex<(dyn T + 'static)>`
30-
--> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
30+
--> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
3131
= note: the return type of a function must have a statically known size
3232

3333
error: aborting due to 3 previous errors

tests/ui/typeck/assign-non-lval-derefmut.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | x.lock().unwrap() += 1;
2020
| cannot use `+=` on type `MutexGuard<'_, usize>`
2121
|
2222
note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
23-
--> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
23+
--> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
2424
|
2525
= note: not implement `AddAssign<{integer}>`
2626
help: `+=` can be used on `usize` if you dereference the left-hand side
@@ -52,7 +52,7 @@ LL | y += 1;
5252
| cannot use `+=` on type `MutexGuard<'_, usize>`
5353
|
5454
note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
55-
--> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
55+
--> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
5656
|
5757
= note: not implement `AddAssign<{integer}>`
5858
help: `+=` can be used on `usize` if you dereference the left-hand side

0 commit comments

Comments
 (0)