From 850a2e59d5ed85a85ed425679746d97532a2e93b Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Thu, 29 Jul 2021 15:51:47 -0700 Subject: [PATCH 1/7] Add arc_lock feature --- lock_api/Cargo.toml | 1 + lock_api/src/lib.rs | 7 +- lock_api/src/mutex.rs | 181 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 1 deletion(-) diff --git a/lock_api/Cargo.toml b/lock_api/Cargo.toml index 55b5c358..a5aaa313 100644 --- a/lock_api/Cargo.toml +++ b/lock_api/Cargo.toml @@ -20,3 +20,4 @@ serde = { version = "1.0.114", default-features = false, optional = true } [features] nightly = [] +arc_lock = [] diff --git a/lock_api/src/lib.rs b/lock_api/src/lib.rs index 6d581356..c99c68bd 100644 --- a/lock_api/src/lib.rs +++ b/lock_api/src/lib.rs @@ -79,9 +79,11 @@ //! //! # Cargo features //! -//! This crate supports two cargo features: +//! This crate supports three cargo features: //! //! - `owning_ref`: Allows your lock types to be used with the `owning_ref` crate. +//! - `arc_lock`: Enables locking from an `Arc`. This enables types such as `ArcMutexGuard`. Note that this +//! requires the `alloc` crate to be present. //! - `nightly`: Enables nightly-only features. At the moment the only such //! feature is `const fn` constructors for lock types. @@ -93,6 +95,9 @@ #[macro_use] extern crate scopeguard; +#[cfg(feature = "arc_lock")] +extern crate alloc; + /// Marker type which indicates that the Guard type for a lock is `Send`. pub struct GuardSend(()); diff --git a/lock_api/src/mutex.rs b/lock_api/src/mutex.rs index aded96d1..621593df 100644 --- a/lock_api/src/mutex.rs +++ b/lock_api/src/mutex.rs @@ -11,6 +11,9 @@ use core::marker::PhantomData; use core::mem; use core::ops::{Deref, DerefMut}; +#[cfg(feature = "arc_lock")] +use alloc::sync::Arc; + #[cfg(feature = "owning_ref")] use owning_ref::StableAddress; @@ -286,6 +289,45 @@ impl Mutex { pub fn data_ptr(&self) -> *mut T { self.data.get() } + + /// # Safety + /// + /// The lock needs to be held for the behavior of this function to be defined. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn guard_arc(this: &Arc) -> ArcMutexGuard { + ArcMutexGuard { + mutex: this.clone(), + marker: PhantomData, + } + } + + /// Acquires a lock through an `Arc`. + /// + /// This method is similar to the `lock` method; however, it requires the `Mutex` to be inside of an `Arc` + /// and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn lock_arc(this: &Arc) -> ArcMutexGuard { + this.raw.lock(); + // SAFETY: the locking guarantee is upheld + unsafe { Self::guard_arc(this) } + } + + /// Attempts to acquire a lock through an `Arc`. + /// + /// This method is similar to the `try_lock` method; however, it requires the `Mutex` to be inside of an + /// `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_arc(this: &Arc) -> Option> { + if this.raw.try_lock() { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::guard_arc(this) }) + } else { + None + } + } } impl Mutex { @@ -336,6 +378,39 @@ impl Mutex { None } } + + /// Attempts to acquire this lock through an `Arc` until a timeout is reached. + /// + /// This method is similar to the `try_lock_for` method; however, it requires the `Mutex` to be inside of an + /// `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_for_arc(this: &Arc, timeout: R::Duration) -> Option> { + if this.raw.try_lock_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::guard_arc(this) }) + } else { + None + } + } + + /// Attempts to acquire this lock through an `Arc` until a timeout is reached. + /// + /// This method is similar to the `try_lock_until` method; however, it requires the `Mutex` to be inside of + /// an `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_until_arc( + this: &Arc, + timeout: R::Instant, + ) -> Option> { + if this.raw.try_lock_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::guard_arc(this) }) + } else { + None + } + } } impl Default for Mutex { @@ -583,6 +658,112 @@ impl<'a, R: RawMutex + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display for Mutex #[cfg(feature = "owning_ref")] unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MutexGuard<'a, R, T> {} +/// An RAII mutex guard returned by the `Arc` locking operations on `Mutex`. This is similar to the `MutexGuard` +/// struct, except instead of using a reference to unlock the `Mutex` it uses an `Arc`. This has several +/// advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the Mutex will immediately unlock"] +pub struct ArcMutexGuard { + mutex: Arc>, + marker: PhantomData, +} + +#[cfg(feature = "arc_lock")] +impl ArcMutexGuard { + /// Returns a reference to the `Mutex` this is guarding, contained in its `Arc`. + #[inline] + pub fn mutex(&self) -> &Arc> { + &self.mutex + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the mutex. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock(); + } + defer!(s.mutex.raw.lock()); + f() + } +} + +#[cfg(feature = "arc_lock")] +impl ArcMutexGuard { + /// Unlocks the mutex using a fair unlock protocol. + /// + /// This is functionally identical to the `unlock_fair` method on [`MutexGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock_fair(); + } + mem::forget(s); + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is functionally identical to the `unlocked_fair` method on [`MutexGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock_fair(); + } + defer!(s.mutex.raw.lock()); + f() + } + + /// Temporarily yields the mutex to a waiting thread if there is one. + /// + /// This is functionally identical to the `bump` method on [`MutexGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.bump(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcMutexGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.mutex.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl DerefMut for ArcMutexGuard { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.mutex.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcMutexGuard { + #[inline] + fn drop(&mut self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + self.mutex.raw.unlock(); + } + } +} + /// An RAII mutex guard returned by `MutexGuard::map`, which can point to a /// subfield of the protected data. /// From a12a47f806c92c70b04a7b05b54b2fc2a79bdb33 Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Fri, 30 Jul 2021 09:35:09 -0700 Subject: [PATCH 2/7] remutex locks --- lock_api/src/remutex.rs | 172 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/lock_api/src/remutex.rs b/lock_api/src/remutex.rs index b49ec6c0..74be4ce5 100644 --- a/lock_api/src/remutex.rs +++ b/lock_api/src/remutex.rs @@ -19,6 +19,9 @@ use core::{ sync::atomic::{AtomicUsize, Ordering}, }; +#[cfg(feature = "arc_lock")] +use alloc::sync::Arc; + #[cfg(feature = "owning_ref")] use owning_ref::StableAddress; @@ -392,6 +395,45 @@ impl ReentrantMutex { pub fn data_ptr(&self) -> *mut T { self.data.get() } + + /// # Safety + /// + /// The lock must be held before calling this method. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn guard_arc(this: &Arc) -> ArcReentrantMutexGuard { + ArcReentrantMutexGuard { + remutex: this.clone(), + marker: PhantomData, + } + } + + /// Acquires a reentrant mutex through an `Arc`. + /// + /// This method is similar to the `lock` method; however, it requires the `ReentrantMutex` to be inside of an + /// `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn lock_arc(this: &Arc) -> ArcReentrantMutexGuard { + this.raw.lock(); + // SAFETY: locking guarantee is upheld + unsafe { Self::guard_arc(this) } + } + + /// Attempts to acquire a reentrant mutex through an `Arc`. + /// + /// This method is similar to the `try_lock` method; however, it requires the `ReentrantMutex` to be inside + /// of an `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_arc(this: &Arc) -> Option> { + if this.raw.try_lock() { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::guard_arc(this) }) + } else { + None + } + } } impl ReentrantMutex { @@ -442,6 +484,36 @@ impl ReentrantMutex { None } } + + /// Attempts to acquire this lock until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_lock_for` method; however, it requires the `ReentrantMutex` to be + /// inside of an `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_for_arc(this: &Arc, timeout: R::Duration) -> Option> { + if this.raw.try_lock_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::guard_arc(this) }) + } else { + None + } + } + + /// Attempts to acquire this lock until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_lock_until` method; however, it requires the `ReentrantMutex` to be + /// inside of an `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_until_arc(this: &Arc, timeout: R::Instant) -> Option> { + if this.raw.try_lock_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::guard_arc(this) }) + } else { + None + } + } } impl Default for ReentrantMutex { @@ -660,6 +732,7 @@ impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> s.remutex.raw.bump(); } } + } impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Deref @@ -706,6 +779,105 @@ unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAdd { } +/// An RAII mutex guard returned by the `Arc` locking operations on `ReentrantMutex`. This is similar to the +/// `ReentrantMutexGuard` struct, except instead of using a reference to unlock the `Mutex` it uses an +/// `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the ReentrantMutex will immediately unlock"] +pub struct ArcReentrantMutexGuard { + remutex: Arc>, + marker: PhantomData, +} + +impl ArcReentrantMutexGuard { + /// Returns a reference to the `ReentrantMutex` this object is guarding, contained in its `Arc`. + pub fn remutex(s: &Self) -> &Arc> { + &s.remutex + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the mutex. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A ReentrantMutexGuard always holds the lock. + unsafe { + s.remutex.raw.unlock(); + } + defer!(s.remutex.raw.lock()); + f() + } +} + +impl + ArcReentrantMutexGuard +{ + /// Unlocks the mutex using a fair unlock protocol. + /// + /// This is functionally identical to the `unlock_fair` method on [`ReentrantMutexGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.unlock_fair(); + } + mem::forget(s); + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is functionally identical to the `unlocked_fair` method on [`ReentrantMutexGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.unlock_fair(); + } + defer!(s.remutex.raw.lock()); + f() + } + + /// Temporarily yields the mutex to a waiting thread if there is one. + /// + /// This is functionally equivalent to the `bump` method on [`ReentrantMutexGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.bump(); + } + } +} + +impl Deref + for ArcReentrantMutexGuard +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.remutex.data.get() } + } +} + +impl Drop + for ReentrantMutexGuard +{ + #[inline] + fn drop(&mut self) { + // Safety: A ReentrantMutexGuard always holds the lock. + unsafe { + self.remutex.raw.unlock(); + } + } +} + /// An RAII mutex guard returned by `ReentrantMutexGuard::map`, which can point to a /// subfield of the protected data. /// From c95dd20ffcb9bce673e8473cf3cdcab89363f77a Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Fri, 30 Jul 2021 09:36:38 -0700 Subject: [PATCH 3/7] missed a spot --- lock_api/src/remutex.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lock_api/src/remutex.rs b/lock_api/src/remutex.rs index 74be4ce5..4d7d682d 100644 --- a/lock_api/src/remutex.rs +++ b/lock_api/src/remutex.rs @@ -789,6 +789,7 @@ pub struct ArcReentrantMutexGuard { marker: PhantomData, } +#[cfg(feature = "arc_lock")] impl ArcReentrantMutexGuard { /// Returns a reference to the `ReentrantMutex` this object is guarding, contained in its `Arc`. pub fn remutex(s: &Self) -> &Arc> { @@ -813,6 +814,7 @@ impl ArcReentrantMutexGuard { } } +#[cfg(feature = "arc_lock")] impl ArcReentrantMutexGuard { @@ -856,6 +858,7 @@ impl } } +#[cfg(feature = "arc_lock")] impl Deref for ArcReentrantMutexGuard { @@ -866,8 +869,9 @@ impl Deref } } +#[cfg(feature = "arc_lock")] impl Drop - for ReentrantMutexGuard + for ArcReentrantMutexGuard { #[inline] fn drop(&mut self) { From 2a2ebfad72c35129a7595ce365c0362d849507ee Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Fri, 30 Jul 2021 10:49:37 -0700 Subject: [PATCH 4/7] rwlock --- lock_api/src/rwlock.rs | 792 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 792 insertions(+) diff --git a/lock_api/src/rwlock.rs b/lock_api/src/rwlock.rs index e97de980..47eae255 100644 --- a/lock_api/src/rwlock.rs +++ b/lock_api/src/rwlock.rs @@ -11,6 +11,13 @@ use core::marker::PhantomData; use core::mem; use core::ops::{Deref, DerefMut}; +#[cfg(feature = "arc_lock")] +use alloc::sync::Arc; +#[cfg(feature = "arc_lock")] +use core::mem::ManuallyDrop; +#[cfg(feature = "arc_lock")] +use core::ptr; + #[cfg(feature = "owning_ref")] use owning_ref::StableAddress; @@ -557,6 +564,84 @@ impl RwLock { pub fn data_ptr(&self) -> *mut T { self.data.get() } + + /// # Safety + /// + /// The lock must be held when calling this method. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn read_guard_arc(this: &Arc) -> ArcRwLockReadGuard { + ArcRwLockReadGuard { + rwlock: this.clone(), + marker: PhantomData, + } + } + + /// # Safety + /// + /// The lock must be held when calling this method. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn write_guard_arc(this: &Arc) -> ArcRwLockWriteGuard { + ArcRwLockWriteGuard { + rwlock: this.clone(), + marker: PhantomData, + } + } + + /// Locks this `RwLock` with read access, through an `Arc`. + /// + /// This method is similar to the `read` method; however, it requires the `RwLock` to be inside of an `Arc` + /// and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn read_arc(this: &Arc) -> ArcRwLockReadGuard { + this.raw.lock_shared(); + // SAFETY: locking guarantee is upheld + unsafe { Self::read_guard_arc(this) } + } + + /// Attempts to lock this `RwLock` with read access, through an `Arc`. + /// + /// This method is similar to the `try_read` method; however, it requires the `RwLock` to be inside of an + /// `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_arc(this: &Arc) -> Option> { + if this.raw.try_lock_shared() { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::read_guard_arc(this) }) + } else { + None + } + } + + /// Locks this `RwLock` with write access, through an `Arc`. + /// + /// This method is similar to the `write` method; however, it requires the `RwLock` to be inside of an `Arc` + /// and the resulting write guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn write_arc(this: &Arc) -> ArcRwLockWriteGuard { + this.raw.lock_exclusive(); + // SAFETY: locking guarantee is upheld + unsafe { Self::write_guard_arc(this) } + } + + /// Attempts to lock this `RwLock` with writ access, through an `Arc`. + /// + /// This method is similar to the `try_write` method; however, it requires the `RwLock` to be inside of an + /// `Arc` and the resulting write guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_write_arc(this: &Arc) -> Option> { + if this.raw.try_lock_exclusive() { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::write_guard_arc(this) }) + } else { + None + } + } } impl RwLock { @@ -657,6 +742,66 @@ impl RwLock { None } } + + /// Attempts to acquire this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_read_for` method; however, it requires the `RwLock` to be inside of an + /// `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_arc_for(this: &Arc, timeout: R::Duration) -> Option> { + if this.raw.try_lock_shared_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::read_guard_arc(this) }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_read_until` method; however, it requires the `RwLock` to be inside of + /// an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_arc_until(this: &Arc, timeout: R::Instant) -> Option> { + if this.raw.try_lock_shared_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::read_guard_arc(this) }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with write access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_write_for` method; however, it requires the `RwLock` to be inside of + /// an `Arc` and the resulting write guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_write_arc_for(this: &Arc, timeout: R::Duration) -> Option> { + if this.raw.try_lock_exclusive_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::write_guard_arc(this) }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_write_until` method; however, it requires the `RwLock` to be inside of + /// an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_write_arc_until(this: &Arc, timeout: R::Instant) -> Option> { + if this.raw.try_lock_exclusive_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::write_guard_arc(this) }) + } else { + None + } + } } impl RwLock { @@ -701,6 +846,33 @@ impl RwLock { None } } + + /// Locks this `RwLock` with shared read access, through an `Arc`. + /// + /// This method is similar to the `read_recursive` method; however, it requires the `RwLock` to be inside of + /// an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn read_recursive_arc(this: &Arc) -> ArcRwLockReadGuard { + this.raw.lock_shared_recursive(); + // SAFETY: locking guarantee is upheld + unsafe { Self::read_guard_arc(this) } + } + + /// Attempts to lock this `RwLock` with shared read access, through an `Arc`. + /// + /// This method is similar to the `try_read_recursive` method; however, it requires the `RwLock` to be inside + /// of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_recursive_arc(this: &Arc) -> Option> { + if this.raw.try_lock_shared_recursive() { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::read_guard_arc(this) }) + } else { + None + } + } } impl RwLock { @@ -745,6 +917,36 @@ impl RwLock { None } } + + /// Attempts to lock this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_read_recursive_for` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_recursive_for_arc(this: &Arc, timeout: R::Duration) -> Option> { + if this.raw.try_lock_shared_recursive_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::read_guard_arc(this) }) + } else { + None + } + } + + /// Attempts to lock this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_read_recursive_until` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_recursive_until_arc(this: &Arc, timeout: R::Instant) -> Option> { + if this.raw.try_lock_shared_recursive_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::read_guard_arc(this) }) + } else { + None + } + } } impl RwLock { @@ -791,6 +993,45 @@ impl RwLock { None } } + + /// # Safety + /// + /// The lock must be held when calling this method. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn upgradable_guard_arc(this: &Arc) -> ArcRwLockUpgradableReadGuard { + ArcRwLockUpgradableReadGuard { + rwlock: this.clone(), + marker: PhantomData + } + } + + /// Locks this `RwLock` with upgradable read access, through an `Arc`. + /// + /// This method is similar to the `upgradable_read` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn upgradable_read_arc(this: &Arc) -> ArcRwLockUpgradableReadGuard { + this.raw.lock_upgradable(); + // SAFETY: locking guarantee is upheld + unsafe { Self::upgradable_guard_arc(this) } + } + + /// Attempts to lock this `RwLock` with upgradable read access, through an `Arc`. + /// + /// This method is similar to the `try_upgradable_read` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_upgradable_read_arc(this: &Arc) -> Option> { + if this.raw.try_lock_upgradable() { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::upgradable_guard_arc(this) }) + } else { + None + } + } } impl RwLock { @@ -831,6 +1072,42 @@ impl RwLock { None } } + + /// Attempts to lock this `RwLock` with upgradable access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_upgradable_read_for` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_upgradable_read_for_arc( + this: &Arc, + timeout: R::Duration, + ) -> Option> { + if this.raw.try_lock_upgradable_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::upgradable_guard_arc(this) }) + } else { + None + } + } + + /// Attempts to lock this `RwLock` with upgradable access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_upgradable_read_until` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_upgradable_read_until_arc( + this: &Arc, + timeout: R::Instant, + ) -> Option> { + if this.raw.try_lock_upgradable_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { Self::upgradable_guard_arc(this) }) + } else { + None + } + } } impl Default for RwLock { @@ -1041,6 +1318,118 @@ impl<'a, R: RawRwLock + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display #[cfg(feature = "owning_ref")] unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockReadGuard<'a, R, T> {} +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. This is similar to the +/// `RwLockReadGuard` struct, except instead of using a reference to unlock the `RwLock` it uses an +/// `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockReadGuard { + rwlock: Arc>, + marker: PhantomData, +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockReadGuard { + /// Returns a reference to the rwlock, contained in its `Arc`. + pub fn rwlock(s: &Self) -> &Arc> { + &s.rwlock + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally identical to the `unlocked` method on [`RwLockReadGuard`]. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared(); + } + defer!(s.rwlock.raw.lock_shared()); + f() + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockReadGuard { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// This is functionally identical to the `unlock_fair` method on [`RwLockReadGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared_fair(); + } + mem::forget(s); + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally identical to the `unlocked_fair` method on [`RwLockReadGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared_fair(); + } + defer!(s.rwlock.raw.lock_shared()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This is functionally identical to the `bump` method on [`RwLockReadGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.bump_shared(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcRwLockReadGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcRwLockReadGuard { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + self.rwlock.raw.unlock_shared(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Debug for ArcRwLockReadGuard { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Display + for ArcRwLockReadGuard +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use = "if unused the RwLock will immediately unlock"] @@ -1262,6 +1651,175 @@ impl<'a, R: RawRwLock + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display #[cfg(feature = "owning_ref")] unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockWriteGuard<'a, R, T> {} +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. This is similar to the +/// `RwLockWriteGuard` struct, except instead of using a reference to unlock the `RwLock` it uses an +/// `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockWriteGuard { + rwlock: Arc>, + marker: PhantomData, +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockWriteGuard { + /// Returns a reference to the rwlock, contained in its `Arc`. + pub fn rwlock(s: &Self) -> &Arc> { + &s.rwlock + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally equivalent to the `unlocked` method on [`RwLockWriteGuard`]. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockWriteGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_exclusive(); + } + defer!(s.rwlock.raw.lock_exclusive()); + f() + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockWriteGuard { + /// Atomically downgrades a write lock into a read lock without allowing any + /// writers to take exclusive access of the lock in the meantime. + /// + /// This is functionally equivalent to the `downgrade` method on [`RwLockWriteGuard`]. + pub fn downgrade(s: Self) -> ArcRwLockReadGuard { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.downgrade(); + } + + // SAFETY: prevent the arc's refcount from changing using ManuallyDrop and ptr::read + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + ArcRwLockReadGuard { + rwlock, + marker: PhantomData, + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockWriteGuard { + /// Atomically downgrades a write lock into an upgradable read lock without allowing any + /// writers to take exclusive access of the lock in the meantime. + /// + /// This is functionally identical to the `downgrade_to_upgradable` method on [`RwLockWriteGuard`]. + pub fn downgrade_to_upgradable(s: Self) -> ArcRwLockUpgradableReadGuard { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.downgrade_to_upgradable(); + } + + // SAFETY: same as above + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + ArcRwLockUpgradableReadGuard { + rwlock, + marker: PhantomData, + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockWriteGuard { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// This is functionally equivalent to the `unlock_fair` method on [`RwLockWriteGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.unlock_exclusive_fair(); + } + + // SAFETY: prevent the Arc from leaking memory + let s = ManuallyDrop::new(s); + let _ = unsafe { ptr::read(&s.rwlock) }; + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally equivalent to the `unlocked_fair` method on [`RwLockWriteGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.unlock_exclusive_fair(); + } + defer!(s.rwlock.raw.lock_exclusive()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This method is functionally equivalent to the `bump` method on [`RwLockWriteGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.bump_exclusive(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcRwLockWriteGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl DerefMut for ArcRwLockWriteGuard { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcRwLockWriteGuard { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + self.rwlock.raw.unlock_exclusive(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Debug for ArcRwLockWriteGuard { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Display + for ArcRwLockWriteGuard +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + /// RAII structure used to release the upgradable read access of a lock when /// dropped. #[must_use = "if unused the RwLock will immediately unlock"] @@ -1495,6 +2053,240 @@ unsafe impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> StableAddress { } +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. This is similar to the +/// `RwLockUpgradableReadGuard` struct, except instead of using a reference to unlock the `RwLock` it uses an +/// `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockUpgradableReadGuard { + rwlock: Arc>, + marker: PhantomData, +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockUpgradableReadGuard { + /// Returns a reference to the rwlock, contained in its original `Arc`. + pub fn rwlock(s: &Self) -> &Arc> { + &s.rwlock + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally identical to the `unlocked` method on [`RwLockUpgradableReadGuard`]. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable(); + } + defer!(s.rwlock.raw.lock_upgradable()); + f() + } + + /// Atomically upgrades an upgradable read lock lock into a exclusive write lock, + /// blocking the current thread until it can be acquired. + pub fn upgrade(s: Self) -> ArcRwLockWriteGuard { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.upgrade(); + } + + // SAFETY: avoid incrementing or decrementing the refcount using ManuallyDrop and reading the Arc out + // of the struct + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + ArcRwLockWriteGuard { + rwlock, + marker: PhantomData, + } + } + + /// Tries to atomically upgrade an upgradable read lock into a 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, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade() } { + // SAFETY: same as above + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + Ok(ArcRwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockUpgradableReadGuard { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// This is functionally identical to the `unlock_fair` method on [`RwLockUpgradableReadGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable_fair(); + } + + // SAFETY: make sure we decrement the refcount properly + let s = ManuallyDrop::new(s); + let _ = unsafe { ptr::read(&s.rwlock) }; + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally equivalent to the `unlocked_fair` method on [`RwLockUpgradableReadGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable_fair(); + } + defer!(s.rwlock.raw.lock_upgradable()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `bump` on [`RwLockUpgradableReadGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.bump_upgradable(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockUpgradableReadGuard { + /// Atomically downgrades an upgradable read lock lock into a shared read lock + /// without allowing any writers to take exclusive access of the lock in the + /// meantime. + /// + /// Note that if there are any writers currently waiting to take the lock + /// then other readers may not be able to acquire the lock even if it was + /// downgraded. + pub fn downgrade(s: Self) -> ArcRwLockReadGuard { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.downgrade_upgradable(); + } + + // SAFETY: use ManuallyDrop and ptr::read to ensure the refcount is not changed + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + ArcRwLockReadGuard { + rwlock, + marker: PhantomData, + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockUpgradableReadGuard { + /// Tries to atomically upgrade an upgradable read lock into a exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// the current guard is returned. + pub fn try_upgrade_for( + s: Self, + timeout: R::Duration, + ) -> Result, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade_for(timeout) } { + // SAFETY: same as above + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + Ok(ArcRwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } + + /// Tries to atomically upgrade an upgradable read lock into a exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// the current guard is returned. + #[inline] + pub fn try_upgrade_until( + s: Self, + timeout: R::Instant, + ) -> Result, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade_until(timeout) } { + // SAFETY: same as above + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + Ok(ArcRwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcRwLockUpgradableReadGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcRwLockUpgradableReadGuard { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + self.rwlock.raw.unlock_upgradable(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Debug + for ArcRwLockUpgradableReadGuard +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Display + for ArcRwLockUpgradableReadGuard +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + + /// An RAII read lock guard returned by `RwLockReadGuard::map`, which can point to a /// subfield of the protected data. /// From e68737825408c5798982112a7caadecf06462a9c Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Fri, 30 Jul 2021 11:06:34 -0700 Subject: [PATCH 5/7] Fix the issue where it leaks memory for no reason --- lock_api/src/mutex.rs | 39 ++++++++------ lock_api/src/remutex.rs | 37 +++++++------ lock_api/src/rwlock.rs | 117 ++++++++++++++++++++-------------------- 3 files changed, 105 insertions(+), 88 deletions(-) diff --git a/lock_api/src/mutex.rs b/lock_api/src/mutex.rs index 621593df..e909cf35 100644 --- a/lock_api/src/mutex.rs +++ b/lock_api/src/mutex.rs @@ -13,6 +13,10 @@ use core::ops::{Deref, DerefMut}; #[cfg(feature = "arc_lock")] use alloc::sync::Arc; +#[cfg(feature = "arc_lock")] +use core::mem::ManuallyDrop; +#[cfg(feature = "arc_lock")] +use core::ptr; #[cfg(feature = "owning_ref")] use owning_ref::StableAddress; @@ -295,9 +299,9 @@ impl Mutex { /// The lock needs to be held for the behavior of this function to be defined. #[cfg(feature = "arc_lock")] #[inline] - unsafe fn guard_arc(this: &Arc) -> ArcMutexGuard { + unsafe fn guard_arc(self: &Arc) -> ArcMutexGuard { ArcMutexGuard { - mutex: this.clone(), + mutex: self.clone(), marker: PhantomData, } } @@ -308,10 +312,10 @@ impl Mutex { /// and the resulting mutex guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn lock_arc(this: &Arc) -> ArcMutexGuard { - this.raw.lock(); + pub fn lock_arc(self: &Arc) -> ArcMutexGuard { + self.raw.lock(); // SAFETY: the locking guarantee is upheld - unsafe { Self::guard_arc(this) } + unsafe { self.guard_arc() } } /// Attempts to acquire a lock through an `Arc`. @@ -320,10 +324,10 @@ impl Mutex { /// `Arc` and the resulting mutex guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_lock_arc(this: &Arc) -> Option> { - if this.raw.try_lock() { + pub fn try_lock_arc(self: &Arc) -> Option> { + if self.raw.try_lock() { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::guard_arc(this) }) + Some(unsafe { self.guard_arc() }) } else { None } @@ -385,10 +389,10 @@ impl Mutex { /// `Arc` and the resulting mutex guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_lock_for_arc(this: &Arc, timeout: R::Duration) -> Option> { - if this.raw.try_lock_for(timeout) { + pub fn try_lock_arc_for(self: &Arc, timeout: R::Duration) -> Option> { + if self.raw.try_lock_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::guard_arc(this) }) + Some(unsafe { self.guard_arc() }) } else { None } @@ -400,13 +404,13 @@ impl Mutex { /// an `Arc` and the resulting mutex guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_lock_until_arc( - this: &Arc, + pub fn try_lock_arc_until( + self: &Arc, timeout: R::Instant, ) -> Option> { - if this.raw.try_lock_until(timeout) { + if self.raw.try_lock_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::guard_arc(this) }) + Some(unsafe { self.guard_arc() }) } else { None } @@ -705,7 +709,10 @@ impl ArcMutexGuard { unsafe { s.mutex.raw.unlock_fair(); } - mem::forget(s); + + // SAFETY: make sure the Arc gets it reference decremented + let s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&s.rwlock) }; } /// Temporarily unlocks the mutex to execute the given function. diff --git a/lock_api/src/remutex.rs b/lock_api/src/remutex.rs index 4d7d682d..3400591f 100644 --- a/lock_api/src/remutex.rs +++ b/lock_api/src/remutex.rs @@ -21,6 +21,10 @@ use core::{ #[cfg(feature = "arc_lock")] use alloc::sync::Arc; +#[cfg(feature = "arc_lock")] +use core::mem::ManuallyDrop; +#[cfg(feature = "arc_lock")] +use core::ptr; #[cfg(feature = "owning_ref")] use owning_ref::StableAddress; @@ -401,9 +405,9 @@ impl ReentrantMutex { /// The lock must be held before calling this method. #[cfg(feature = "arc_lock")] #[inline] - unsafe fn guard_arc(this: &Arc) -> ArcReentrantMutexGuard { + unsafe fn guard_arc(self: &Arc) -> ArcReentrantMutexGuard { ArcReentrantMutexGuard { - remutex: this.clone(), + remutex: self.clone(), marker: PhantomData, } } @@ -414,10 +418,10 @@ impl ReentrantMutex { /// `Arc` and the resulting mutex guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn lock_arc(this: &Arc) -> ArcReentrantMutexGuard { - this.raw.lock(); + pub fn lock_arc(self: &Arc) -> ArcReentrantMutexGuard { + self.raw.lock(); // SAFETY: locking guarantee is upheld - unsafe { Self::guard_arc(this) } + unsafe { self.guard_arc() } } /// Attempts to acquire a reentrant mutex through an `Arc`. @@ -426,10 +430,10 @@ impl ReentrantMutex { /// of an `Arc` and the resulting mutex guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_lock_arc(this: &Arc) -> Option> { - if this.raw.try_lock() { + pub fn try_lock_arc(self: &Arc) -> Option> { + if self.raw.try_lock() { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::guard_arc(this) }) + Some(unsafe { self.guard_arc() }) } else { None } @@ -491,10 +495,10 @@ impl ReentrantMutex { /// inside of an `Arc` and the resulting mutex guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_lock_for_arc(this: &Arc, timeout: R::Duration) -> Option> { - if this.raw.try_lock_for(timeout) { + pub fn try_lock_arc_for(self: &Arc, timeout: R::Duration) -> Option> { + if self.raw.try_lock_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::guard_arc(this) }) + Some(unsafe { self.guard_arc() }) } else { None } @@ -506,10 +510,10 @@ impl ReentrantMutex { /// inside of an `Arc` and the resulting mutex guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_lock_until_arc(this: &Arc, timeout: R::Instant) -> Option> { - if this.raw.try_lock_until(timeout) { + pub fn try_lock_arc_until(self: &Arc, timeout: R::Instant) -> Option> { + if self.raw.try_lock_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::guard_arc(this) }) + Some(unsafe { self.guard_arc() }) } else { None } @@ -827,7 +831,10 @@ impl unsafe { s.remutex.raw.unlock_fair(); } - mem::forget(s); + + // SAFETY: ensure that the Arc's refcount is decremented + let s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&s.rwlock) }; } /// Temporarily unlocks the mutex to execute the given function. diff --git a/lock_api/src/rwlock.rs b/lock_api/src/rwlock.rs index 47eae255..d3dd1ac6 100644 --- a/lock_api/src/rwlock.rs +++ b/lock_api/src/rwlock.rs @@ -570,9 +570,9 @@ impl RwLock { /// The lock must be held when calling this method. #[cfg(feature = "arc_lock")] #[inline] - unsafe fn read_guard_arc(this: &Arc) -> ArcRwLockReadGuard { + unsafe fn read_guard_arc(self: &Arc) -> ArcRwLockReadGuard { ArcRwLockReadGuard { - rwlock: this.clone(), + rwlock: self.clone(), marker: PhantomData, } } @@ -582,9 +582,9 @@ impl RwLock { /// The lock must be held when calling this method. #[cfg(feature = "arc_lock")] #[inline] - unsafe fn write_guard_arc(this: &Arc) -> ArcRwLockWriteGuard { + unsafe fn write_guard_arc(self: &Arc) -> ArcRwLockWriteGuard { ArcRwLockWriteGuard { - rwlock: this.clone(), + rwlock: self.clone(), marker: PhantomData, } } @@ -595,10 +595,10 @@ impl RwLock { /// and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn read_arc(this: &Arc) -> ArcRwLockReadGuard { - this.raw.lock_shared(); + pub fn read_arc(self: &Arc) -> ArcRwLockReadGuard { + self.raw.lock_shared(); // SAFETY: locking guarantee is upheld - unsafe { Self::read_guard_arc(this) } + unsafe { self.read_guard_arc() } } /// Attempts to lock this `RwLock` with read access, through an `Arc`. @@ -607,10 +607,10 @@ impl RwLock { /// `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_read_arc(this: &Arc) -> Option> { - if this.raw.try_lock_shared() { + pub fn try_read_arc(self: &Arc) -> Option> { + if self.raw.try_lock_shared() { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::read_guard_arc(this) }) + Some(unsafe { self.read_guard_arc() }) } else { None } @@ -622,10 +622,10 @@ impl RwLock { /// and the resulting write guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn write_arc(this: &Arc) -> ArcRwLockWriteGuard { - this.raw.lock_exclusive(); + pub fn write_arc(self: &Arc) -> ArcRwLockWriteGuard { + self.raw.lock_exclusive(); // SAFETY: locking guarantee is upheld - unsafe { Self::write_guard_arc(this) } + unsafe { self.write_guard_arc() } } /// Attempts to lock this `RwLock` with writ access, through an `Arc`. @@ -634,10 +634,10 @@ impl RwLock { /// `Arc` and the resulting write guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_write_arc(this: &Arc) -> Option> { - if this.raw.try_lock_exclusive() { + pub fn try_write_arc(self: &Arc) -> Option> { + if self.raw.try_lock_exclusive() { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::write_guard_arc(this) }) + Some(unsafe { self.write_guard_arc() }) } else { None } @@ -749,10 +749,10 @@ impl RwLock { /// `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_read_arc_for(this: &Arc, timeout: R::Duration) -> Option> { - if this.raw.try_lock_shared_for(timeout) { + pub fn try_read_arc_for(self: &Arc, timeout: R::Duration) -> Option> { + if self.raw.try_lock_shared_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::read_guard_arc(this) }) + Some(unsafe { self.read_guard_arc() }) } else { None } @@ -764,10 +764,10 @@ impl RwLock { /// an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_read_arc_until(this: &Arc, timeout: R::Instant) -> Option> { - if this.raw.try_lock_shared_until(timeout) { + pub fn try_read_arc_until(self: &Arc, timeout: R::Instant) -> Option> { + if self.raw.try_lock_shared_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::read_guard_arc(this) }) + Some(unsafe { self.read_guard_arc() }) } else { None } @@ -779,10 +779,10 @@ impl RwLock { /// an `Arc` and the resulting write guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_write_arc_for(this: &Arc, timeout: R::Duration) -> Option> { - if this.raw.try_lock_exclusive_for(timeout) { + pub fn try_write_arc_for(self: &Arc, timeout: R::Duration) -> Option> { + if self.raw.try_lock_exclusive_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::write_guard_arc(this) }) + Some(unsafe { self.write_guard_arc() }) } else { None } @@ -794,10 +794,10 @@ impl RwLock { /// an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_write_arc_until(this: &Arc, timeout: R::Instant) -> Option> { - if this.raw.try_lock_exclusive_until(timeout) { + pub fn try_write_arc_until(self: &Arc, timeout: R::Instant) -> Option> { + if self.raw.try_lock_exclusive_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::write_guard_arc(this) }) + Some(unsafe { self.write_guard_arc() }) } else { None } @@ -853,10 +853,10 @@ impl RwLock { /// an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn read_recursive_arc(this: &Arc) -> ArcRwLockReadGuard { + pub fn read_arc_recursive(self: &Arc) -> ArcRwLockReadGuard { this.raw.lock_shared_recursive(); // SAFETY: locking guarantee is upheld - unsafe { Self::read_guard_arc(this) } + unsafe { self.read_guard_arc() } } /// Attempts to lock this `RwLock` with shared read access, through an `Arc`. @@ -865,10 +865,10 @@ impl RwLock { /// of an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_read_recursive_arc(this: &Arc) -> Option> { - if this.raw.try_lock_shared_recursive() { + pub fn try_read_recursive_arc(self: &Arc) -> Option> { + if self.raw.try_lock_shared_recursive() { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::read_guard_arc(this) }) + Some(unsafe { self.read_guard_arc() }) } else { None } @@ -924,10 +924,10 @@ impl RwLock { /// inside of an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_read_recursive_for_arc(this: &Arc, timeout: R::Duration) -> Option> { - if this.raw.try_lock_shared_recursive_for(timeout) { + pub fn try_read_arc_recursive_for(self: &Arc, timeout: R::Duration) -> Option> { + if self.raw.try_lock_shared_recursive_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::read_guard_arc(this) }) + Some(unsafe { self.read_guard_arc() }) } else { None } @@ -939,10 +939,10 @@ impl RwLock { /// inside of an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_read_recursive_until_arc(this: &Arc, timeout: R::Instant) -> Option> { - if this.raw.try_lock_shared_recursive_until(timeout) { + pub fn try_read_arc_recursive_until(self: &Arc, timeout: R::Instant) -> Option> { + if self.raw.try_lock_shared_recursive_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::read_guard_arc(this) }) + Some(unsafe { self.read_guard_arc() }) } else { None } @@ -999,9 +999,9 @@ impl RwLock { /// The lock must be held when calling this method. #[cfg(feature = "arc_lock")] #[inline] - unsafe fn upgradable_guard_arc(this: &Arc) -> ArcRwLockUpgradableReadGuard { + unsafe fn upgradable_guard_arc(self: &Arc) -> ArcRwLockUpgradableReadGuard { ArcRwLockUpgradableReadGuard { - rwlock: this.clone(), + rwlock: self.clone(), marker: PhantomData } } @@ -1012,10 +1012,10 @@ impl RwLock { /// inside of an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn upgradable_read_arc(this: &Arc) -> ArcRwLockUpgradableReadGuard { - this.raw.lock_upgradable(); + pub fn upgradable_read_arc(self: &Arc) -> ArcRwLockUpgradableReadGuard { + self.raw.lock_upgradable(); // SAFETY: locking guarantee is upheld - unsafe { Self::upgradable_guard_arc(this) } + unsafe { self.upgradable_guard_arc() } } /// Attempts to lock this `RwLock` with upgradable read access, through an `Arc`. @@ -1024,10 +1024,10 @@ impl RwLock { /// inside of an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_upgradable_read_arc(this: &Arc) -> Option> { - if this.raw.try_lock_upgradable() { + pub fn try_upgradable_read_arc(self: &Arc) -> Option> { + if self.raw.try_lock_upgradable() { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::upgradable_guard_arc(this) }) + Some(unsafe { self.upgradable_guard_arc() }) } else { None } @@ -1079,13 +1079,13 @@ impl RwLock { /// inside of an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_upgradable_read_for_arc( - this: &Arc, + pub fn try_upgradable_read_arc_for( + self: &Arc, timeout: R::Duration, ) -> Option> { - if this.raw.try_lock_upgradable_for(timeout) { + if self.raw.try_lock_upgradable_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::upgradable_guard_arc(this) }) + Some(unsafe { self.upgradable_guard_arc(this) }) } else { None } @@ -1097,13 +1097,13 @@ impl RwLock { /// inside of an `Arc` and the resulting read guard has no lifetime requirements. #[cfg(feature = "arc_lock")] #[inline] - pub fn try_upgradable_read_until_arc( + pub fn try_upgradable_read_arc_until( this: &Arc, timeout: R::Instant, ) -> Option> { - if this.raw.try_lock_upgradable_until(timeout) { + if self.raw.try_lock_upgradable_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { Self::upgradable_guard_arc(this) }) + Some(unsafe { self.upgradable_guard_arc() }) } else { None } @@ -1363,7 +1363,10 @@ impl ArcRwLockReadGuard { unsafe { s.rwlock.raw.unlock_shared_fair(); } - mem::forget(s); + + // SAFETY: ensure the Arc has its refcount decremented + let s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&s.rwlock) }; } /// Temporarily unlocks the `RwLock` to execute the given function. @@ -1745,7 +1748,7 @@ impl ArcRwLockWriteGuard { // SAFETY: prevent the Arc from leaking memory let s = ManuallyDrop::new(s); - let _ = unsafe { ptr::read(&s.rwlock) }; + unsafe { ptr::drop_in_place(&s.rwlock) }; } /// Temporarily unlocks the `RwLock` to execute the given function. @@ -2139,7 +2142,7 @@ impl ArcRwLockUpgradableReadGuard { // SAFETY: make sure we decrement the refcount properly let s = ManuallyDrop::new(s); - let _ = unsafe { ptr::read(&s.rwlock) }; + unsafe { ptr::drop_in_place(&s.rwlock) }; } /// Temporarily unlocks the `RwLock` to execute the given function. From 8b0eb2ffca5dc2c74d11cac4480274679a14cd90 Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Fri, 30 Jul 2021 11:11:35 -0700 Subject: [PATCH 6/7] whoops --- lock_api/src/mutex.rs | 11 ++++++----- lock_api/src/remutex.rs | 12 +++++++----- lock_api/src/rwlock.rs | 38 ++++++++++++++++++++------------------ 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/lock_api/src/mutex.rs b/lock_api/src/mutex.rs index e909cf35..f64fc13f 100644 --- a/lock_api/src/mutex.rs +++ b/lock_api/src/mutex.rs @@ -662,9 +662,10 @@ impl<'a, R: RawMutex + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display for Mutex #[cfg(feature = "owning_ref")] unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MutexGuard<'a, R, T> {} -/// An RAII mutex guard returned by the `Arc` locking operations on `Mutex`. This is similar to the `MutexGuard` -/// struct, except instead of using a reference to unlock the `Mutex` it uses an `Arc`. This has several -/// advantages, most notably that it has an `'static` lifetime. +/// An RAII mutex guard returned by the `Arc` locking operations on `Mutex`. +/// +/// This is similar to the `MutexGuard` struct, except instead of using a reference to unlock the `Mutex` it +/// uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. #[cfg(feature = "arc_lock")] #[must_use = "if unused the Mutex will immediately unlock"] pub struct ArcMutexGuard { @@ -711,8 +712,8 @@ impl ArcMutexGuard { } // SAFETY: make sure the Arc gets it reference decremented - let s = ManuallyDrop::new(s); - unsafe { ptr::drop_in_place(&s.rwlock) }; + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.mutex) }; } /// Temporarily unlocks the mutex to execute the given function. diff --git a/lock_api/src/remutex.rs b/lock_api/src/remutex.rs index 3400591f..8493a249 100644 --- a/lock_api/src/remutex.rs +++ b/lock_api/src/remutex.rs @@ -783,9 +783,11 @@ unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAdd { } -/// An RAII mutex guard returned by the `Arc` locking operations on `ReentrantMutex`. This is similar to the -/// `ReentrantMutexGuard` struct, except instead of using a reference to unlock the `Mutex` it uses an -/// `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +/// An RAII mutex guard returned by the `Arc` locking operations on `ReentrantMutex`. +/// +/// This is similar to the `ReentrantMutexGuard` struct, except instead of using a reference to unlock the +/// `Mutex` it uses an `Arc`. This has several advantages, most notably that it has an `'static` +/// lifetime. #[cfg(feature = "arc_lock")] #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ArcReentrantMutexGuard { @@ -833,8 +835,8 @@ impl } // SAFETY: ensure that the Arc's refcount is decremented - let s = ManuallyDrop::new(s); - unsafe { ptr::drop_in_place(&s.rwlock) }; + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.remutex) }; } /// Temporarily unlocks the mutex to execute the given function. diff --git a/lock_api/src/rwlock.rs b/lock_api/src/rwlock.rs index d3dd1ac6..c404934e 100644 --- a/lock_api/src/rwlock.rs +++ b/lock_api/src/rwlock.rs @@ -854,7 +854,7 @@ impl RwLock { #[cfg(feature = "arc_lock")] #[inline] pub fn read_arc_recursive(self: &Arc) -> ArcRwLockReadGuard { - this.raw.lock_shared_recursive(); + self.raw.lock_shared_recursive(); // SAFETY: locking guarantee is upheld unsafe { self.read_guard_arc() } } @@ -1085,7 +1085,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_upgradable_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.upgradable_guard_arc(this) }) + Some(unsafe { self.upgradable_guard_arc() }) } else { None } @@ -1098,7 +1098,7 @@ impl RwLock { #[cfg(feature = "arc_lock")] #[inline] pub fn try_upgradable_read_arc_until( - this: &Arc, + self: &Arc, timeout: R::Instant, ) -> Option> { if self.raw.try_lock_upgradable_until(timeout) { @@ -1318,9 +1318,10 @@ impl<'a, R: RawRwLock + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display #[cfg(feature = "owning_ref")] unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockReadGuard<'a, R, T> {} -/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. This is similar to the -/// `RwLockReadGuard` struct, except instead of using a reference to unlock the `RwLock` it uses an -/// `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. +/// +/// This is similar to the `RwLockReadGuard` struct, except instead of using a reference to unlock the `RwLock` +/// it uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. #[cfg(feature = "arc_lock")] #[must_use = "if unused the RwLock will immediately unlock"] pub struct ArcRwLockReadGuard { @@ -1365,8 +1366,8 @@ impl ArcRwLockReadGuard { } // SAFETY: ensure the Arc has its refcount decremented - let s = ManuallyDrop::new(s); - unsafe { ptr::drop_in_place(&s.rwlock) }; + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.rwlock) }; } /// Temporarily unlocks the `RwLock` to execute the given function. @@ -1654,9 +1655,9 @@ impl<'a, R: RawRwLock + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display #[cfg(feature = "owning_ref")] unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockWriteGuard<'a, R, T> {} -/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. This is similar to the -/// `RwLockWriteGuard` struct, except instead of using a reference to unlock the `RwLock` it uses an -/// `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. +/// This is similar to the `RwLockWriteGuard` struct, except instead of using a reference to unlock the `RwLock` +/// it uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. #[cfg(feature = "arc_lock")] #[must_use = "if unused the RwLock will immediately unlock"] pub struct ArcRwLockWriteGuard { @@ -1747,8 +1748,8 @@ impl ArcRwLockWriteGuard { } // SAFETY: prevent the Arc from leaking memory - let s = ManuallyDrop::new(s); - unsafe { ptr::drop_in_place(&s.rwlock) }; + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.rwlock) }; } /// Temporarily unlocks the `RwLock` to execute the given function. @@ -2056,9 +2057,10 @@ unsafe impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> StableAddress { } -/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. This is similar to the -/// `RwLockUpgradableReadGuard` struct, except instead of using a reference to unlock the `RwLock` it uses an -/// `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. +/// This is similar to the `RwLockUpgradableReadGuard` struct, except instead of using a reference to unlock the +/// `RwLock` it uses an `Arc`. This has several advantages, most notably that it has an `'static` +/// lifetime. #[cfg(feature = "arc_lock")] #[must_use = "if unused the RwLock will immediately unlock"] pub struct ArcRwLockUpgradableReadGuard { @@ -2141,8 +2143,8 @@ impl ArcRwLockUpgradableReadGuard { } // SAFETY: make sure we decrement the refcount properly - let s = ManuallyDrop::new(s); - unsafe { ptr::drop_in_place(&s.rwlock) }; + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.rwlock) }; } /// Temporarily unlocks the `RwLock` to execute the given function. From a9f567188f4474cd3b86029ccf5bcf07800712ad Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Sat, 31 Jul 2021 10:23:39 -0700 Subject: [PATCH 7/7] arc lock to ci --- .github/workflows/rust.yml | 4 ++-- Cargo.toml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d613089a..32b432f3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -17,7 +17,7 @@ jobs: matrix: os: [ubuntu, macos, windows] channel: [1.36.0, stable, beta, nightly] - feature: [serde, deadlock_detection] + feature: [arc_lock, serde, deadlock_detection] exclude: - feature: deadlock_detection channel: '1.36.0' @@ -53,7 +53,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: rustup default nightly - - run: cargo doc --workspace --features serde,deadlock_detection --no-deps -p parking_lot -p parking_lot_core -p lock_api + - run: cargo doc --workspace --features arc_lock,serde,deadlock_detection --no-deps -p parking_lot -p parking_lot_core -p lock_api benchmark: runs-on: ubuntu-latest steps: diff --git a/Cargo.toml b/Cargo.toml index 67a2555d..253e8352 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ bincode = "1.3.0" [features] default = [] +arc_lock = ["lock_api/arc_lock"] owning_ref = ["lock_api/owning_ref"] nightly = ["parking_lot_core/nightly", "lock_api/nightly"] deadlock_detection = ["parking_lot_core/deadlock_detection"]