sync: require that an RwLock has max_readers != 0 (#8076)

This commit is contained in:
Alice Ryhl
2026-05-07 09:31:12 +02:00
committed by GitHub
parent 9fccf5339d
commit 30d25ccb8b
2 changed files with 23 additions and 1 deletions
+11 -1
View File
@@ -266,12 +266,13 @@ impl<T: ?Sized> RwLock<T> {
///
/// # Panics
///
/// Panics if `max_reads` is more than `u32::MAX >> 3`.
/// Panics if `max_reads` is `0` or is bigger than `u32::MAX >> 3`.
#[track_caller]
pub fn with_max_readers(value: T, max_reads: u32) -> RwLock<T>
where
T: Sized,
{
assert_ne!(max_reads, 0, "a RwLock may not be created with 0 readers");
assert!(
max_reads <= MAX_READS,
"a RwLock may not be created with more than {MAX_READS} readers"
@@ -367,11 +368,16 @@ impl<T: ?Sized> RwLock<T> {
///
/// static LOCK: RwLock<i32> = RwLock::const_with_max_readers(5, 1024);
/// ```
///
/// # Panics
///
/// Panics if `max_reads` is `0` or is bigger than `u32::MAX >> 3`.
#[cfg(not(all(loom, test)))]
pub const fn const_with_max_readers(value: T, max_reads: u32) -> RwLock<T>
where
T: Sized,
{
assert!(max_reads != 0, "a RwLock may not be created with 0 readers");
assert!(max_reads <= MAX_READS);
RwLock {
@@ -771,6 +777,7 @@ impl<T: ?Sized> RwLock<T> {
/// ```
pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
let acquire_fut = async {
debug_assert_ne!(self.mr, 0);
self.s.acquire(self.mr as usize).await.unwrap_or_else(|_| {
// The semaphore was closed. but, we never explicitly close it, and we have a
// handle to it through the Arc, which means that this can never happen.
@@ -906,6 +913,7 @@ impl<T: ?Sized> RwLock<T> {
let resource_span = self.resource_span.clone();
let acquire_fut = async {
debug_assert_ne!(self.mr, 0);
self.s.acquire(self.mr as usize).await.unwrap_or_else(|_| {
// The semaphore was closed. but, we never explicitly close it, and we have a
// handle to it through the Arc, which means that this can never happen.
@@ -970,6 +978,7 @@ impl<T: ?Sized> RwLock<T> {
/// }
/// ```
pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, T>, TryLockError> {
debug_assert_ne!(self.mr, 0);
match self.s.try_acquire(self.mr as usize) {
Ok(permit) => permit,
Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
@@ -1028,6 +1037,7 @@ impl<T: ?Sized> RwLock<T> {
/// }
/// ```
pub fn try_write_owned(self: Arc<Self>) -> Result<OwnedRwLockWriteGuard<T>, TryLockError> {
debug_assert_ne!(self.mr, 0);
match self.s.try_acquire(self.mr as usize) {
Ok(permit) => permit,
Err(TryAcquireError::NoPermits) => return Err(TryLockError(())),
+12
View File
@@ -78,6 +78,18 @@ fn exhaust_reading() {
let _g1 = assert_ready!(t1.poll());
}
#[test]
#[should_panic(expected = "a RwLock may not be created with 0 readers")]
fn zero_max_readers() {
RwLock::with_max_readers(100, 0);
}
#[test]
#[should_panic(expected = "a RwLock may not be created with 0 readers")]
fn zero_max_readers_const() {
RwLock::const_with_max_readers(100, 0);
}
// When there is an active exclusive owner, subsequent exclusive access should not be possible
#[test]
fn write_exclusive_pending() {