From d7989f856433042e0e550db8bbfd976bccc502e8 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 28 May 2023 00:52:51 -0400 Subject: [PATCH 1/2] Add reference-counted versions of `RwLock` guards --- src/lib.rs | 9 +- src/rwlock.rs | 677 +++++++++++++++++++++++++++++++++++------- src/rwlock/futures.rs | 300 +++++++++++++++++++ src/rwlock/raw.rs | 8 + tests/rwlock.rs | 249 +++++++++++++++- 5 files changed, 1125 insertions(+), 118 deletions(-) create mode 100644 src/rwlock/futures.rs diff --git a/src/lib.rs b/src/lib.rs index a2ee70a..dbf81c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,10 @@ mod semaphore; pub use barrier::{Barrier, BarrierWaitResult}; pub use mutex::{Mutex, MutexGuard, MutexGuardArc}; pub use once_cell::OnceCell; -pub use rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableReadGuard, RwLockWriteGuard}; +pub use rwlock::{ + ArcRwLockReadGuard, ArcRwLockUpgradableReadGuard, ArcRwLockWriteGuard, RwLock, RwLockReadGuard, + RwLockUpgradableReadGuard, RwLockWriteGuard, +}; pub use semaphore::{Semaphore, SemaphoreGuard, SemaphoreGuardArc}; pub mod futures { @@ -55,6 +58,8 @@ pub mod futures { pub use crate::barrier::BarrierWait; pub use crate::mutex::{Lock, LockArc}; - pub use crate::rwlock::{Read, UpgradableRead, Upgrade, Write}; + pub use crate::rwlock::futures::{ + ArcUpgrade, Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, Write, WriteArc, + }; pub use crate::semaphore::{Acquire, AcquireArc}; } diff --git a/src/rwlock.rs b/src/rwlock.rs index 2b6d54e..c8a8b1d 100644 --- a/src/rwlock.rs +++ b/src/rwlock.rs @@ -1,14 +1,18 @@ use std::cell::UnsafeCell; use std::fmt; -use std::future::Future; -use std::mem::ManuallyDrop; +use std::mem::{self, ManuallyDrop}; use std::ops::{Deref, DerefMut}; -use std::pin::Pin; -use std::task::{Context, Poll}; +use std::ptr::{self, NonNull}; +use std::sync::Arc; +pub(crate) mod futures; mod raw; -use self::raw::{RawRead, RawRwLock, RawUpgradableRead, RawUpgrade, RawWrite}; +use self::futures::{ + ArcUpgrade, Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, Write, WriteArc, +}; +use self::raw::{RawRwLock, RawUpgrade}; + /// An async reader-writer lock. /// /// This type of lock allows multiple readers or one writer at any point in time. @@ -59,6 +63,8 @@ impl RwLock { /// /// let lock = RwLock::new(0); /// ``` + #[must_use] + #[inline] pub const fn new(t: T) -> RwLock { RwLock { raw: RawRwLock::new(), @@ -76,10 +82,73 @@ impl RwLock { /// let lock = RwLock::new(5); /// assert_eq!(lock.into_inner(), 5); /// ``` + #[must_use] #[inline] pub fn into_inner(self) -> T { self.value.into_inner() } + + /// Attempts to acquire an an owned, reference-counted read lock. + /// + /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a + /// guard is returned that releases the lock when dropped. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::RwLock; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let reader = lock.read_arc().await; + /// assert_eq!(*reader, 1); + /// + /// assert!(lock.try_read_arc().is_some()); + /// # }) + /// ``` + #[inline] + pub fn try_read_arc(self: &Arc) -> Option> { + if self.raw.try_read() { + let arc = self.clone(); + + // SAFETY: we previously acquired a read lock. + Some(unsafe { ArcRwLockReadGuard::from_arc(arc) }) + } else { + None + } + } + + /// Acquires an owned, reference-counted read lock. + /// + /// Returns a guard that releases the lock when dropped. + /// + /// Note that attempts to acquire a read lock will block if there are also concurrent attempts + /// to acquire a write lock. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::RwLock; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let reader = lock.read_arc().await; + /// assert_eq!(*reader, 1); + /// + /// assert!(lock.try_read_arc().is_some()); + /// # }) + /// ``` + #[inline] + pub fn read_arc<'a>(self: &'a Arc) -> ReadArc<'a, T> { + ReadArc { + raw: self.raw.read(), + lock: self, + } + } } impl RwLock { @@ -179,7 +248,7 @@ impl RwLock { } } - /// Attempts to acquire a read lock with the possiblity to upgrade to a write lock. + /// Acquires a read lock with the possiblity to upgrade to a write lock. /// /// Returns a guard that releases the lock when dropped. /// @@ -213,6 +282,77 @@ impl RwLock { } } + /// Attempts to acquire an owned, reference-counted read lock with the possiblity to + /// upgrade to a write lock. + /// + /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a + /// guard is returned that releases the lock when dropped. + /// + /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there + /// can be at most one upgradable read lock at a time. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let reader = lock.upgradable_read_arc().await; + /// assert_eq!(*reader, 1); + /// assert_eq!(*lock.try_read_arc().unwrap(), 1); + /// + /// let mut writer = ArcRwLockUpgradableReadGuard::upgrade(reader).await; + /// *writer = 2; + /// # }) + /// ``` + #[inline] + pub fn try_upgradable_read_arc(self: &Arc) -> Option> { + if self.raw.try_upgradable_read() { + Some(ArcRwLockUpgradableReadGuard { lock: self.clone() }) + } else { + None + } + } + + /// Acquires an owned, reference-counted read lock with the possiblity + /// to upgrade to a write lock. + /// + /// Returns a guard that releases the lock when dropped. + /// + /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there + /// can be at most one upgradable read lock at a time. + /// + /// Note that attempts to acquire an upgradable read lock will block if there are concurrent + /// attempts to acquire another upgradable read lock or a write lock. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let reader = lock.upgradable_read_arc().await; + /// assert_eq!(*reader, 1); + /// assert_eq!(*lock.try_read_arc().unwrap(), 1); + /// + /// let mut writer = ArcRwLockUpgradableReadGuard::upgrade(reader).await; + /// *writer = 2; + /// # }) + /// ``` + #[inline] + pub fn upgradable_read_arc<'a>(self: &'a Arc) -> UpgradableReadArc<'a, T> { + UpgradableReadArc { + raw: self.raw.upgradable_read(), + lock: self, + } + } + /// Attempts to acquire a write lock. /// /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, a @@ -231,6 +371,7 @@ impl RwLock { /// assert!(lock.try_write().is_none()); /// # }) /// ``` + #[inline] pub fn try_write(&self) -> Option> { if self.raw.try_write() { Some(RwLockWriteGuard { @@ -258,6 +399,7 @@ impl RwLock { /// assert!(lock.try_read().is_none()); /// # }) /// ``` + #[inline] pub fn write(&self) -> Write<'_, T> { Write { raw: self.raw.write(), @@ -265,6 +407,59 @@ impl RwLock { } } + /// Attempts to acquire an owned, reference-counted write lock. + /// + /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, a + /// guard is returned that releases the lock when dropped. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::RwLock; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// assert!(lock.try_write_arc().is_some()); + /// let reader = lock.read_arc().await; + /// assert!(lock.try_write_arc().is_none()); + /// # }) + /// ``` + #[inline] + pub fn try_write_arc(self: &Arc) -> Option> { + if self.raw.try_write() { + Some(ArcRwLockWriteGuard { lock: self.clone() }) + } else { + None + } + } + + /// Acquires an owned, reference-counted write lock. + /// + /// Returns a guard that releases the lock when dropped. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::RwLock; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let writer = lock.write_arc().await; + /// assert!(lock.try_read_arc().is_none()); + /// # }) + /// ``` + #[inline] + pub fn write_arc<'a>(self: &'a Arc) -> WriteArc<'a, T> { + WriteArc { + raw: self.raw.write(), + lock: self, + } + } + /// Returns a mutable reference to the inner value. /// /// Since this call borrows the lock mutably, no actual locking takes place. The mutable borrow @@ -282,6 +477,8 @@ impl RwLock { /// assert_eq!(*lock.read().await, 2); /// # }) /// ``` + #[must_use] + #[inline] pub fn get_mut(&mut self) -> &mut T { unsafe { &mut *self.value.get() } } @@ -304,161 +501,143 @@ impl fmt::Debug for RwLock { } impl From for RwLock { + #[inline] fn from(val: T) -> RwLock { RwLock::new(val) } } impl Default for RwLock { + #[inline] fn default() -> RwLock { RwLock::new(Default::default()) } } -/// The future returned by [`RwLock::read`]. -pub struct Read<'a, T: ?Sized> { - /// Raw read lock acquisition future, doesn't depend on `T`. - raw: RawRead<'a>, +/// A guard that releases the read lock when dropped. +#[clippy::has_significant_drop] +pub struct RwLockReadGuard<'a, T: ?Sized> { + /// Reference to underlying locking implementation. + /// Doesn't depend on `T`. + lock: &'a RawRwLock, /// Pointer to the value protected by the lock. Covariant in `T`. value: *const T, } -unsafe impl Send for Read<'_, T> {} -unsafe impl Sync for Read<'_, T> {} +unsafe impl Send for RwLockReadGuard<'_, T> {} +unsafe impl Sync for RwLockReadGuard<'_, T> {} -impl fmt::Debug for Read<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("Read { .. }") +impl Drop for RwLockReadGuard<'_, T> { + #[inline] + fn drop(&mut self) { + // SAFETY: we are dropping a read guard. + unsafe { + self.lock.read_unlock(); + } } } -impl Unpin for Read<'_, T> {} - -impl<'a, T: ?Sized> Future for Read<'a, T> { - type Output = RwLockReadGuard<'a, T>; - +impl fmt::Debug for RwLockReadGuard<'_, T> { #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - ready!(Pin::new(&mut self.raw).poll(cx)); - - Poll::Ready(RwLockReadGuard { - lock: self.raw.lock, - value: self.value, - }) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) } } -/// The future returned by [`RwLock::upgradable_read`]. -pub struct UpgradableRead<'a, T: ?Sized> { - /// Raw upgradable read lock acquisition future, doesn't depend on `T`. - raw: RawUpgradableRead<'a>, - - /// Pointer to the value protected by the lock. Invariant in `T` - /// as the upgradable lock could provide write access. - value: *mut T, -} - -unsafe impl Send for UpgradableRead<'_, T> {} -unsafe impl Sync for UpgradableRead<'_, T> {} - -impl fmt::Debug for UpgradableRead<'_, T> { +impl fmt::Display for RwLockReadGuard<'_, T> { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("UpgradableRead { .. }") + (**self).fmt(f) } } -impl Unpin for UpgradableRead<'_, T> {} - -impl<'a, T: ?Sized> Future for UpgradableRead<'a, T> { - type Output = RwLockUpgradableReadGuard<'a, T>; +impl Deref for RwLockReadGuard<'_, T> { + type Target = T; #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - ready!(Pin::new(&mut self.raw).poll(cx)); - - Poll::Ready(RwLockUpgradableReadGuard { - lock: self.raw.lock, - value: self.value, - }) + fn deref(&self) -> &T { + unsafe { &*self.value } } } -/// The future returned by [`RwLock::write`]. -pub struct Write<'a, T: ?Sized> { - /// Raw write lock acquisition future, doesn't depend on `T`. - raw: RawWrite<'a>, - - /// Pointer to the value protected by the lock. Invariant in `T`. - value: *mut T, +/// An owned, reference-counting guard that releases the read lock when dropped. +#[clippy::has_significant_drop] +pub struct ArcRwLockReadGuard { + /// **WARNING**: This doesn't actually point to a `T`! + /// It points to a `RwLock`, via a pointer obtained with `Arc::into_raw`. + /// We lie for covariance. + lock: NonNull, } -unsafe impl Send for Write<'_, T> {} -unsafe impl Sync for Write<'_, T> {} +unsafe impl Send for ArcRwLockReadGuard {} +unsafe impl Sync for ArcRwLockReadGuard {} -impl fmt::Debug for Write<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("Write { .. }") +impl ArcRwLockReadGuard { + /// Constructs the underlying `Arc` back from the underlying `RwLock`. + /// + /// # Safety + /// + /// Both the returned `Arc` and the guard will decrement their reference + /// counts on drop! So one of the two must be forgotten. + #[inline] + unsafe fn inner_arc(guard: &Self) -> Arc> { + Arc::from_raw(guard.lock.as_ptr().cast()) } -} - -impl Unpin for Write<'_, T> {} - -impl<'a, T: ?Sized> Future for Write<'a, T> { - type Output = RwLockWriteGuard<'a, T>; + /// Constructs a guard from the underlying `Arc`. + /// + /// # Safety + /// + /// A read lock must be acquired before calling this. #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - ready!(Pin::new(&mut self.raw).poll(cx)); + unsafe fn from_arc(arc: Arc>) -> Self { + let ptr = Arc::into_raw(arc); - Poll::Ready(RwLockWriteGuard { - lock: self.raw.lock, - value: self.value, - }) + Self { + lock: NonNull::new(ptr as *mut RwLock as *mut T).unwrap(), + } } } -/// A guard that releases the read lock when dropped. -#[clippy::has_significant_drop] -pub struct RwLockReadGuard<'a, T: ?Sized> { - /// Reference to underlying locking implementation. - /// Doesn't depend on `T`. - lock: &'a RawRwLock, - - /// Pointer to the value protected by the lock. Covariant in `T`. - value: *const T, -} - -unsafe impl Send for RwLockReadGuard<'_, T> {} -unsafe impl Sync for RwLockReadGuard<'_, T> {} - -impl Drop for RwLockReadGuard<'_, T> { +impl Drop for ArcRwLockReadGuard { #[inline] fn drop(&mut self) { - // SAFETY: we are dropping a read guard. + // SAFETY: we are in `drop`, decrementing the reference count + // on purpose. + // We hold a read lock on the `RwLock`. unsafe { - self.lock.read_unlock(); + let arc = Self::inner_arc(self); + arc.raw.read_unlock(); } } } -impl fmt::Debug for RwLockReadGuard<'_, T> { +impl fmt::Debug for ArcRwLockReadGuard { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -impl fmt::Display for RwLockReadGuard<'_, T> { +impl fmt::Display for ArcRwLockReadGuard { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } -impl Deref for RwLockReadGuard<'_, T> { +impl Deref for ArcRwLockReadGuard { type Target = T; + #[inline] fn deref(&self) -> &T { - unsafe { &*self.value } + // SAFETY: we use `ManuallyDrop` to avoid double-drop. + // We hold a read lock on the `RwLock`. + unsafe { + let arc = ManuallyDrop::new(Self::inner_arc(self)); + &*arc.value.get() + } } } @@ -595,12 +774,14 @@ impl<'a, T: ?Sized> RwLockUpgradableReadGuard<'a, T> { } impl fmt::Debug for RwLockUpgradableReadGuard<'_, T> { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl fmt::Display for RwLockUpgradableReadGuard<'_, T> { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } @@ -609,39 +790,170 @@ impl fmt::Display for RwLockUpgradableReadGuard<'_, T> impl Deref for RwLockUpgradableReadGuard<'_, T> { type Target = T; + #[inline] fn deref(&self) -> &T { unsafe { &*self.value } } } -/// The future returned by [`RwLockUpgradableReadGuard::upgrade`]. -pub struct Upgrade<'a, T: ?Sized> { - /// Raw read lock upgrade future, doesn't depend on `T`. - raw: RawUpgrade<'a>, +/// An owned, reference-counting guard that releases the upgradable read lock when dropped. +#[clippy::has_significant_drop] +pub struct ArcRwLockUpgradableReadGuard { + /// We want invariance, so no need for pointer tricks. + lock: Arc>, +} - /// Pointer to the value protected by the lock. Invariant in `T`. - value: *mut T, +impl Drop for ArcRwLockUpgradableReadGuard { + #[inline] + fn drop(&mut self) { + // SAFETY: we are dropping an upgradable read guard. + unsafe { + self.lock.raw.upgradable_read_unlock(); + } + } } -impl fmt::Debug for Upgrade<'_, T> { +unsafe impl Send for ArcRwLockUpgradableReadGuard {} +unsafe impl Sync for ArcRwLockUpgradableReadGuard {} + +impl fmt::Debug for ArcRwLockUpgradableReadGuard { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Upgrade").finish() + fmt::Debug::fmt(&**self, f) + } +} + +impl fmt::Display for ArcRwLockUpgradableReadGuard { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl Deref for ArcRwLockUpgradableReadGuard { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.lock.value.get() } + } +} + +impl ArcRwLockUpgradableReadGuard { + /// Downgrades into a regular reader guard. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let reader = lock.upgradable_read_arc().await; + /// assert_eq!(*reader, 1); + /// + /// assert!(lock.try_upgradable_read_arc().is_none()); + /// + /// let reader = ArcRwLockUpgradableReadGuard::downgrade(reader); + /// + /// assert!(lock.try_upgradable_read_arc().is_some()); + /// # }) + /// ``` + #[inline] + pub fn downgrade(guard: Self) -> ArcRwLockReadGuard { + // SAFETY: we hold an upgradable read lock, which we are downgrading. + unsafe { + guard.lock.raw.downgrade_upgradable_read(); + } + + // SAFETY: we just downgraded to a read lock. + unsafe { ArcRwLockReadGuard::from_arc(Self::into_arc(guard)) } } } -impl Unpin for Upgrade<'_, T> {} +impl ArcRwLockUpgradableReadGuard { + /// Consumes the lock (without dropping) and returns the underlying `Arc`. + #[inline] + fn into_arc(guard: Self) -> Arc> { + let guard = ManuallyDrop::new(guard); + // SAFETY: `guard` is not used after this + unsafe { ptr::read(&guard.lock) } + } -impl<'a, T: ?Sized> Future for Upgrade<'a, T> { - type Output = RwLockWriteGuard<'a, T>; + /// Attempts to upgrade into a write lock. + /// + /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, + /// an upgraded guard is returned that releases the write lock when dropped. + /// + /// This function can only fail if there are other active read locks. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let reader = lock.upgradable_read_arc().await; + /// assert_eq!(*reader, 1); + /// + /// let reader2 = lock.read_arc().await; + /// let reader = ArcRwLockUpgradableReadGuard::try_upgrade(reader).unwrap_err(); + /// + /// drop(reader2); + /// let writer = ArcRwLockUpgradableReadGuard::try_upgrade(reader).unwrap(); + /// # }) + /// ``` + #[inline] + pub fn try_upgrade(guard: Self) -> Result, Self> { + // SAFETY: We hold an upgradable read guard. + if unsafe { guard.lock.raw.try_upgrade() } { + Ok(ArcRwLockWriteGuard { + lock: Self::into_arc(guard), + }) + } else { + Err(guard) + } + } + /// Upgrades into a write lock. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let reader = lock.upgradable_read_arc().await; + /// assert_eq!(*reader, 1); + /// + /// let mut writer = ArcRwLockUpgradableReadGuard::upgrade(reader).await; + /// *writer = 2; + /// # }) + /// ``` #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let lock = ready!(Pin::new(&mut self.raw).poll(cx)); + pub fn upgrade(guard: Self) -> ArcUpgrade { + // We need to do some ugly lying about lifetimes; + // See the comment on the `raw` field of `ArcUpgrade` + // for an explanation. + + // SAFETY: we hold an upgradable read guard. + let raw: RawUpgrade<'_> = unsafe { guard.lock.raw.upgrade() }; + + // SAFETY: see above explanation. + let raw: RawUpgrade<'static> = unsafe { mem::transmute(raw) }; - Poll::Ready(RwLockWriteGuard { - lock, - value: self.value, - }) + ArcUpgrade { + raw, + lock: ManuallyDrop::new(Self::into_arc(guard)), + } } } @@ -748,12 +1060,14 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { } impl fmt::Debug for RwLockWriteGuard<'_, T> { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl fmt::Display for RwLockWriteGuard<'_, T> { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } @@ -762,13 +1076,146 @@ impl fmt::Display for RwLockWriteGuard<'_, T> { impl Deref for RwLockWriteGuard<'_, T> { type Target = T; + #[inline] fn deref(&self) -> &T { unsafe { &*self.value } } } impl DerefMut for RwLockWriteGuard<'_, T> { + #[inline] fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.value } } } + +/// An owned, reference-counted guard that releases the write lock when dropped. +#[clippy::has_significant_drop] +pub struct ArcRwLockWriteGuard { + lock: Arc>, +} + +unsafe impl Send for ArcRwLockWriteGuard {} +unsafe impl Sync for ArcRwLockWriteGuard {} + +impl Drop for ArcRwLockWriteGuard { + #[inline] + fn drop(&mut self) { + // SAFETY: we are dropping a write lock. + unsafe { + self.lock.raw.write_unlock(); + } + } +} + +impl ArcRwLockWriteGuard { + /// Downgrades into a regular reader guard. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::{RwLock, ArcRwLockWriteGuard}; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let mut writer = lock.write_arc().await; + /// *writer += 1; + /// + /// assert!(lock.try_read_arc().is_none()); + /// + /// let reader = ArcRwLockWriteGuard::downgrade(writer); + /// assert_eq!(*reader, 2); + /// + /// assert!(lock.try_read_arc().is_some()); + /// # }) + /// ``` + #[inline] + pub fn downgrade(guard: Self) -> ArcRwLockReadGuard { + // SAFETY: `write` is a write guard + unsafe { + guard.lock.raw.downgrade_write(); + } + + // SAFETY: we just downgraded to a read lock + unsafe { ArcRwLockReadGuard::from_arc(Self::into_arc(guard)) } + } +} + +impl ArcRwLockWriteGuard { + /// Consumes the lock (without dropping) and returns the underlying `Arc`. + #[inline] + fn into_arc(guard: Self) -> Arc> { + let guard = ManuallyDrop::new(guard); + // SAFETY: `guard` is not used after this + unsafe { ptr::read(&guard.lock) } + } + + /// Downgrades into an upgradable reader guard. + /// + /// # Examples + /// + /// ``` + /// # futures_lite::future::block_on(async { + /// use std::sync::Arc; + /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard, ArcRwLockWriteGuard}; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let mut writer = lock.write_arc().await; + /// *writer += 1; + /// + /// assert!(lock.try_read_arc().is_none()); + /// + /// let reader = ArcRwLockWriteGuard::downgrade_to_upgradable(writer); + /// assert_eq!(*reader, 2); + /// + /// assert!(lock.try_write_arc().is_none()); + /// assert!(lock.try_read_arc().is_some()); + /// + /// assert!(ArcRwLockUpgradableReadGuard::try_upgrade(reader).is_ok()) + /// # }) + /// ``` + #[inline] + pub fn downgrade_to_upgradable(guard: Self) -> ArcRwLockUpgradableReadGuard { + // SAFETY: `guard` is a write guard + unsafe { + guard.lock.raw.downgrade_to_upgradable(); + } + + ArcRwLockUpgradableReadGuard { + lock: Self::into_arc(guard), + } + } +} + +impl fmt::Debug for ArcRwLockWriteGuard { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl fmt::Display for ArcRwLockWriteGuard { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl Deref for ArcRwLockWriteGuard { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.lock.value.get() } + } +} + +impl DerefMut for ArcRwLockWriteGuard { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.lock.value.get() } + } +} diff --git a/src/rwlock/futures.rs b/src/rwlock/futures.rs new file mode 100644 index 0000000..c294749 --- /dev/null +++ b/src/rwlock/futures.rs @@ -0,0 +1,300 @@ +use std::fmt; +use std::future::Future; +use std::mem::ManuallyDrop; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; + +use super::raw::{RawRead, RawUpgradableRead, RawUpgrade, RawWrite}; +use super::{ + ArcRwLockReadGuard, ArcRwLockUpgradableReadGuard, ArcRwLockWriteGuard, RwLock, RwLockReadGuard, + RwLockUpgradableReadGuard, RwLockWriteGuard, +}; + +/// The future returned by [`RwLock::read`]. +pub struct Read<'a, T: ?Sized> { + /// Raw read lock acquisition future, doesn't depend on `T`. + pub(super) raw: RawRead<'a>, + + /// Pointer to the value protected by the lock. Covariant in `T`. + pub(super) value: *const T, +} + +unsafe impl Send for Read<'_, T> {} +unsafe impl Sync for Read<'_, T> {} + +impl fmt::Debug for Read<'_, T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Read { .. }") + } +} + +impl Unpin for Read<'_, T> {} + +impl<'a, T: ?Sized> Future for Read<'a, T> { + type Output = RwLockReadGuard<'a, T>; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ready!(Pin::new(&mut self.raw).poll(cx)); + + Poll::Ready(RwLockReadGuard { + lock: self.raw.lock, + value: self.value, + }) + } +} + +/// The future returned by [`RwLock::read_arc`]. +pub struct ReadArc<'a, T> { + /// Raw read lock acquisition future, doesn't depend on `T`. + pub(super) raw: RawRead<'a>, + + // FIXME: Could be covariant in T + pub(super) lock: &'a Arc>, +} + +unsafe impl Send for ReadArc<'_, T> {} +unsafe impl Sync for ReadArc<'_, T> {} + +impl fmt::Debug for ReadArc<'_, T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("ReadArc { .. }") + } +} + +impl Unpin for ReadArc<'_, T> {} + +impl<'a, T> Future for ReadArc<'a, T> { + type Output = ArcRwLockReadGuard; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ready!(Pin::new(&mut self.raw).poll(cx)); + + // SAFETY: we just acquired a read lock + Poll::Ready(unsafe { ArcRwLockReadGuard::from_arc(self.lock.clone()) }) + } +} + +/// The future returned by [`RwLock::upgradable_read`]. +pub struct UpgradableRead<'a, T: ?Sized> { + /// Raw upgradable read lock acquisition future, doesn't depend on `T`. + pub(super) raw: RawUpgradableRead<'a>, + + /// Pointer to the value protected by the lock. Invariant in `T` + /// as the upgradable lock could provide write access. + pub(super) value: *mut T, +} + +unsafe impl Send for UpgradableRead<'_, T> {} +unsafe impl Sync for UpgradableRead<'_, T> {} + +impl fmt::Debug for UpgradableRead<'_, T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("UpgradableRead { .. }") + } +} + +impl Unpin for UpgradableRead<'_, T> {} + +impl<'a, T: ?Sized> Future for UpgradableRead<'a, T> { + type Output = RwLockUpgradableReadGuard<'a, T>; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ready!(Pin::new(&mut self.raw).poll(cx)); + + Poll::Ready(RwLockUpgradableReadGuard { + lock: self.raw.lock, + value: self.value, + }) + } +} + +/// The future returned by [`RwLock::upgradable_read_arc`]. +pub struct UpgradableReadArc<'a, T: ?Sized> { + /// Raw upgradable read lock acquisition future, doesn't depend on `T`. + pub(super) raw: RawUpgradableRead<'a>, + + pub(super) lock: &'a Arc>, +} + +unsafe impl Send for UpgradableReadArc<'_, T> {} +unsafe impl Sync for UpgradableReadArc<'_, T> {} + +impl fmt::Debug for UpgradableReadArc<'_, T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("UpgradableReadArc { .. }") + } +} + +impl Unpin for UpgradableReadArc<'_, T> {} + +impl<'a, T: ?Sized> Future for UpgradableReadArc<'a, T> { + type Output = ArcRwLockUpgradableReadGuard; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ready!(Pin::new(&mut self.raw).poll(cx)); + Poll::Ready(ArcRwLockUpgradableReadGuard { + lock: self.lock.clone(), + }) + } +} + +/// The future returned by [`RwLock::write`]. +pub struct Write<'a, T: ?Sized> { + /// Raw write lock acquisition future, doesn't depend on `T`. + pub(super) raw: RawWrite<'a>, + + /// Pointer to the value protected by the lock. Invariant in `T`. + pub(super) value: *mut T, +} + +unsafe impl Send for Write<'_, T> {} +unsafe impl Sync for Write<'_, T> {} + +impl fmt::Debug for Write<'_, T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Write { .. }") + } +} + +impl Unpin for Write<'_, T> {} + +impl<'a, T: ?Sized> Future for Write<'a, T> { + type Output = RwLockWriteGuard<'a, T>; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ready!(Pin::new(&mut self.raw).poll(cx)); + + Poll::Ready(RwLockWriteGuard { + lock: self.raw.lock, + value: self.value, + }) + } +} + +/// The future returned by [`RwLock::write_arc`]. +pub struct WriteArc<'a, T: ?Sized> { + /// Raw write lock acquisition future, doesn't depend on `T`. + pub(super) raw: RawWrite<'a>, + + pub(super) lock: &'a Arc>, +} + +unsafe impl Send for WriteArc<'_, T> {} +unsafe impl Sync for WriteArc<'_, T> {} + +impl fmt::Debug for WriteArc<'_, T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("WriteArc { .. }") + } +} + +impl Unpin for WriteArc<'_, T> {} + +impl<'a, T: ?Sized> Future for WriteArc<'a, T> { + type Output = ArcRwLockWriteGuard; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ready!(Pin::new(&mut self.raw).poll(cx)); + + Poll::Ready(ArcRwLockWriteGuard { + lock: self.lock.clone(), + }) + } +} + +/// The future returned by [`RwLockUpgradableReadGuard::upgrade`]. +pub struct Upgrade<'a, T: ?Sized> { + /// Raw read lock upgrade future, doesn't depend on `T`. + pub(super) raw: RawUpgrade<'a>, + + /// Pointer to the value protected by the lock. Invariant in `T`. + pub(super) value: *mut T, +} + +impl fmt::Debug for Upgrade<'_, T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Upgrade").finish() + } +} + +impl Unpin for Upgrade<'_, T> {} + +impl<'a, T: ?Sized> Future for Upgrade<'a, T> { + type Output = RwLockWriteGuard<'a, T>; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let lock = ready!(Pin::new(&mut self.raw).poll(cx)); + + Poll::Ready(RwLockWriteGuard { + lock, + value: self.value, + }) + } +} + +/// The future returned by [`ArcRwLockUpgradableReadGuard::upgrade`]. +pub struct ArcUpgrade { + /// Raw read lock upgrade future, doesn't depend on `T`. + /// `'static` is a lie, this field is actually referencing the + /// `Arc` data. But since this struct also stores said `Arc`, we know + /// this value will be alive as long as the struct is. + /// + /// Yes, one field of the `ArcUpgrade` struct is referencing another. + /// Such self-references are usually not sound without pinning. + /// However, in this case, there is an indirection via the heap; + /// moving the `ArcUpgrade` won't move the heap allocation of the `Arc`, + /// so the reference inside `RawUpgrade` isn't invalidated. + pub(super) raw: RawUpgrade<'static>, + + /// Pointer to the value protected by the lock. Invariant in `T`. + pub(super) lock: ManuallyDrop>>, +} + +impl fmt::Debug for ArcUpgrade { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ArcUpgrade").finish() + } +} + +impl Unpin for ArcUpgrade {} + +impl Future for ArcUpgrade { + type Output = ArcRwLockWriteGuard; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ready!(Pin::new(&mut self.raw).poll(cx)); + + Poll::Ready(ArcRwLockWriteGuard { + lock: unsafe { ManuallyDrop::take(&mut self.lock) }, + }) + } +} + +impl Drop for ArcUpgrade { + #[inline] + fn drop(&mut self) { + if !self.raw.is_ready() { + // SAFETY: we drop the `Arc` (decrementing the reference count) + // only if this future was cancelled before returning an + // upgraded lock. + unsafe { ManuallyDrop::drop(&mut self.lock) }; + } + } +} diff --git a/src/rwlock/raw.rs b/src/rwlock/raw.rs index ade23e0..6dd4731 100644 --- a/src/rwlock/raw.rs +++ b/src/rwlock/raw.rs @@ -550,3 +550,11 @@ impl<'a> Drop for RawUpgrade<'a> { } } } + +impl<'a> RawUpgrade<'a> { + /// Whether the future returned `Poll::Ready(..)` at some point. + #[inline] + pub(super) fn is_ready(&self) -> bool { + self.lock.is_none() + } +} diff --git a/tests/rwlock.rs b/tests/rwlock.rs index 16685a2..7d19397 100644 --- a/tests/rwlock.rs +++ b/tests/rwlock.rs @@ -14,7 +14,10 @@ use std::thread; use futures_lite::future; -use async_lock::{RwLock, RwLockReadGuard, RwLockUpgradableReadGuard}; +use async_lock::{ + ArcRwLockReadGuard, ArcRwLockUpgradableReadGuard, RwLock, RwLockReadGuard, + RwLockUpgradableReadGuard, +}; #[cfg(target_family = "wasm")] use wasm_bindgen_test::wasm_bindgen_test as test; @@ -123,6 +126,40 @@ fn contention() { }); } +#[cfg(not(target_family = "wasm"))] +#[test] +fn contention_arc() { + const N: u32 = 10; + const M: usize = if cfg!(miri) { 100 } else { 1000 }; + + let (tx, rx) = async_channel::unbounded(); + let tx = Arc::new(tx); + let rw = Arc::new(RwLock::new(())); + + // Spawn N tasks that randomly acquire the lock M times. + for _ in 0..N { + let tx = tx.clone(); + let rw = rw.clone(); + + spawn(async move { + for _ in 0..M { + if fastrand::u32(..N) == 0 { + drop(rw.write_arc().await); + } else { + drop(rw.read_arc().await); + } + } + tx.send(()).await.unwrap(); + }); + } + + future::block_on(async move { + for _ in 0..N { + rx.recv().await.unwrap(); + } + }); +} + #[cfg(not(target_family = "wasm"))] #[test] fn writer_and_readers() { @@ -169,6 +206,52 @@ fn writer_and_readers() { }); } +#[cfg(not(target_family = "wasm"))] +#[test] +fn writer_and_readers_arc() { + let lock = Arc::new(RwLock::new(0i32)); + let (tx, rx) = async_channel::unbounded(); + + // Spawn a writer task. + spawn({ + let lock = lock.clone(); + async move { + let mut lock = lock.write_arc().await; + for _ in 0..1000 { + let tmp = *lock; + *lock = -1; + future::yield_now().await; + *lock = tmp + 1; + } + tx.send(()).await.unwrap(); + } + }); + + // Readers try to catch the writer in the act. + let mut readers = Vec::new(); + for _ in 0..5 { + let lock = lock.clone(); + readers.push(spawn(async move { + for _ in 0..1000 { + let lock = lock.read_arc().await; + assert!(*lock >= 0); + } + })); + } + + future::block_on(async move { + // Wait for readers to pass their asserts. + for r in readers { + r.await; + } + + // Wait for writer to finish. + rx.recv().await.unwrap(); + let lock = lock.read_arc().await; + assert_eq!(*lock, 1000); + }); +} + #[test] fn upgrade() { future::block_on(async { @@ -199,6 +282,36 @@ fn upgrade() { }); } +#[test] +fn upgrade_arc() { + future::block_on(async { + let lock: Arc> = Arc::new(RwLock::new(0)); + + let read_guard = lock.read_arc().await; + let read_guard2 = lock.read_arc().await; + // Should be able to obtain an upgradable lock. + let upgradable_guard = lock.upgradable_read_arc().await; + // Should be able to obtain a read lock when an upgradable lock is active. + let read_guard3 = lock.read_arc().await; + assert_eq!(0, *read_guard3); + drop(read_guard); + drop(read_guard2); + drop(read_guard3); + + // Writers should not pass. + assert!(lock.try_write().is_none()); + + let mut write_guard = ArcRwLockUpgradableReadGuard::try_upgrade(upgradable_guard).expect( + "should be able to upgrade an upgradable lock because there are no more readers", + ); + *write_guard += 1; + drop(write_guard); + + let read_guard = lock.read_arc().await; + assert_eq!(1, *read_guard) + }); +} + #[test] fn not_upgrade() { future::block_on(async { @@ -230,6 +343,37 @@ fn not_upgrade() { }); } +#[test] +fn not_upgrade_arc() { + future::block_on(async { + let mutex: Arc> = Arc::new(RwLock::new(0)); + + let read_guard = mutex.read_arc().await; + let read_guard2 = mutex.read_arc().await; + // Should be able to obtain an upgradable lock. + let upgradable_guard = mutex.upgradable_read_arc().await; + // Should be able to obtain a shared lock when an upgradable lock is active. + let read_guard3 = mutex.read_arc().await; + assert_eq!(0, *read_guard3); + drop(read_guard); + drop(read_guard2); + drop(read_guard3); + + // Drop the upgradable lock. + drop(upgradable_guard); + + assert_eq!(0, *(mutex.read_arc().await)); + + // Should be able to acquire a write lock because there are no more readers. + let mut write_guard = mutex.write_arc().await; + *write_guard += 1; + drop(write_guard); + + let read_guard = mutex.read_arc().await; + assert_eq!(1, *read_guard) + }); +} + #[test] fn upgradable_with_concurrent_writer() { future::block_on(async { @@ -258,6 +402,34 @@ fn upgradable_with_concurrent_writer() { }); } +#[test] +fn upgradable_with_concurrent_writer_arc() { + future::block_on(async { + let lock: Arc> = Arc::new(RwLock::new(0)); + let lock2 = lock.clone(); + + let upgradable_guard = lock.upgradable_read_arc().await; + + future::or( + async move { + let mut write_guard = lock2.write_arc().await; + *write_guard = 1; + }, + async move { + let mut write_guard = ArcRwLockUpgradableReadGuard::upgrade(upgradable_guard).await; + assert_eq!(*write_guard, 0); + *write_guard = 2; + }, + ) + .await; + + assert_eq!(2, *(lock.write_arc().await)); + + let read_guard = lock.read_arc().await; + assert_eq!(2, *read_guard); + }); +} + #[test] fn yields_when_contended() { let rw = RwLock::new(()); @@ -278,6 +450,29 @@ fn yields_when_contended() { ); } +#[test] +fn yields_when_contended_arc() { + let rw = Arc::new(RwLock::new(())); + + check_yields_when_contended(rw.try_write_arc().unwrap(), rw.read_arc()); + check_yields_when_contended(rw.try_write_arc().unwrap(), rw.upgradable_read_arc()); + check_yields_when_contended(rw.try_write_arc().unwrap(), rw.write_arc()); + + check_yields_when_contended(rw.try_read_arc().unwrap(), rw.write_arc()); + + check_yields_when_contended(rw.try_upgradable_read_arc().unwrap(), rw.write_arc()); + check_yields_when_contended( + rw.try_upgradable_read_arc().unwrap(), + rw.upgradable_read_arc(), + ); + + let upgradable = rw.try_upgradable_read_arc().unwrap(); + check_yields_when_contended( + rw.try_read_arc().unwrap(), + ArcRwLockUpgradableReadGuard::upgrade(upgradable), + ); +} + #[test] fn cancellation() { future::block_on(async { @@ -307,7 +502,59 @@ fn cancellation() { }); } +#[test] +fn arc_rwlock_refcounts() { + future::block_on(async { + let rw = Arc::new(RwLock::new(())); + assert_eq!(Arc::strong_count(&rw), 1); + + drop(rw.read_arc()); + assert_eq!(Arc::strong_count(&rw), 1); + + drop(rw.upgradable_read_arc()); + assert_eq!(Arc::strong_count(&rw), 1); + + drop(rw.write()); + assert_eq!(Arc::strong_count(&rw), 1); + + let read = rw.read_arc().await; + assert_eq!(Arc::strong_count(&rw), 2); + drop(read); + assert_eq!(Arc::strong_count(&rw), 1); + + let upgradable_read = rw.upgradable_read_arc().await; + assert_eq!(Arc::strong_count(&rw), 2); + drop(upgradable_read); + assert_eq!(Arc::strong_count(&rw), 1); + + let write = rw.write_arc().await; + assert_eq!(Arc::strong_count(&rw), 2); + drop(write); + assert_eq!(Arc::strong_count(&rw), 1); + + let upgradable_read = rw.upgradable_read_arc().await; + assert_eq!(Arc::strong_count(&rw), 2); + drop(ArcRwLockUpgradableReadGuard::upgrade(upgradable_read)); + assert_eq!(Arc::strong_count(&rw), 1); + + let upgradable_read = rw.upgradable_read_arc().await; + assert_eq!(Arc::strong_count(&rw), 2); + let write = ArcRwLockUpgradableReadGuard::upgrade(upgradable_read).await; + assert_eq!(Arc::strong_count(&rw), 2); + drop(write); + assert_eq!(Arc::strong_count(&rw), 1); + }); +} + // We are testing that this compiles. fn _covariance_test<'g>(guard: RwLockReadGuard<'g, &'static ()>) { let _: RwLockReadGuard<'g, &'g ()> = guard; } + +// We are testing that this compiles. +fn _covariance_test_arc( + guard: ArcRwLockReadGuard<&'static ()>, + mut _guard_2: ArcRwLockReadGuard<&()>, +) { + _guard_2 = guard; +} From e26614e5e8a33e16ec3ee502407ad23485bb02b9 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 3 Jun 2023 12:48:19 -0400 Subject: [PATCH 2/2] Address review comments --- src/lib.rs | 6 +- src/rwlock.rs | 130 +++++++++++++++++++++--------------------- src/rwlock/futures.rs | 41 +++++++------ tests/rwlock.rs | 18 +++--- 4 files changed, 99 insertions(+), 96 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dbf81c0..95562b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,8 +48,8 @@ pub use barrier::{Barrier, BarrierWaitResult}; pub use mutex::{Mutex, MutexGuard, MutexGuardArc}; pub use once_cell::OnceCell; pub use rwlock::{ - ArcRwLockReadGuard, ArcRwLockUpgradableReadGuard, ArcRwLockWriteGuard, RwLock, RwLockReadGuard, - RwLockUpgradableReadGuard, RwLockWriteGuard, + RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard, + RwLockUpgradableReadGuardArc, RwLockWriteGuard, RwLockWriteGuardArc, }; pub use semaphore::{Semaphore, SemaphoreGuard, SemaphoreGuardArc}; @@ -59,7 +59,7 @@ pub mod futures { pub use crate::barrier::BarrierWait; pub use crate::mutex::{Lock, LockArc}; pub use crate::rwlock::futures::{ - ArcUpgrade, Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, Write, WriteArc, + Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, UpgradeArc, Write, WriteArc, }; pub use crate::semaphore::{Acquire, AcquireArc}; } diff --git a/src/rwlock.rs b/src/rwlock.rs index c8a8b1d..49222f6 100644 --- a/src/rwlock.rs +++ b/src/rwlock.rs @@ -9,7 +9,7 @@ pub(crate) mod futures; mod raw; use self::futures::{ - ArcUpgrade, Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, Write, WriteArc, + Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, UpgradeArc, Write, WriteArc, }; use self::raw::{RawRwLock, RawUpgrade}; @@ -109,12 +109,12 @@ impl RwLock { /// # }) /// ``` #[inline] - pub fn try_read_arc(self: &Arc) -> Option> { + pub fn try_read_arc(self: &Arc) -> Option> { if self.raw.try_read() { let arc = self.clone(); // SAFETY: we previously acquired a read lock. - Some(unsafe { ArcRwLockReadGuard::from_arc(arc) }) + Some(unsafe { RwLockReadGuardArc::from_arc(arc) }) } else { None } @@ -296,7 +296,7 @@ impl RwLock { /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; - /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// @@ -304,14 +304,14 @@ impl RwLock { /// assert_eq!(*reader, 1); /// assert_eq!(*lock.try_read_arc().unwrap(), 1); /// - /// let mut writer = ArcRwLockUpgradableReadGuard::upgrade(reader).await; + /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` #[inline] - pub fn try_upgradable_read_arc(self: &Arc) -> Option> { + pub fn try_upgradable_read_arc(self: &Arc) -> Option> { if self.raw.try_upgradable_read() { - Some(ArcRwLockUpgradableReadGuard { lock: self.clone() }) + Some(RwLockUpgradableReadGuardArc { lock: self.clone() }) } else { None } @@ -333,7 +333,7 @@ impl RwLock { /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; - /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// @@ -341,7 +341,7 @@ impl RwLock { /// assert_eq!(*reader, 1); /// assert_eq!(*lock.try_read_arc().unwrap(), 1); /// - /// let mut writer = ArcRwLockUpgradableReadGuard::upgrade(reader).await; + /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` @@ -427,9 +427,9 @@ impl RwLock { /// # }) /// ``` #[inline] - pub fn try_write_arc(self: &Arc) -> Option> { + pub fn try_write_arc(self: &Arc) -> Option> { if self.raw.try_write() { - Some(ArcRwLockWriteGuard { lock: self.clone() }) + Some(RwLockWriteGuardArc { lock: self.clone() }) } else { None } @@ -563,17 +563,17 @@ impl Deref for RwLockReadGuard<'_, T> { /// An owned, reference-counting guard that releases the read lock when dropped. #[clippy::has_significant_drop] -pub struct ArcRwLockReadGuard { +pub struct RwLockReadGuardArc { /// **WARNING**: This doesn't actually point to a `T`! /// It points to a `RwLock`, via a pointer obtained with `Arc::into_raw`. /// We lie for covariance. lock: NonNull, } -unsafe impl Send for ArcRwLockReadGuard {} -unsafe impl Sync for ArcRwLockReadGuard {} +unsafe impl Send for RwLockReadGuardArc {} +unsafe impl Sync for RwLockReadGuardArc {} -impl ArcRwLockReadGuard { +impl RwLockReadGuardArc { /// Constructs the underlying `Arc` back from the underlying `RwLock`. /// /// # Safety @@ -581,8 +581,8 @@ impl ArcRwLockReadGuard { /// Both the returned `Arc` and the guard will decrement their reference /// counts on drop! So one of the two must be forgotten. #[inline] - unsafe fn inner_arc(guard: &Self) -> Arc> { - Arc::from_raw(guard.lock.as_ptr().cast()) + unsafe fn inner_arc(guard: &Self) -> ManuallyDrop>> { + ManuallyDrop::new(Arc::from_raw(guard.lock.as_ptr().cast())) } /// Constructs a guard from the underlying `Arc`. @@ -600,34 +600,34 @@ impl ArcRwLockReadGuard { } } -impl Drop for ArcRwLockReadGuard { +impl Drop for RwLockReadGuardArc { #[inline] fn drop(&mut self) { // SAFETY: we are in `drop`, decrementing the reference count // on purpose. // We hold a read lock on the `RwLock`. unsafe { - let arc = Self::inner_arc(self); + let arc = ManuallyDrop::into_inner(Self::inner_arc(self)); arc.raw.read_unlock(); } } } -impl fmt::Debug for ArcRwLockReadGuard { +impl fmt::Debug for RwLockReadGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -impl fmt::Display for ArcRwLockReadGuard { +impl fmt::Display for RwLockReadGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } -impl Deref for ArcRwLockReadGuard { +impl Deref for RwLockReadGuardArc { type Target = T; #[inline] @@ -635,7 +635,7 @@ impl Deref for ArcRwLockReadGuard { // SAFETY: we use `ManuallyDrop` to avoid double-drop. // We hold a read lock on the `RwLock`. unsafe { - let arc = ManuallyDrop::new(Self::inner_arc(self)); + let arc = Self::inner_arc(self); &*arc.value.get() } } @@ -798,12 +798,12 @@ impl Deref for RwLockUpgradableReadGuard<'_, T> { /// An owned, reference-counting guard that releases the upgradable read lock when dropped. #[clippy::has_significant_drop] -pub struct ArcRwLockUpgradableReadGuard { +pub struct RwLockUpgradableReadGuardArc { /// We want invariance, so no need for pointer tricks. lock: Arc>, } -impl Drop for ArcRwLockUpgradableReadGuard { +impl Drop for RwLockUpgradableReadGuardArc { #[inline] fn drop(&mut self) { // SAFETY: we are dropping an upgradable read guard. @@ -813,24 +813,24 @@ impl Drop for ArcRwLockUpgradableReadGuard { } } -unsafe impl Send for ArcRwLockUpgradableReadGuard {} -unsafe impl Sync for ArcRwLockUpgradableReadGuard {} +unsafe impl Send for RwLockUpgradableReadGuardArc {} +unsafe impl Sync for RwLockUpgradableReadGuardArc {} -impl fmt::Debug for ArcRwLockUpgradableReadGuard { +impl fmt::Debug for RwLockUpgradableReadGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -impl fmt::Display for ArcRwLockUpgradableReadGuard { +impl fmt::Display for RwLockUpgradableReadGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } -impl Deref for ArcRwLockUpgradableReadGuard { +impl Deref for RwLockUpgradableReadGuardArc { type Target = T; #[inline] @@ -839,7 +839,7 @@ impl Deref for ArcRwLockUpgradableReadGuard { } } -impl ArcRwLockUpgradableReadGuard { +impl RwLockUpgradableReadGuardArc { /// Downgrades into a regular reader guard. /// /// # Examples @@ -847,7 +847,7 @@ impl ArcRwLockUpgradableReadGuard { /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; - /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// @@ -856,24 +856,24 @@ impl ArcRwLockUpgradableReadGuard { /// /// assert!(lock.try_upgradable_read_arc().is_none()); /// - /// let reader = ArcRwLockUpgradableReadGuard::downgrade(reader); + /// let reader = RwLockUpgradableReadGuardArc::downgrade(reader); /// /// assert!(lock.try_upgradable_read_arc().is_some()); /// # }) /// ``` #[inline] - pub fn downgrade(guard: Self) -> ArcRwLockReadGuard { + pub fn downgrade(guard: Self) -> RwLockReadGuardArc { // SAFETY: we hold an upgradable read lock, which we are downgrading. unsafe { guard.lock.raw.downgrade_upgradable_read(); } // SAFETY: we just downgraded to a read lock. - unsafe { ArcRwLockReadGuard::from_arc(Self::into_arc(guard)) } + unsafe { RwLockReadGuardArc::from_arc(Self::into_arc(guard)) } } } -impl ArcRwLockUpgradableReadGuard { +impl RwLockUpgradableReadGuardArc { /// Consumes the lock (without dropping) and returns the underlying `Arc`. #[inline] fn into_arc(guard: Self) -> Arc> { @@ -894,7 +894,7 @@ impl ArcRwLockUpgradableReadGuard { /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; - /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// @@ -902,17 +902,17 @@ impl ArcRwLockUpgradableReadGuard { /// assert_eq!(*reader, 1); /// /// let reader2 = lock.read_arc().await; - /// let reader = ArcRwLockUpgradableReadGuard::try_upgrade(reader).unwrap_err(); + /// let reader = RwLockUpgradableReadGuardArc::try_upgrade(reader).unwrap_err(); /// /// drop(reader2); - /// let writer = ArcRwLockUpgradableReadGuard::try_upgrade(reader).unwrap(); + /// let writer = RwLockUpgradableReadGuardArc::try_upgrade(reader).unwrap(); /// # }) /// ``` #[inline] - pub fn try_upgrade(guard: Self) -> Result, Self> { + pub fn try_upgrade(guard: Self) -> Result, Self> { // SAFETY: We hold an upgradable read guard. if unsafe { guard.lock.raw.try_upgrade() } { - Ok(ArcRwLockWriteGuard { + Ok(RwLockWriteGuardArc { lock: Self::into_arc(guard), }) } else { @@ -927,19 +927,19 @@ impl ArcRwLockUpgradableReadGuard { /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; - /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard}; + /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// /// let reader = lock.upgradable_read_arc().await; /// assert_eq!(*reader, 1); /// - /// let mut writer = ArcRwLockUpgradableReadGuard::upgrade(reader).await; + /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; /// *writer = 2; /// # }) /// ``` #[inline] - pub fn upgrade(guard: Self) -> ArcUpgrade { + pub fn upgrade(guard: Self) -> UpgradeArc { // We need to do some ugly lying about lifetimes; // See the comment on the `raw` field of `ArcUpgrade` // for an explanation. @@ -950,8 +950,8 @@ impl ArcRwLockUpgradableReadGuard { // SAFETY: see above explanation. let raw: RawUpgrade<'static> = unsafe { mem::transmute(raw) }; - ArcUpgrade { - raw, + UpgradeArc { + raw: ManuallyDrop::new(raw), lock: ManuallyDrop::new(Self::into_arc(guard)), } } @@ -1091,14 +1091,14 @@ impl DerefMut for RwLockWriteGuard<'_, T> { /// An owned, reference-counted guard that releases the write lock when dropped. #[clippy::has_significant_drop] -pub struct ArcRwLockWriteGuard { +pub struct RwLockWriteGuardArc { lock: Arc>, } -unsafe impl Send for ArcRwLockWriteGuard {} -unsafe impl Sync for ArcRwLockWriteGuard {} +unsafe impl Send for RwLockWriteGuardArc {} +unsafe impl Sync for RwLockWriteGuardArc {} -impl Drop for ArcRwLockWriteGuard { +impl Drop for RwLockWriteGuardArc { #[inline] fn drop(&mut self) { // SAFETY: we are dropping a write lock. @@ -1108,7 +1108,7 @@ impl Drop for ArcRwLockWriteGuard { } } -impl ArcRwLockWriteGuard { +impl RwLockWriteGuardArc { /// Downgrades into a regular reader guard. /// /// # Examples @@ -1116,7 +1116,7 @@ impl ArcRwLockWriteGuard { /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; - /// use async_lock::{RwLock, ArcRwLockWriteGuard}; + /// use async_lock::{RwLock, RwLockWriteGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// @@ -1125,25 +1125,25 @@ impl ArcRwLockWriteGuard { /// /// assert!(lock.try_read_arc().is_none()); /// - /// let reader = ArcRwLockWriteGuard::downgrade(writer); + /// let reader = RwLockWriteGuardArc::downgrade(writer); /// assert_eq!(*reader, 2); /// /// assert!(lock.try_read_arc().is_some()); /// # }) /// ``` #[inline] - pub fn downgrade(guard: Self) -> ArcRwLockReadGuard { + pub fn downgrade(guard: Self) -> RwLockReadGuardArc { // SAFETY: `write` is a write guard unsafe { guard.lock.raw.downgrade_write(); } // SAFETY: we just downgraded to a read lock - unsafe { ArcRwLockReadGuard::from_arc(Self::into_arc(guard)) } + unsafe { RwLockReadGuardArc::from_arc(Self::into_arc(guard)) } } } -impl ArcRwLockWriteGuard { +impl RwLockWriteGuardArc { /// Consumes the lock (without dropping) and returns the underlying `Arc`. #[inline] fn into_arc(guard: Self) -> Arc> { @@ -1159,7 +1159,7 @@ impl ArcRwLockWriteGuard { /// ``` /// # futures_lite::future::block_on(async { /// use std::sync::Arc; - /// use async_lock::{RwLock, ArcRwLockUpgradableReadGuard, ArcRwLockWriteGuard}; + /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc, RwLockWriteGuardArc}; /// /// let lock = Arc::new(RwLock::new(1)); /// @@ -1168,43 +1168,43 @@ impl ArcRwLockWriteGuard { /// /// assert!(lock.try_read_arc().is_none()); /// - /// let reader = ArcRwLockWriteGuard::downgrade_to_upgradable(writer); + /// let reader = RwLockWriteGuardArc::downgrade_to_upgradable(writer); /// assert_eq!(*reader, 2); /// /// assert!(lock.try_write_arc().is_none()); /// assert!(lock.try_read_arc().is_some()); /// - /// assert!(ArcRwLockUpgradableReadGuard::try_upgrade(reader).is_ok()) + /// assert!(RwLockUpgradableReadGuardArc::try_upgrade(reader).is_ok()) /// # }) /// ``` #[inline] - pub fn downgrade_to_upgradable(guard: Self) -> ArcRwLockUpgradableReadGuard { + pub fn downgrade_to_upgradable(guard: Self) -> RwLockUpgradableReadGuardArc { // SAFETY: `guard` is a write guard unsafe { guard.lock.raw.downgrade_to_upgradable(); } - ArcRwLockUpgradableReadGuard { + RwLockUpgradableReadGuardArc { lock: Self::into_arc(guard), } } } -impl fmt::Debug for ArcRwLockWriteGuard { +impl fmt::Debug for RwLockWriteGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -impl fmt::Display for ArcRwLockWriteGuard { +impl fmt::Display for RwLockWriteGuardArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } -impl Deref for ArcRwLockWriteGuard { +impl Deref for RwLockWriteGuardArc { type Target = T; #[inline] @@ -1213,7 +1213,7 @@ impl Deref for ArcRwLockWriteGuard { } } -impl DerefMut for ArcRwLockWriteGuard { +impl DerefMut for RwLockWriteGuardArc { #[inline] fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.lock.value.get() } diff --git a/src/rwlock/futures.rs b/src/rwlock/futures.rs index c294749..73fbc17 100644 --- a/src/rwlock/futures.rs +++ b/src/rwlock/futures.rs @@ -7,8 +7,8 @@ use std::task::{Context, Poll}; use super::raw::{RawRead, RawUpgradableRead, RawUpgrade, RawWrite}; use super::{ - ArcRwLockReadGuard, ArcRwLockUpgradableReadGuard, ArcRwLockWriteGuard, RwLock, RwLockReadGuard, - RwLockUpgradableReadGuard, RwLockWriteGuard, + RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard, + RwLockUpgradableReadGuardArc, RwLockWriteGuard, RwLockWriteGuardArc, }; /// The future returned by [`RwLock::read`]. @@ -68,14 +68,14 @@ impl fmt::Debug for ReadArc<'_, T> { impl Unpin for ReadArc<'_, T> {} impl<'a, T> Future for ReadArc<'a, T> { - type Output = ArcRwLockReadGuard; + type Output = RwLockReadGuardArc; #[inline] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { ready!(Pin::new(&mut self.raw).poll(cx)); // SAFETY: we just acquired a read lock - Poll::Ready(unsafe { ArcRwLockReadGuard::from_arc(self.lock.clone()) }) + Poll::Ready(unsafe { RwLockReadGuardArc::from_arc(self.lock.clone()) }) } } @@ -136,12 +136,12 @@ impl fmt::Debug for UpgradableReadArc<'_, T> { impl Unpin for UpgradableReadArc<'_, T> {} impl<'a, T: ?Sized> Future for UpgradableReadArc<'a, T> { - type Output = ArcRwLockUpgradableReadGuard; + type Output = RwLockUpgradableReadGuardArc; #[inline] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { ready!(Pin::new(&mut self.raw).poll(cx)); - Poll::Ready(ArcRwLockUpgradableReadGuard { + Poll::Ready(RwLockUpgradableReadGuardArc { lock: self.lock.clone(), }) } @@ -203,13 +203,13 @@ impl fmt::Debug for WriteArc<'_, T> { impl Unpin for WriteArc<'_, T> {} impl<'a, T: ?Sized> Future for WriteArc<'a, T> { - type Output = ArcRwLockWriteGuard; + type Output = RwLockWriteGuardArc; #[inline] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { ready!(Pin::new(&mut self.raw).poll(cx)); - Poll::Ready(ArcRwLockWriteGuard { + Poll::Ready(RwLockWriteGuardArc { lock: self.lock.clone(), }) } @@ -247,8 +247,8 @@ impl<'a, T: ?Sized> Future for Upgrade<'a, T> { } } -/// The future returned by [`ArcRwLockUpgradableReadGuard::upgrade`]. -pub struct ArcUpgrade { +/// The future returned by [`RwLockUpgradableReadGuardArc::upgrade`]. +pub struct UpgradeArc { /// Raw read lock upgrade future, doesn't depend on `T`. /// `'static` is a lie, this field is actually referencing the /// `Arc` data. But since this struct also stores said `Arc`, we know @@ -259,42 +259,45 @@ pub struct ArcUpgrade { /// However, in this case, there is an indirection via the heap; /// moving the `ArcUpgrade` won't move the heap allocation of the `Arc`, /// so the reference inside `RawUpgrade` isn't invalidated. - pub(super) raw: RawUpgrade<'static>, + pub(super) raw: ManuallyDrop>, /// Pointer to the value protected by the lock. Invariant in `T`. pub(super) lock: ManuallyDrop>>, } -impl fmt::Debug for ArcUpgrade { +impl fmt::Debug for UpgradeArc { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ArcUpgrade").finish() } } -impl Unpin for ArcUpgrade {} +impl Unpin for UpgradeArc {} -impl Future for ArcUpgrade { - type Output = ArcRwLockWriteGuard; +impl Future for UpgradeArc { + type Output = RwLockWriteGuardArc; #[inline] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - ready!(Pin::new(&mut self.raw).poll(cx)); + ready!(Pin::new(&mut *self.raw).poll(cx)); - Poll::Ready(ArcRwLockWriteGuard { + Poll::Ready(RwLockWriteGuardArc { lock: unsafe { ManuallyDrop::take(&mut self.lock) }, }) } } -impl Drop for ArcUpgrade { +impl Drop for UpgradeArc { #[inline] fn drop(&mut self) { if !self.raw.is_ready() { // SAFETY: we drop the `Arc` (decrementing the reference count) // only if this future was cancelled before returning an // upgraded lock. - unsafe { ManuallyDrop::drop(&mut self.lock) }; + unsafe { + ManuallyDrop::drop(&mut self.raw); + ManuallyDrop::drop(&mut self.lock); + }; } } } diff --git a/tests/rwlock.rs b/tests/rwlock.rs index 7d19397..6a5ea86 100644 --- a/tests/rwlock.rs +++ b/tests/rwlock.rs @@ -15,8 +15,8 @@ use std::thread; use futures_lite::future; use async_lock::{ - ArcRwLockReadGuard, ArcRwLockUpgradableReadGuard, RwLock, RwLockReadGuard, - RwLockUpgradableReadGuard, + RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard, + RwLockUpgradableReadGuardArc, }; #[cfg(target_family = "wasm")] @@ -301,7 +301,7 @@ fn upgrade_arc() { // Writers should not pass. assert!(lock.try_write().is_none()); - let mut write_guard = ArcRwLockUpgradableReadGuard::try_upgrade(upgradable_guard).expect( + let mut write_guard = RwLockUpgradableReadGuardArc::try_upgrade(upgradable_guard).expect( "should be able to upgrade an upgradable lock because there are no more readers", ); *write_guard += 1; @@ -416,7 +416,7 @@ fn upgradable_with_concurrent_writer_arc() { *write_guard = 1; }, async move { - let mut write_guard = ArcRwLockUpgradableReadGuard::upgrade(upgradable_guard).await; + let mut write_guard = RwLockUpgradableReadGuardArc::upgrade(upgradable_guard).await; assert_eq!(*write_guard, 0); *write_guard = 2; }, @@ -469,7 +469,7 @@ fn yields_when_contended_arc() { let upgradable = rw.try_upgradable_read_arc().unwrap(); check_yields_when_contended( rw.try_read_arc().unwrap(), - ArcRwLockUpgradableReadGuard::upgrade(upgradable), + RwLockUpgradableReadGuardArc::upgrade(upgradable), ); } @@ -534,12 +534,12 @@ fn arc_rwlock_refcounts() { let upgradable_read = rw.upgradable_read_arc().await; assert_eq!(Arc::strong_count(&rw), 2); - drop(ArcRwLockUpgradableReadGuard::upgrade(upgradable_read)); + drop(RwLockUpgradableReadGuardArc::upgrade(upgradable_read)); assert_eq!(Arc::strong_count(&rw), 1); let upgradable_read = rw.upgradable_read_arc().await; assert_eq!(Arc::strong_count(&rw), 2); - let write = ArcRwLockUpgradableReadGuard::upgrade(upgradable_read).await; + let write = RwLockUpgradableReadGuardArc::upgrade(upgradable_read).await; assert_eq!(Arc::strong_count(&rw), 2); drop(write); assert_eq!(Arc::strong_count(&rw), 1); @@ -553,8 +553,8 @@ fn _covariance_test<'g>(guard: RwLockReadGuard<'g, &'static ()>) { // We are testing that this compiles. fn _covariance_test_arc( - guard: ArcRwLockReadGuard<&'static ()>, - mut _guard_2: ArcRwLockReadGuard<&()>, + guard: RwLockReadGuardArc<&'static ()>, + mut _guard_2: RwLockReadGuardArc<&()>, ) { _guard_2 = guard; }