From dd79127911841e1c73a31dfd3cffbf34b24828b7 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Sun, 29 Jun 2025 21:00:23 +0900 Subject: [PATCH 1/2] stabilize feature rwlock_downgrade --- library/std/src/sync/poison/rwlock.rs | 3 +-- library/std/tests/sync/lib.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 934a173425a81..8e189d52306cc 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -1084,7 +1084,6 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// # Example /// /// ``` - /// #![feature(rwlock_downgrade)] /// use std::sync::{Arc, RwLock, RwLockWriteGuard}; /// /// // The inner value starts as 0. @@ -1118,7 +1117,7 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// let final_check = rw.read().unwrap(); /// assert_eq!(*final_check, 2); /// ``` - #[unstable(feature = "rwlock_downgrade", issue = "128203")] + #[stable(feature = "rwlock_downgrade", since = "CURRENT_RUSTC_VERSION")] pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> { let lock = s.lock; diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs index 51190f0894fb7..1bc6dc2d01511 100644 --- a/library/std/tests/sync/lib.rs +++ b/library/std/tests/sync/lib.rs @@ -4,7 +4,6 @@ #![feature(once_cell_try)] #![feature(lock_value_accessors)] #![feature(reentrant_lock)] -#![feature(rwlock_downgrade)] #![feature(std_internals)] #![allow(internal_features)] From 2c39d70bbf067dc8c40175f0eef4da7c80c9cec9 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Wed, 2 Jul 2025 14:15:12 +0900 Subject: [PATCH 2/2] simplify downgrade documentation --- library/std/src/sync/poison/rwlock.rs | 62 ++++++++++++++++----------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 8e189d52306cc..9a669739eeddd 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -1073,49 +1073,61 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. /// - /// This method will atomically change the state of the [`RwLock`] from exclusive mode into - /// shared mode. This means that it is impossible for a writing thread to get in between a - /// thread calling `downgrade` and the same thread reading whatever it wrote while it had the - /// [`RwLock`] in write mode. + /// Since we have the `RwLockWriteGuard`, the [`RwLock`] must already be locked for writing, so + /// this method cannot fail. /// - /// Note that since we have the `RwLockWriteGuard`, we know that the [`RwLock`] is already - /// locked for writing, so this method cannot fail. + /// Aftering downgrading, other readers will be allowed to read the protected data. /// - /// # Example + /// # Examples + /// + /// `downgrade` takes ownership of the `RwLockWriteGuard` and returns a [`RwLockReadGuard`]. + /// + /// ``` + /// use std::sync::{RwLock, RwLockWriteGuard}; + /// + /// let rw = RwLock::new(0); + /// + /// let mut write_guard = rw.write().unwrap(); + /// *write_guard = 42; + /// + /// let read_guard = RwLockWriteGuard::downgrade(write_guard); + /// assert_eq!(42, *read_guard); + /// ``` + /// + /// `downgrade` will _atomically_ change the state of the [`RwLock`] from exclusive mode into + /// shared mode. This means that it is impossible for another writing thread to get in between a + /// thread calling `downgrade` and any reads it performs after downgrading. /// /// ``` /// use std::sync::{Arc, RwLock, RwLockWriteGuard}; /// - /// // The inner value starts as 0. - /// let rw = Arc::new(RwLock::new(0)); + /// let rw = Arc::new(RwLock::new(1)); /// /// // Put the lock in write mode. /// let mut main_write_guard = rw.write().unwrap(); /// - /// let evil = rw.clone(); - /// let handle = std::thread::spawn(move || { + /// let rw_clone = rw.clone(); + /// let evil_handle = std::thread::spawn(move || { /// // This will not return until the main thread drops the `main_read_guard`. - /// let mut evil_guard = evil.write().unwrap(); + /// let mut evil_guard = rw_clone.write().unwrap(); /// - /// assert_eq!(*evil_guard, 1); - /// *evil_guard = 2; + /// assert_eq!(*evil_guard, 2); + /// *evil_guard = 3; /// }); /// - /// // After spawning the writer thread, set the inner value to 1. - /// *main_write_guard = 1; + /// *main_write_guard = 2; /// /// // Atomically downgrade the write guard into a read guard. /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); /// - /// // Since `downgrade` is atomic, the writer thread cannot have set the inner value to 2. - /// assert_eq!(*main_read_guard, 1, "`downgrade` was not atomic"); - /// - /// // Clean up everything now - /// drop(main_read_guard); - /// handle.join().unwrap(); - /// - /// let final_check = rw.read().unwrap(); - /// assert_eq!(*final_check, 2); + /// // Since `downgrade` is atomic, the writer thread cannot have changed the protected data. + /// assert_eq!(*main_read_guard, 2, "`downgrade` was not atomic"); + /// # + /// # drop(main_read_guard); + /// # evil_handle.join().unwrap(); + /// # + /// # let final_check = rw.read().unwrap(); + /// # assert_eq!(*final_check, 3); /// ``` #[stable(feature = "rwlock_downgrade", since = "CURRENT_RUSTC_VERSION")] pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> {