summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-08 01:20:56 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-08 01:20:56 +0000
commit9d273378b93f938af3f3c6a75e76d206ac62abc4 (patch)
treea2a322209580b9cd981a2e8cad86c37fa0ecdea0
parent79f3ae59497b278d20c5d316c7865a20de71951f (diff)
parente735ee64f5249ff65d2d3b1f58069864a9ad0df5 (diff)
downloadlock_api-simpleperf-release.tar.gz
Snap for 11421525 from e735ee64f5249ff65d2d3b1f58069864a9ad0df5 to simpleperf-releasesimpleperf-release
Change-Id: Ice4439abb6fba93091400fac046a536d259f7ea8
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp6
-rw-r--r--Cargo.toml13
-rw-r--r--Cargo.toml.orig9
-rw-r--r--METADATA25
-rw-r--r--src/lib.rs3
-rw-r--r--src/mutex.rs41
-rw-r--r--src/remutex.rs39
-rw-r--r--src/rwlock.rs387
9 files changed, 427 insertions, 98 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 6b5d531..73ab3ff 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "9e956adc2c6ecde7c15ff7611396d24be711c8a9"
+ "sha1": "8d92826bdcc8f7a507a2803ecbe5d98747f1df34"
},
"path_in_vcs": "lock_api"
} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 0cf269e..ef48f40 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,9 +42,13 @@ rust_library {
host_supported: true,
crate_name: "lock_api",
cargo_env_compat: true,
- cargo_pkg_version: "0.4.9",
+ cargo_pkg_version: "0.4.11",
srcs: ["src/lib.rs"],
edition: "2018",
+ features: [
+ "atomic_usize",
+ "default",
+ ],
cfgs: ["has_const_fn_trait_bound"],
rustlibs: ["libscopeguard"],
apex_available: [
diff --git a/Cargo.toml b/Cargo.toml
index b1ff8c4..501db6e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,8 +11,9 @@
[package]
edition = "2018"
+rust-version = "1.49.0"
name = "lock_api"
-version = "0.4.9"
+version = "0.4.11"
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
description = "Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std."
keywords = [
@@ -28,6 +29,14 @@ categories = [
license = "MIT OR Apache-2.0"
repository = "https://github.com/Amanieu/parking_lot"
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+ "--generate-link-to-definition",
+]
+
[dependencies.owning_ref]
version = "0.4.1"
optional = true
@@ -46,4 +55,6 @@ version = "1.1.0"
[features]
arc_lock = []
+atomic_usize = []
+default = ["atomic_usize"]
nightly = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index c21bd8a..683e69f 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "lock_api"
-version = "0.4.9"
+version = "0.4.11"
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
description = "Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std."
license = "MIT OR Apache-2.0"
@@ -8,6 +8,11 @@ repository = "https://github.com/Amanieu/parking_lot"
keywords = ["mutex", "rwlock", "lock", "no_std"]
categories = ["concurrency", "no-std"]
edition = "2018"
+rust-version = "1.49.0"
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]
[dependencies]
scopeguard = { version = "1.1.0", default-features = false }
@@ -22,5 +27,7 @@ serde = { version = "1.0.126", default-features = false, optional = true }
autocfg = "1.1.0"
[features]
+default = ["atomic_usize"]
nightly = []
arc_lock = []
+atomic_usize = []
diff --git a/METADATA b/METADATA
index e0c7e81..832bc1e 100644
--- a/METADATA
+++ b/METADATA
@@ -1,23 +1,20 @@
# This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update rust/crates/lock_api
-# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+# Usage: tools/external_updater/updater.sh update external/rust/crates/lock_api
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
name: "lock_api"
description: "Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std."
third_party {
- url {
- type: HOMEPAGE
- value: "https://crates.io/crates/lock_api"
- }
- url {
- type: ARCHIVE
- value: "https://static.crates.io/crates/lock_api/lock_api-0.4.9.crate"
- }
- version: "0.4.9"
license_type: NOTICE
last_upgrade_date {
- year: 2022
- month: 12
- day: 12
+ year: 2024
+ month: 2
+ day: 2
+ }
+ homepage: "https://crates.io/crates/lock_api"
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/lock_api/lock_api-0.4.11.crate"
+ version: "0.4.11"
}
}
diff --git a/src/lib.rs b/src/lib.rs
index cfa53bc..3ea417a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -86,6 +86,7 @@
//! requires the `alloc` crate to be present.
#![no_std]
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
@@ -106,7 +107,9 @@ unsafe impl Sync for GuardNoSend {}
mod mutex;
pub use crate::mutex::*;
+#[cfg(feature = "atomic_usize")]
mod remutex;
+#[cfg(feature = "atomic_usize")]
pub use crate::remutex::*;
mod rwlock;
diff --git a/src/mutex.rs b/src/mutex.rs
index c97e543..80eadfa 100644
--- a/src/mutex.rs
+++ b/src/mutex.rs
@@ -189,11 +189,16 @@ impl<R, T> Mutex<R, T> {
}
impl<R: RawMutex, T: ?Sized> Mutex<R, T> {
+ /// Creates a new `MutexGuard` without checking if the mutex is locked.
+ ///
/// # Safety
///
- /// The lock must be held when calling this method.
+ /// This method must only be called if the thread logically holds the lock.
+ ///
+ /// Calling this function when a guard has already been produced is undefined behaviour unless
+ /// the guard was forgotten with `mem::forget`.
#[inline]
- unsafe fn guard(&self) -> MutexGuard<'_, R, T> {
+ pub unsafe fn make_guard_unchecked(&self) -> MutexGuard<'_, R, T> {
MutexGuard {
mutex: self,
marker: PhantomData,
@@ -213,7 +218,7 @@ impl<R: RawMutex, T: ?Sized> Mutex<R, T> {
pub fn lock(&self) -> MutexGuard<'_, R, T> {
self.raw.lock();
// SAFETY: The lock is held, as required.
- unsafe { self.guard() }
+ unsafe { self.make_guard_unchecked() }
}
/// Attempts to acquire this lock.
@@ -227,7 +232,7 @@ impl<R: RawMutex, T: ?Sized> Mutex<R, T> {
pub fn try_lock(&self) -> Option<MutexGuard<'_, R, T>> {
if self.raw.try_lock() {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.guard() })
+ Some(unsafe { self.make_guard_unchecked() })
} else {
None
}
@@ -257,7 +262,7 @@ impl<R: RawMutex, T: ?Sized> Mutex<R, T> {
/// # Safety
///
/// This method must only be called if the current thread logically owns a
- /// `MutexGuard` but that guard has be discarded using `mem::forget`.
+ /// `MutexGuard` but that guard has been discarded using `mem::forget`.
/// Behavior is undefined if a mutex is unlocked when not locked.
#[inline]
pub unsafe fn force_unlock(&self) {
@@ -294,12 +299,17 @@ impl<R: RawMutex, T: ?Sized> Mutex<R, T> {
self.data.get()
}
+ /// Creates a new `ArcMutexGuard` without checking if the mutex is locked.
+ ///
/// # Safety
///
- /// The lock needs to be held for the behavior of this function to be defined.
+ /// This method must only be called if the thread logically holds the lock.
+ ///
+ /// Calling this function when a guard has already been produced is undefined behaviour unless
+ /// the guard was forgotten with `mem::forget`.
#[cfg(feature = "arc_lock")]
#[inline]
- unsafe fn guard_arc(self: &Arc<Self>) -> ArcMutexGuard<R, T> {
+ unsafe fn make_arc_guard_unchecked(self: &Arc<Self>) -> ArcMutexGuard<R, T> {
ArcMutexGuard {
mutex: self.clone(),
marker: PhantomData,
@@ -315,7 +325,7 @@ impl<R: RawMutex, T: ?Sized> Mutex<R, T> {
pub fn lock_arc(self: &Arc<Self>) -> ArcMutexGuard<R, T> {
self.raw.lock();
// SAFETY: the locking guarantee is upheld
- unsafe { self.guard_arc() }
+ unsafe { self.make_arc_guard_unchecked() }
}
/// Attempts to acquire a lock through an `Arc`.
@@ -327,7 +337,7 @@ impl<R: RawMutex, T: ?Sized> Mutex<R, T> {
pub fn try_lock_arc(self: &Arc<Self>) -> Option<ArcMutexGuard<R, T>> {
if self.raw.try_lock() {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.guard_arc() })
+ Some(unsafe { self.make_arc_guard_unchecked() })
} else {
None
}
@@ -344,7 +354,7 @@ impl<R: RawMutexFair, T: ?Sized> Mutex<R, T> {
/// # Safety
///
/// This method must only be called if the current thread logically owns a
- /// `MutexGuard` but that guard has be discarded using `mem::forget`.
+ /// `MutexGuard` but that guard has been discarded using `mem::forget`.
/// Behavior is undefined if a mutex is unlocked when not locked.
#[inline]
pub unsafe fn force_unlock_fair(&self) {
@@ -362,7 +372,7 @@ impl<R: RawMutexTimed, T: ?Sized> Mutex<R, T> {
pub fn try_lock_for(&self, timeout: R::Duration) -> Option<MutexGuard<'_, R, T>> {
if self.raw.try_lock_for(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.guard() })
+ Some(unsafe { self.make_guard_unchecked() })
} else {
None
}
@@ -377,7 +387,7 @@ impl<R: RawMutexTimed, T: ?Sized> Mutex<R, T> {
pub fn try_lock_until(&self, timeout: R::Instant) -> Option<MutexGuard<'_, R, T>> {
if self.raw.try_lock_until(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.guard() })
+ Some(unsafe { self.make_guard_unchecked() })
} else {
None
}
@@ -392,7 +402,7 @@ impl<R: RawMutexTimed, T: ?Sized> Mutex<R, T> {
pub fn try_lock_arc_for(self: &Arc<Self>, timeout: R::Duration) -> Option<ArcMutexGuard<R, T>> {
if self.raw.try_lock_for(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.guard_arc() })
+ Some(unsafe { self.make_arc_guard_unchecked() })
} else {
None
}
@@ -410,7 +420,7 @@ impl<R: RawMutexTimed, T: ?Sized> Mutex<R, T> {
) -> Option<ArcMutexGuard<R, T>> {
if self.raw.try_lock_until(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.guard_arc() })
+ Some(unsafe { self.make_arc_guard_unchecked() })
} else {
None
}
@@ -485,6 +495,7 @@ where
///
/// The data protected by the mutex can be accessed through this guard via its
/// `Deref` and `DerefMut` implementations.
+#[clippy::has_significant_drop]
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MutexGuard<'a, R: RawMutex, T: ?Sized> {
mutex: &'a Mutex<R, T>,
@@ -678,6 +689,7 @@ unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MutexGuard<'
/// This is similar to the `MutexGuard` struct, except instead of using a reference to unlock the `Mutex` it
/// uses an `Arc<Mutex>`. This has several advantages, most notably that it has an `'static` lifetime.
#[cfg(feature = "arc_lock")]
+#[clippy::has_significant_drop]
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct ArcMutexGuard<R: RawMutex, T: ?Sized> {
mutex: Arc<Mutex<R, T>>,
@@ -813,6 +825,7 @@ impl<R: RawMutex, T: ?Sized> Drop for ArcMutexGuard<R, T> {
/// former doesn't support temporarily unlocking and re-locking, since that
/// could introduce soundness issues if the locked object is modified by another
/// thread.
+#[clippy::has_significant_drop]
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MappedMutexGuard<'a, R: RawMutex, T: ?Sized> {
raw: &'a R,
diff --git a/src/remutex.rs b/src/remutex.rs
index 3e2010f..74f2da3 100644
--- a/src/remutex.rs
+++ b/src/remutex.rs
@@ -183,8 +183,10 @@ impl<R: RawMutexFair, G: GetThreadId> RawReentrantMutex<R, G> {
if self.lock_count.get() == 1 {
let id = self.owner.load(Ordering::Relaxed);
self.owner.store(0, Ordering::Relaxed);
+ self.lock_count.set(0);
self.mutex.bump();
self.owner.store(id, Ordering::Relaxed);
+ self.lock_count.set(1);
}
}
}
@@ -287,11 +289,16 @@ impl<R, G, T> ReentrantMutex<R, G, T> {
}
impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
+ /// Creates a new `ReentrantMutexGuard` without checking if the lock is held.
+ ///
/// # Safety
///
- /// The lock must be held when calling this method.
+ /// This method must only be called if the thread logically holds the lock.
+ ///
+ /// Calling this function when a guard has already been produced is undefined behaviour unless
+ /// the guard was forgotten with `mem::forget`.
#[inline]
- unsafe fn guard(&self) -> ReentrantMutexGuard<'_, R, G, T> {
+ pub unsafe fn make_guard_unchecked(&self) -> ReentrantMutexGuard<'_, R, G, T> {
ReentrantMutexGuard {
remutex: &self,
marker: PhantomData,
@@ -312,7 +319,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
pub fn lock(&self) -> ReentrantMutexGuard<'_, R, G, T> {
self.raw.lock();
// SAFETY: The lock is held, as required.
- unsafe { self.guard() }
+ unsafe { self.make_guard_unchecked() }
}
/// Attempts to acquire this lock.
@@ -326,7 +333,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, R, G, T>> {
if self.raw.try_lock() {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.guard() })
+ Some(unsafe { self.make_guard_unchecked() })
} else {
None
}
@@ -400,12 +407,17 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
self.data.get()
}
+ /// Creates a new `ArcReentrantMutexGuard` without checking if the lock is held.
+ ///
/// # Safety
///
- /// The lock must be held before calling this method.
+ /// This method must only be called if the thread logically holds the lock.
+ ///
+ /// Calling this function when a guard has already been produced is undefined behaviour unless
+ /// the guard was forgotten with `mem::forget`.
#[cfg(feature = "arc_lock")]
#[inline]
- unsafe fn guard_arc(self: &Arc<Self>) -> ArcReentrantMutexGuard<R, G, T> {
+ pub unsafe fn make_arc_guard_unchecked(self: &Arc<Self>) -> ArcReentrantMutexGuard<R, G, T> {
ArcReentrantMutexGuard {
remutex: self.clone(),
marker: PhantomData,
@@ -421,7 +433,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
pub fn lock_arc(self: &Arc<Self>) -> ArcReentrantMutexGuard<R, G, T> {
self.raw.lock();
// SAFETY: locking guarantee is upheld
- unsafe { self.guard_arc() }
+ unsafe { self.make_arc_guard_unchecked() }
}
/// Attempts to acquire a reentrant mutex through an `Arc`.
@@ -433,7 +445,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
pub fn try_lock_arc(self: &Arc<Self>) -> Option<ArcReentrantMutexGuard<R, G, T>> {
if self.raw.try_lock() {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.guard_arc() })
+ Some(unsafe { self.make_arc_guard_unchecked() })
} else {
None
}
@@ -468,7 +480,7 @@ impl<R: RawMutexTimed, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
pub fn try_lock_for(&self, timeout: R::Duration) -> Option<ReentrantMutexGuard<'_, R, G, T>> {
if self.raw.try_lock_for(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.guard() })
+ Some(unsafe { self.make_guard_unchecked() })
} else {
None
}
@@ -483,7 +495,7 @@ impl<R: RawMutexTimed, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
pub fn try_lock_until(&self, timeout: R::Instant) -> Option<ReentrantMutexGuard<'_, R, G, T>> {
if self.raw.try_lock_until(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.guard() })
+ Some(unsafe { self.make_guard_unchecked() })
} else {
None
}
@@ -501,7 +513,7 @@ impl<R: RawMutexTimed, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
) -> Option<ArcReentrantMutexGuard<R, G, T>> {
if self.raw.try_lock_for(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.guard_arc() })
+ Some(unsafe { self.make_arc_guard_unchecked() })
} else {
None
}
@@ -519,7 +531,7 @@ impl<R: RawMutexTimed, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
) -> Option<ArcReentrantMutexGuard<R, G, T>> {
if self.raw.try_lock_until(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.guard_arc() })
+ Some(unsafe { self.make_arc_guard_unchecked() })
} else {
None
}
@@ -599,6 +611,7 @@ where
///
/// The data protected by the mutex can be accessed through this guard via its
/// `Deref` implementation.
+#[clippy::has_significant_drop]
#[must_use = "if unused the ReentrantMutex will immediately unlock"]
pub struct ReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized> {
remutex: &'a ReentrantMutex<R, G, T>,
@@ -794,6 +807,7 @@ unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAdd
/// `Mutex` it uses an `Arc<ReentrantMutex>`. This has several advantages, most notably that it has an `'static`
/// lifetime.
#[cfg(feature = "arc_lock")]
+#[clippy::has_significant_drop]
#[must_use = "if unused the ReentrantMutex will immediately unlock"]
pub struct ArcReentrantMutexGuard<R: RawMutex, G: GetThreadId, T: ?Sized> {
remutex: Arc<ReentrantMutex<R, G, T>>,
@@ -897,6 +911,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> Drop for ArcReentrantMutexGuard<R,
/// former doesn't support temporarily unlocking and re-locking, since that
/// could introduce soundness issues if the locked object is modified by another
/// thread.
+#[clippy::has_significant_drop]
#[must_use = "if unused the ReentrantMutex will immediately unlock"]
pub struct MappedReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized> {
raw: &'a RawReentrantMutex<R, G>,
diff --git a/src/rwlock.rs b/src/rwlock.rs
index c972fb6..cf9e8aa 100644
--- a/src/rwlock.rs
+++ b/src/rwlock.rs
@@ -409,22 +409,33 @@ impl<R, T> RwLock<R, T> {
}
impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
+ /// Creates a new `RwLockReadGuard` without checking if the lock is held.
+ ///
/// # Safety
///
- /// The lock must be held when calling this method.
+ /// This method must only be called if the thread logically holds a read lock.
+ ///
+ /// This function does not increment the read count of the lock. Calling this function when a
+ /// guard has already been produced is undefined behaviour unless the guard was forgotten
+ /// with `mem::forget`.`
#[inline]
- unsafe fn read_guard(&self) -> RwLockReadGuard<'_, R, T> {
+ pub unsafe fn make_read_guard_unchecked(&self) -> RwLockReadGuard<'_, R, T> {
RwLockReadGuard {
rwlock: self,
marker: PhantomData,
}
}
+ /// Creates a new `RwLockReadGuard` without checking if the lock is held.
+ ///
/// # Safety
///
- /// The lock must be held when calling this method.
+ /// This method must only be called if the thread logically holds a write lock.
+ ///
+ /// Calling this function when a guard has already been produced is undefined behaviour unless
+ /// the guard was forgotten with `mem::forget`.
#[inline]
- unsafe fn write_guard(&self) -> RwLockWriteGuard<'_, R, T> {
+ pub unsafe fn make_write_guard_unchecked(&self) -> RwLockWriteGuard<'_, R, T> {
RwLockWriteGuard {
rwlock: self,
marker: PhantomData,
@@ -447,7 +458,7 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
pub fn read(&self) -> RwLockReadGuard<'_, R, T> {
self.raw.lock_shared();
// SAFETY: The lock is held, as required.
- unsafe { self.read_guard() }
+ unsafe { self.make_read_guard_unchecked() }
}
/// Attempts to acquire this `RwLock` with shared read access.
@@ -461,7 +472,7 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
pub fn try_read(&self) -> Option<RwLockReadGuard<'_, R, T>> {
if self.raw.try_lock_shared() {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.read_guard() })
+ Some(unsafe { self.make_read_guard_unchecked() })
} else {
None
}
@@ -479,7 +490,7 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
pub fn write(&self) -> RwLockWriteGuard<'_, R, T> {
self.raw.lock_exclusive();
// SAFETY: The lock is held, as required.
- unsafe { self.write_guard() }
+ unsafe { self.make_write_guard_unchecked() }
}
/// Attempts to lock this `RwLock` with exclusive write access.
@@ -493,7 +504,7 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, R, T>> {
if self.raw.try_lock_exclusive() {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.write_guard() })
+ Some(unsafe { self.make_write_guard_unchecked() })
} else {
None
}
@@ -583,24 +594,35 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
self.data.get()
}
+ /// Creates a new `RwLockReadGuard` without checking if the lock is held.
+ ///
/// # Safety
///
- /// The lock must be held when calling this method.
+ /// This method must only be called if the thread logically holds a read lock.
+ ///
+ /// This function does not increment the read count of the lock. Calling this function when a
+ /// guard has already been produced is undefined behaviour unless the guard was forgotten
+ /// with `mem::forget`.`
#[cfg(feature = "arc_lock")]
#[inline]
- unsafe fn read_guard_arc(self: &Arc<Self>) -> ArcRwLockReadGuard<R, T> {
+ pub unsafe fn make_arc_read_guard_unchecked(self: &Arc<Self>) -> ArcRwLockReadGuard<R, T> {
ArcRwLockReadGuard {
rwlock: self.clone(),
marker: PhantomData,
}
}
+ /// Creates a new `RwLockWriteGuard` without checking if the lock is held.
+ ///
/// # Safety
///
- /// The lock must be held when calling this method.
+ /// This method must only be called if the thread logically holds a write lock.
+ ///
+ /// Calling this function when a guard has already been produced is undefined behaviour unless
+ /// the guard was forgotten with `mem::forget`.
#[cfg(feature = "arc_lock")]
#[inline]
- unsafe fn write_guard_arc(self: &Arc<Self>) -> ArcRwLockWriteGuard<R, T> {
+ pub unsafe fn make_arc_write_guard_unchecked(self: &Arc<Self>) -> ArcRwLockWriteGuard<R, T> {
ArcRwLockWriteGuard {
rwlock: self.clone(),
marker: PhantomData,
@@ -616,7 +638,7 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
pub fn read_arc(self: &Arc<Self>) -> ArcRwLockReadGuard<R, T> {
self.raw.lock_shared();
// SAFETY: locking guarantee is upheld
- unsafe { self.read_guard_arc() }
+ unsafe { self.make_arc_read_guard_unchecked() }
}
/// Attempts to lock this `RwLock` with read access, through an `Arc`.
@@ -628,7 +650,7 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
pub fn try_read_arc(self: &Arc<Self>) -> Option<ArcRwLockReadGuard<R, T>> {
if self.raw.try_lock_shared() {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.read_guard_arc() })
+ Some(unsafe { self.make_arc_read_guard_unchecked() })
} else {
None
}
@@ -643,7 +665,7 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
pub fn write_arc(self: &Arc<Self>) -> ArcRwLockWriteGuard<R, T> {
self.raw.lock_exclusive();
// SAFETY: locking guarantee is upheld
- unsafe { self.write_guard_arc() }
+ unsafe { self.make_arc_write_guard_unchecked() }
}
/// Attempts to lock this `RwLock` with writ access, through an `Arc`.
@@ -655,7 +677,7 @@ impl<R: RawRwLock, T: ?Sized> RwLock<R, T> {
pub fn try_write_arc(self: &Arc<Self>) -> Option<ArcRwLockWriteGuard<R, T>> {
if self.raw.try_lock_exclusive() {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.write_guard_arc() })
+ Some(unsafe { self.make_arc_write_guard_unchecked() })
} else {
None
}
@@ -707,7 +729,7 @@ impl<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> {
pub fn try_read_for(&self, timeout: R::Duration) -> Option<RwLockReadGuard<'_, R, T>> {
if self.raw.try_lock_shared_for(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.read_guard() })
+ Some(unsafe { self.make_read_guard_unchecked() })
} else {
None
}
@@ -723,7 +745,7 @@ impl<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> {
pub fn try_read_until(&self, timeout: R::Instant) -> Option<RwLockReadGuard<'_, R, T>> {
if self.raw.try_lock_shared_until(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.read_guard() })
+ Some(unsafe { self.make_read_guard_unchecked() })
} else {
None
}
@@ -739,7 +761,7 @@ impl<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> {
pub fn try_write_for(&self, timeout: R::Duration) -> Option<RwLockWriteGuard<'_, R, T>> {
if self.raw.try_lock_exclusive_for(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.write_guard() })
+ Some(unsafe { self.make_write_guard_unchecked() })
} else {
None
}
@@ -755,7 +777,7 @@ impl<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> {
pub fn try_write_until(&self, timeout: R::Instant) -> Option<RwLockWriteGuard<'_, R, T>> {
if self.raw.try_lock_exclusive_until(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.write_guard() })
+ Some(unsafe { self.make_write_guard_unchecked() })
} else {
None
}
@@ -773,7 +795,7 @@ impl<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> {
) -> Option<ArcRwLockReadGuard<R, T>> {
if self.raw.try_lock_shared_for(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.read_guard_arc() })
+ Some(unsafe { self.make_arc_read_guard_unchecked() })
} else {
None
}
@@ -791,7 +813,7 @@ impl<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> {
) -> Option<ArcRwLockReadGuard<R, T>> {
if self.raw.try_lock_shared_until(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.read_guard_arc() })
+ Some(unsafe { self.make_arc_read_guard_unchecked() })
} else {
None
}
@@ -809,7 +831,7 @@ impl<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> {
) -> Option<ArcRwLockWriteGuard<R, T>> {
if self.raw.try_lock_exclusive_for(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.write_guard_arc() })
+ Some(unsafe { self.make_arc_write_guard_unchecked() })
} else {
None
}
@@ -827,7 +849,7 @@ impl<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> {
) -> Option<ArcRwLockWriteGuard<R, T>> {
if self.raw.try_lock_exclusive_until(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.write_guard_arc() })
+ Some(unsafe { self.make_arc_write_guard_unchecked() })
} else {
None
}
@@ -854,7 +876,7 @@ impl<R: RawRwLockRecursive, T: ?Sized> RwLock<R, T> {
pub fn read_recursive(&self) -> RwLockReadGuard<'_, R, T> {
self.raw.lock_shared_recursive();
// SAFETY: The lock is held, as required.
- unsafe { self.read_guard() }
+ unsafe { self.make_read_guard_unchecked() }
}
/// Attempts to acquire this `RwLock` with shared read access.
@@ -871,7 +893,7 @@ impl<R: RawRwLockRecursive, T: ?Sized> RwLock<R, T> {
pub fn try_read_recursive(&self) -> Option<RwLockReadGuard<'_, R, T>> {
if self.raw.try_lock_shared_recursive() {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.read_guard() })
+ Some(unsafe { self.make_read_guard_unchecked() })
} else {
None
}
@@ -886,7 +908,7 @@ impl<R: RawRwLockRecursive, T: ?Sized> RwLock<R, T> {
pub fn read_arc_recursive(self: &Arc<Self>) -> ArcRwLockReadGuard<R, T> {
self.raw.lock_shared_recursive();
// SAFETY: locking guarantee is upheld
- unsafe { self.read_guard_arc() }
+ unsafe { self.make_arc_read_guard_unchecked() }
}
/// Attempts to lock this `RwLock` with shared read access, through an `Arc`.
@@ -898,7 +920,7 @@ impl<R: RawRwLockRecursive, T: ?Sized> RwLock<R, T> {
pub fn try_read_recursive_arc(self: &Arc<Self>) -> Option<ArcRwLockReadGuard<R, T>> {
if self.raw.try_lock_shared_recursive() {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.read_guard_arc() })
+ Some(unsafe { self.make_arc_read_guard_unchecked() })
} else {
None
}
@@ -923,7 +945,7 @@ impl<R: RawRwLockRecursiveTimed, T: ?Sized> RwLock<R, T> {
) -> Option<RwLockReadGuard<'_, R, T>> {
if self.raw.try_lock_shared_recursive_for(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.read_guard() })
+ Some(unsafe { self.make_read_guard_unchecked() })
} else {
None
}
@@ -942,7 +964,7 @@ impl<R: RawRwLockRecursiveTimed, T: ?Sized> RwLock<R, T> {
) -> Option<RwLockReadGuard<'_, R, T>> {
if self.raw.try_lock_shared_recursive_until(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.read_guard() })
+ Some(unsafe { self.make_read_guard_unchecked() })
} else {
None
}
@@ -960,7 +982,7 @@ impl<R: RawRwLockRecursiveTimed, T: ?Sized> RwLock<R, T> {
) -> Option<ArcRwLockReadGuard<R, T>> {
if self.raw.try_lock_shared_recursive_for(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.read_guard_arc() })
+ Some(unsafe { self.make_arc_read_guard_unchecked() })
} else {
None
}
@@ -978,7 +1000,7 @@ impl<R: RawRwLockRecursiveTimed, T: ?Sized> RwLock<R, T> {
) -> Option<ArcRwLockReadGuard<R, T>> {
if self.raw.try_lock_shared_recursive_until(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.read_guard_arc() })
+ Some(unsafe { self.make_arc_read_guard_unchecked() })
} else {
None
}
@@ -986,11 +1008,17 @@ impl<R: RawRwLockRecursiveTimed, T: ?Sized> RwLock<R, T> {
}
impl<R: RawRwLockUpgrade, T: ?Sized> RwLock<R, T> {
+ /// Creates a new `RwLockUpgradableReadGuard` without checking if the lock is held.
+ ///
/// # Safety
///
- /// The lock must be held when calling this method.
+ /// This method must only be called if the thread logically holds an upgradable read lock.
+ ///
+ /// This function does not increment the read count of the lock. Calling this function when a
+ /// guard has already been produced is undefined behaviour unless the guard was forgotten
+ /// with `mem::forget`.`
#[inline]
- unsafe fn upgradable_guard(&self) -> RwLockUpgradableReadGuard<'_, R, T> {
+ pub unsafe fn make_upgradable_guard_unchecked(&self) -> RwLockUpgradableReadGuard<'_, R, T> {
RwLockUpgradableReadGuard {
rwlock: self,
marker: PhantomData,
@@ -1010,7 +1038,7 @@ impl<R: RawRwLockUpgrade, T: ?Sized> RwLock<R, T> {
pub fn upgradable_read(&self) -> RwLockUpgradableReadGuard<'_, R, T> {
self.raw.lock_upgradable();
// SAFETY: The lock is held, as required.
- unsafe { self.upgradable_guard() }
+ unsafe { self.make_upgradable_guard_unchecked() }
}
/// Attempts to acquire this `RwLock` with upgradable read access.
@@ -1024,18 +1052,26 @@ impl<R: RawRwLockUpgrade, T: ?Sized> RwLock<R, T> {
pub fn try_upgradable_read(&self) -> Option<RwLockUpgradableReadGuard<'_, R, T>> {
if self.raw.try_lock_upgradable() {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.upgradable_guard() })
+ Some(unsafe { self.make_upgradable_guard_unchecked() })
} else {
None
}
}
+ /// Creates a new `ArcRwLockUpgradableReadGuard` without checking if the lock is held.
+ ///
/// # Safety
///
- /// The lock must be held when calling this method.
+ /// This method must only be called if the thread logically holds an upgradable read lock.
+ ///
+ /// This function does not increment the read count of the lock. Calling this function when a
+ /// guard has already been produced is undefined behaviour unless the guard was forgotten
+ /// with `mem::forget`.`
#[cfg(feature = "arc_lock")]
#[inline]
- unsafe fn upgradable_guard_arc(self: &Arc<Self>) -> ArcRwLockUpgradableReadGuard<R, T> {
+ pub unsafe fn make_upgradable_arc_guard_unchecked(
+ self: &Arc<Self>,
+ ) -> ArcRwLockUpgradableReadGuard<R, T> {
ArcRwLockUpgradableReadGuard {
rwlock: self.clone(),
marker: PhantomData,
@@ -1051,7 +1087,7 @@ impl<R: RawRwLockUpgrade, T: ?Sized> RwLock<R, T> {
pub fn upgradable_read_arc(self: &Arc<Self>) -> ArcRwLockUpgradableReadGuard<R, T> {
self.raw.lock_upgradable();
// SAFETY: locking guarantee is upheld
- unsafe { self.upgradable_guard_arc() }
+ unsafe { self.make_upgradable_arc_guard_unchecked() }
}
/// Attempts to lock this `RwLock` with upgradable read access, through an `Arc`.
@@ -1063,7 +1099,7 @@ impl<R: RawRwLockUpgrade, T: ?Sized> RwLock<R, T> {
pub fn try_upgradable_read_arc(self: &Arc<Self>) -> Option<ArcRwLockUpgradableReadGuard<R, T>> {
if self.raw.try_lock_upgradable() {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.upgradable_guard_arc() })
+ Some(unsafe { self.make_upgradable_arc_guard_unchecked() })
} else {
None
}
@@ -1084,7 +1120,7 @@ impl<R: RawRwLockUpgradeTimed, T: ?Sized> RwLock<R, T> {
) -> Option<RwLockUpgradableReadGuard<'_, R, T>> {
if self.raw.try_lock_upgradable_for(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.upgradable_guard() })
+ Some(unsafe { self.make_upgradable_guard_unchecked() })
} else {
None
}
@@ -1103,7 +1139,7 @@ impl<R: RawRwLockUpgradeTimed, T: ?Sized> RwLock<R, T> {
) -> Option<RwLockUpgradableReadGuard<'_, R, T>> {
if self.raw.try_lock_upgradable_until(timeout) {
// SAFETY: The lock is held, as required.
- Some(unsafe { self.upgradable_guard() })
+ Some(unsafe { self.make_upgradable_guard_unchecked() })
} else {
None
}
@@ -1121,7 +1157,7 @@ impl<R: RawRwLockUpgradeTimed, T: ?Sized> RwLock<R, T> {
) -> Option<ArcRwLockUpgradableReadGuard<R, T>> {
if self.raw.try_lock_upgradable_for(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.upgradable_guard_arc() })
+ Some(unsafe { self.make_upgradable_arc_guard_unchecked() })
} else {
None
}
@@ -1139,7 +1175,7 @@ impl<R: RawRwLockUpgradeTimed, T: ?Sized> RwLock<R, T> {
) -> Option<ArcRwLockUpgradableReadGuard<R, T>> {
if self.raw.try_lock_upgradable_until(timeout) {
// SAFETY: locking guarantee is upheld
- Some(unsafe { self.upgradable_guard_arc() })
+ Some(unsafe { self.make_upgradable_arc_guard_unchecked() })
} else {
None
}
@@ -1182,12 +1218,15 @@ impl<R: RawRwLock, T: ?Sized + fmt::Debug> fmt::Debug for RwLock<R, T> {
/// RAII structure used to release the shared read access of a lock when
/// dropped.
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct RwLockReadGuard<'a, R: RawRwLock, T: ?Sized> {
rwlock: &'a RwLock<R, T>,
marker: PhantomData<(&'a T, R::GuardMarker)>,
}
+unsafe impl<R: RawRwLock + Sync, T: Sync + ?Sized> Sync for RwLockReadGuard<'_, R, T> {}
+
impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> RwLockReadGuard<'a, R, T> {
/// Returns a reference to the original reader-writer lock object.
pub fn rwlock(s: &Self) -> &'a RwLock<R, T> {
@@ -1246,8 +1285,6 @@ impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> RwLockReadGuard<'a, R, T> {
/// Temporarily unlocks the `RwLock` to execute the given function.
///
- /// The `RwLock` is unlocked a fair unlock protocol.
- ///
/// This is safe because `&mut` guarantees that there exist no other
/// references to the data protected by the `RwLock`.
#[inline]
@@ -1359,6 +1396,7 @@ unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockReadG
/// This is similar to the `RwLockReadGuard` struct, except instead of using a reference to unlock the `RwLock`
/// it uses an `Arc<RwLock>`. This has several advantages, most notably that it has an `'static` lifetime.
#[cfg(feature = "arc_lock")]
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct ArcRwLockReadGuard<R: RawRwLock, T: ?Sized> {
rwlock: Arc<RwLock<R, T>>,
@@ -1470,12 +1508,15 @@ impl<R: RawRwLock, T: fmt::Display + ?Sized> fmt::Display for ArcRwLockReadGuard
/// RAII structure used to release the exclusive write access of a lock when
/// dropped.
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct RwLockWriteGuard<'a, R: RawRwLock, T: ?Sized> {
rwlock: &'a RwLock<R, T>,
marker: PhantomData<(&'a mut T, R::GuardMarker)>,
}
+unsafe impl<R: RawRwLock + Sync, T: Sync + ?Sized> Sync for RwLockWriteGuard<'_, R, T> {}
+
impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> RwLockWriteGuard<'a, R, T> {
/// Returns a reference to the original reader-writer lock object.
pub fn rwlock(s: &Self) -> &'a RwLock<R, T> {
@@ -1693,6 +1734,7 @@ unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockWrite
/// This is similar to the `RwLockWriteGuard` struct, except instead of using a reference to unlock the `RwLock`
/// it uses an `Arc<RwLock>`. This has several advantages, most notably that it has an `'static` lifetime.
#[cfg(feature = "arc_lock")]
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct ArcRwLockWriteGuard<R: RawRwLock, T: ?Sized> {
rwlock: Arc<RwLock<R, T>>,
@@ -1858,6 +1900,7 @@ impl<R: RawRwLock, T: fmt::Display + ?Sized> fmt::Display for ArcRwLockWriteGuar
/// RAII structure used to release the upgradable read access of a lock when
/// dropped.
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct RwLockUpgradableReadGuard<'a, R: RawRwLockUpgrade, T: ?Sized> {
rwlock: &'a RwLock<R, T>,
@@ -1892,7 +1935,7 @@ impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a,
f()
}
- /// Atomically upgrades an upgradable read lock lock into a exclusive write lock,
+ /// Atomically upgrades an upgradable read lock lock into an exclusive write lock,
/// blocking the current thread until it can be acquired.
pub fn upgrade(s: Self) -> RwLockWriteGuard<'a, R, T> {
// Safety: An RwLockUpgradableReadGuard always holds an upgradable lock.
@@ -1907,7 +1950,7 @@ impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a,
}
}
- /// Tries to atomically upgrade an upgradable read lock into a exclusive write lock.
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive write lock.
///
/// If the access could not be granted at this time, then the current guard is returned.
pub fn try_upgrade(s: Self) -> Result<RwLockWriteGuard<'a, R, T>, Self> {
@@ -2000,10 +2043,60 @@ impl<'a, R: RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a> RwLockUpgradableRead
marker: PhantomData,
}
}
+
+ /// First, atomically upgrades an upgradable read lock lock into an exclusive write lock,
+ /// blocking the current thread until it can be acquired.
+ ///
+ /// Then, calls the provided closure with an exclusive reference to the lock's data.
+ ///
+ /// Finally, atomically downgrades the lock back to an upgradable read lock.
+ /// The closure's return value is wrapped in `Some` and returned.
+ ///
+ /// This function only requires a mutable reference to the guard, unlike
+ /// `upgrade` which takes the guard by value.
+ pub fn with_upgraded<Ret, F: FnOnce(&mut T) -> Ret>(&mut self, f: F) -> Ret {
+ unsafe {
+ self.rwlock.raw.upgrade();
+ }
+
+ // Safety: We just upgraded the lock, so we have mutable access to the data.
+ // This will restore the state the lock was in at the start of the function.
+ defer!(unsafe { self.rwlock.raw.downgrade_to_upgradable() });
+
+ // Safety: We upgraded the lock, so we have mutable access to the data.
+ // When this function returns, whether by drop or panic,
+ // the drop guard will downgrade it back to an upgradeable lock.
+ f(unsafe { &mut *self.rwlock.data.get() })
+ }
+
+ /// First, tries to atomically upgrade an upgradable read lock into an exclusive write lock.
+ ///
+ /// If the access could not be granted at this time, then `None` is returned.
+ ///
+ /// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
+ /// and finally downgrades the lock back to an upgradable read lock.
+ /// The closure's return value is wrapped in `Some` and returned.
+ ///
+ /// This function only requires a mutable reference to the guard, unlike
+ /// `try_upgrade` which takes the guard by value.
+ pub fn try_with_upgraded<Ret, F: FnOnce(&mut T) -> Ret>(&mut self, f: F) -> Option<Ret> {
+ if unsafe { self.rwlock.raw.try_upgrade() } {
+ // Safety: We just upgraded the lock, so we have mutable access to the data.
+ // This will restore the state the lock was in at the start of the function.
+ defer!(unsafe { self.rwlock.raw.downgrade_to_upgradable() });
+
+ // Safety: We upgraded the lock, so we have mutable access to the data.
+ // When this function returns, whether by drop or panic,
+ // the drop guard will downgrade it back to an upgradeable lock.
+ Some(f(unsafe { &mut *self.rwlock.data.get() }))
+ } else {
+ None
+ }
+ }
}
impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, R, T> {
- /// Tries to atomically upgrade an upgradable read lock into a exclusive
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive
/// write lock, until a timeout is reached.
///
/// If the access could not be granted before the timeout expires, then
@@ -2025,7 +2118,7 @@ impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuar
}
}
- /// Tries to atomically upgrade an upgradable read lock into a exclusive
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive
/// write lock, until a timeout is reached.
///
/// If the access could not be granted before the timeout expires, then
@@ -2049,6 +2142,72 @@ impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuar
}
}
+impl<'a, R: RawRwLockUpgradeTimed + RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a>
+ RwLockUpgradableReadGuard<'a, R, T>
+{
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive
+ /// write lock, until a timeout is reached.
+ ///
+ /// If the access could not be granted before the timeout expires, then
+ /// `None` is returned.
+ ///
+ /// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
+ /// and finally downgrades the lock back to an upgradable read lock.
+ /// The closure's return value is wrapped in `Some` and returned.
+ ///
+ /// This function only requires a mutable reference to the guard, unlike
+ /// `try_upgrade_for` which takes the guard by value.
+ pub fn try_with_upgraded_for<Ret, F: FnOnce(&mut T) -> Ret>(
+ &mut self,
+ timeout: R::Duration,
+ f: F,
+ ) -> Option<Ret> {
+ if unsafe { self.rwlock.raw.try_upgrade_for(timeout) } {
+ // Safety: We just upgraded the lock, so we have mutable access to the data.
+ // This will restore the state the lock was in at the start of the function.
+ defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
+
+ // Safety: We upgraded the lock, so we have mutable access to the data.
+ // When this function returns, whether by drop or panic,
+ // the drop guard will downgrade it back to an upgradeable lock.
+ Some(f(unsafe { &mut *self.rwlock.data.get() }))
+ } else {
+ None
+ }
+ }
+
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive
+ /// write lock, until a timeout is reached.
+ ///
+ /// If the access could not be granted before the timeout expires, then
+ /// `None` is returned.
+ ///
+ /// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
+ /// and finally downgrades the lock back to an upgradable read lock.
+ /// The closure's return value is wrapped in `Some` and returned.
+ ///
+ /// This function only requires a mutable reference to the guard, unlike
+ /// `try_upgrade_until` which takes the guard by value.
+ pub fn try_with_upgraded_until<Ret, F: FnOnce(&mut T) -> Ret>(
+ &mut self,
+ timeout: R::Instant,
+ f: F,
+ ) -> Option<Ret> {
+ if unsafe { self.rwlock.raw.try_upgrade_until(timeout) } {
+ // Safety: We just upgraded the lock, so we have mutable access to the data.
+ // This will restore the state the lock was in at the start of the function.
+ defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
+
+ // Safety: We upgraded the lock, so we have mutable access to the data.
+ // When this function returns, whether by drop or panic,
+ // the drop guard will downgrade it back to an upgradeable lock.
+ Some(f(unsafe { &mut *self.rwlock.data.get() }))
+ } else {
+ None
+ }
+ }
+}
+
impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> Deref for RwLockUpgradableReadGuard<'a, R, T> {
type Target = T;
#[inline]
@@ -2094,6 +2253,7 @@ unsafe impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> StableAddress
/// `RwLock` it uses an `Arc<RwLock>`. This has several advantages, most notably that it has an `'static`
/// lifetime.
#[cfg(feature = "arc_lock")]
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct ArcRwLockUpgradableReadGuard<R: RawRwLockUpgrade, T: ?Sized> {
rwlock: Arc<RwLock<R, T>>,
@@ -2123,7 +2283,7 @@ impl<R: RawRwLockUpgrade, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
f()
}
- /// Atomically upgrades an upgradable read lock lock into a exclusive write lock,
+ /// Atomically upgrades an upgradable read lock lock into an exclusive write lock,
/// blocking the current thread until it can be acquired.
pub fn upgrade(s: Self) -> ArcRwLockWriteGuard<R, T> {
// Safety: An RwLockUpgradableReadGuard always holds an upgradable lock.
@@ -2142,7 +2302,7 @@ impl<R: RawRwLockUpgrade, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
}
}
- /// Tries to atomically upgrade an upgradable read lock into a exclusive write lock.
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive write lock.
///
/// If the access could not be granted at this time, then the current guard is returned.
pub fn try_upgrade(s: Self) -> Result<ArcRwLockWriteGuard<R, T>, Self> {
@@ -2231,11 +2391,61 @@ impl<R: RawRwLockUpgradeDowngrade, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T>
marker: PhantomData,
}
}
+
+ /// First, atomically upgrades an upgradable read lock lock into an exclusive write lock,
+ /// blocking the current thread until it can be acquired.
+ ///
+ /// Then, calls the provided closure with an exclusive reference to the lock's data.
+ ///
+ /// Finally, atomically downgrades the lock back to an upgradable read lock.
+ /// The closure's return value is returned.
+ ///
+ /// This function only requires a mutable reference to the guard, unlike
+ /// `upgrade` which takes the guard by value.
+ pub fn with_upgraded<Ret, F: FnOnce(&mut T) -> Ret>(&mut self, f: F) -> Ret {
+ unsafe {
+ self.rwlock.raw.upgrade();
+ }
+
+ // Safety: We just upgraded the lock, so we have mutable access to the data.
+ // This will restore the state the lock was in at the start of the function.
+ defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
+
+ // Safety: We upgraded the lock, so we have mutable access to the data.
+ // When this function returns, whether by drop or panic,
+ // the drop guard will downgrade it back to an upgradeable lock.
+ f(unsafe { &mut *self.rwlock.data.get() })
+ }
+
+ /// First, tries to atomically upgrade an upgradable read lock into an exclusive write lock.
+ ///
+ /// If the access could not be granted at this time, then `None` is returned.
+ ///
+ /// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
+ /// and finally downgrades the lock back to an upgradable read lock.
+ /// The closure's return value is wrapped in `Some` and returned.
+ ///
+ /// This function only requires a mutable reference to the guard, unlike
+ /// `try_upgrade` which takes the guard by value.
+ pub fn try_with_upgraded<Ret, F: FnOnce(&mut T) -> Ret>(&mut self, f: F) -> Option<Ret> {
+ if unsafe { self.rwlock.raw.try_upgrade() } {
+ // Safety: We just upgraded the lock, so we have mutable access to the data.
+ // This will restore the state the lock was in at the start of the function.
+ defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
+
+ // Safety: We upgraded the lock, so we have mutable access to the data.
+ // When this function returns, whether by drop or panic,
+ // the drop guard will downgrade it back to an upgradeable lock.
+ Some(f(unsafe { &mut *self.rwlock.data.get() }))
+ } else {
+ None
+ }
+ }
}
#[cfg(feature = "arc_lock")]
impl<R: RawRwLockUpgradeTimed, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
- /// Tries to atomically upgrade an upgradable read lock into a exclusive
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive
/// write lock, until a timeout is reached.
///
/// If the access could not be granted before the timeout expires, then
@@ -2259,7 +2469,7 @@ impl<R: RawRwLockUpgradeTimed, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
}
}
- /// Tries to atomically upgrade an upgradable read lock into a exclusive
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive
/// write lock, until a timeout is reached.
///
/// If the access could not be granted before the timeout expires, then
@@ -2286,6 +2496,73 @@ impl<R: RawRwLockUpgradeTimed, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
}
#[cfg(feature = "arc_lock")]
+impl<R: RawRwLockUpgradeTimed + RawRwLockUpgradeDowngrade, T: ?Sized>
+ ArcRwLockUpgradableReadGuard<R, T>
+{
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive
+ /// write lock, until a timeout is reached.
+ ///
+ /// If the access could not be granted before the timeout expires, then
+ /// `None` is returned.
+ ///
+ /// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
+ /// and finally downgrades the lock back to an upgradable read lock.
+ /// The closure's return value is wrapped in `Some` and returned.
+ ///
+ /// This function only requires a mutable reference to the guard, unlike
+ /// `try_upgrade_for` which takes the guard by value.
+ pub fn try_with_upgraded_for<Ret, F: FnOnce(&mut T) -> Ret>(
+ &mut self,
+ timeout: R::Duration,
+ f: F,
+ ) -> Option<Ret> {
+ if unsafe { self.rwlock.raw.try_upgrade_for(timeout) } {
+ // Safety: We just upgraded the lock, so we have mutable access to the data.
+ // This will restore the state the lock was in at the start of the function.
+ defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
+
+ // Safety: We upgraded the lock, so we have mutable access to the data.
+ // When this function returns, whether by drop or panic,
+ // the drop guard will downgrade it back to an upgradeable lock.
+ Some(f(unsafe { &mut *self.rwlock.data.get() }))
+ } else {
+ None
+ }
+ }
+
+ /// Tries to atomically upgrade an upgradable read lock into an exclusive
+ /// write lock, until a timeout is reached.
+ ///
+ /// If the access could not be granted before the timeout expires, then
+ /// `None` is returned.
+ ///
+ /// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
+ /// and finally downgrades the lock back to an upgradable read lock.
+ /// The closure's return value is wrapped in `Some` and returned.
+ ///
+ /// This function only requires a mutable reference to the guard, unlike
+ /// `try_upgrade_until` which takes the guard by value.
+ pub fn try_with_upgraded_until<Ret, F: FnOnce(&mut T) -> Ret>(
+ &mut self,
+ timeout: R::Instant,
+ f: F,
+ ) -> Option<Ret> {
+ if unsafe { self.rwlock.raw.try_upgrade_until(timeout) } {
+ // Safety: We just upgraded the lock, so we have mutable access to the data.
+ // This will restore the state the lock was in at the start of the function.
+ defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
+
+ // Safety: We upgraded the lock, so we have mutable access to the data.
+ // When this function returns, whether by drop or panic,
+ // the drop guard will downgrade it back to an upgradeable lock.
+ Some(f(unsafe { &mut *self.rwlock.data.get() }))
+ } else {
+ None
+ }
+ }
+}
+
+#[cfg(feature = "arc_lock")]
impl<R: RawRwLockUpgrade, T: ?Sized> Deref for ArcRwLockUpgradableReadGuard<R, T> {
type Target = T;
#[inline]
@@ -2330,6 +2607,7 @@ impl<R: RawRwLockUpgrade, T: fmt::Display + ?Sized> fmt::Display
/// former doesn't support temporarily unlocking and re-locking, since that
/// could introduce soundness issues if the locked object is modified by another
/// thread.
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct MappedRwLockReadGuard<'a, R: RawRwLock, T: ?Sized> {
raw: &'a R,
@@ -2465,6 +2743,7 @@ unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress
/// former doesn't support temporarily unlocking and re-locking, since that
/// could introduce soundness issues if the locked object is modified by another
/// thread.
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct MappedRwLockWriteGuard<'a, R: RawRwLock, T: ?Sized> {
raw: &'a R,