diff options
| author | Mica White <botahamec@outlook.com> | 2025-03-09 20:49:56 -0400 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2025-03-09 20:49:56 -0400 |
| commit | 58abf5872023aca7ee6459fa3b2e067d57923ba5 (patch) | |
| tree | 196cadda0dd4386668477ef286f9c9b09480e713 /src/rwlock | |
| parent | 4ba03be97e6cc7e790bbc9bfc18caaa228c8a262 (diff) | |
Finish testing and fixing
Diffstat (limited to 'src/rwlock')
| -rw-r--r-- | src/rwlock/read_guard.rs | 4 | ||||
| -rw-r--r-- | src/rwlock/read_lock.rs | 54 | ||||
| -rw-r--r-- | src/rwlock/rwlock.rs | 115 | ||||
| -rw-r--r-- | src/rwlock/write_guard.rs | 6 | ||||
| -rw-r--r-- | src/rwlock/write_lock.rs | 52 |
5 files changed, 128 insertions, 103 deletions
diff --git a/src/rwlock/read_guard.rs b/src/rwlock/read_guard.rs index 0d68c75..5b26c06 100644 --- a/src/rwlock/read_guard.rs +++ b/src/rwlock/read_guard.rs @@ -64,7 +64,7 @@ impl<'a, T: ?Sized, R: RawRwLock> RwLockReadRef<'a, T, R> { /// Creates an immutable reference for the underlying data of an [`RwLock`] /// without locking it or taking ownership of the key. #[must_use] - pub(crate) unsafe fn new(mutex: &'a RwLock<T, R>) -> Self { + pub(crate) const unsafe fn new(mutex: &'a RwLock<T, R>) -> Self { Self(mutex, PhantomData) } } @@ -109,7 +109,7 @@ impl<'a, T: ?Sized, R: RawRwLock> RwLockReadGuard<'a, T, R> { /// Create a guard to the given mutex. Undefined if multiple guards to the /// same mutex exist at once. #[must_use] - pub(super) unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: ThreadKey) -> Self { + pub(super) const unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: ThreadKey) -> Self { Self { rwlock: RwLockReadRef(rwlock, PhantomData), thread_key, diff --git a/src/rwlock/read_lock.rs b/src/rwlock/read_lock.rs index 05b184a..dd9e42f 100644 --- a/src/rwlock/read_lock.rs +++ b/src/rwlock/read_lock.rs @@ -3,11 +3,41 @@ use std::fmt::Debug; use lock_api::RawRwLock; use crate::lockable::{Lockable, RawLock, Sharable}; -use crate::ThreadKey; +use crate::{Keyable, ThreadKey}; use super::{ReadLock, RwLock, RwLockReadGuard, RwLockReadRef}; -unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for ReadLock<'_, T, R> { +unsafe impl<T, R: RawRwLock> RawLock for ReadLock<'_, T, R> { + fn poison(&self) { + self.0.poison() + } + + unsafe fn raw_write(&self) { + self.0.raw_read() + } + + unsafe fn raw_try_write(&self) -> bool { + self.0.raw_try_read() + } + + unsafe fn raw_unlock_write(&self) { + self.0.raw_unlock_read() + } + + unsafe fn raw_read(&self) { + self.0.raw_read() + } + + unsafe fn raw_try_read(&self) -> bool { + self.0.raw_try_read() + } + + unsafe fn raw_unlock_read(&self) { + self.0.raw_unlock_read() + } +} + +unsafe impl<T, R: RawRwLock> Lockable for ReadLock<'_, T, R> { type Guard<'g> = RwLockReadRef<'g, T, R> where @@ -19,7 +49,7 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for ReadLock<'_, T, R> Self: 'a; fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn RawLock>) { - ptrs.push(self.as_ref()); + ptrs.push(self); } unsafe fn guard(&self) -> Self::Guard<'_> { @@ -31,7 +61,7 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for ReadLock<'_, T, R> } } -unsafe impl<T: Send, R: RawRwLock + Send + Sync> Sharable for ReadLock<'_, T, R> { +unsafe impl<T, R: RawRwLock> Sharable for ReadLock<'_, T, R> { type ReadGuard<'g> = RwLockReadRef<'g, T, R> where @@ -53,7 +83,7 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Sharable for ReadLock<'_, T, R> #[mutants::skip] #[cfg(not(tarpaulin_include))] -impl<T: ?Sized + Debug, R: RawRwLock> Debug for ReadLock<'_, T, R> { +impl<T: Debug, R: RawRwLock> Debug for ReadLock<'_, T, R> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // safety: this is just a try lock, and the value is dropped // immediately after, so there's no risk of blocking ourselves @@ -104,7 +134,19 @@ impl<'l, T, R> ReadLock<'l, T, R> { } } -impl<T: ?Sized, R: RawRwLock> ReadLock<'_, T, R> { +impl<T, R: RawRwLock> ReadLock<'_, T, R> { + pub fn scoped_lock<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a T) -> Ret) -> Ret { + self.0.scoped_read(key, f) + } + + pub fn scoped_try_lock<'a, Key: Keyable, Ret>( + &'a self, + key: Key, + f: impl Fn(&'a T) -> Ret, + ) -> Result<Ret, Key> { + self.0.scoped_try_read(key, f) + } + /// Locks the underlying [`RwLock`] with shared read access, blocking the /// current thread until it can be acquired. /// diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs index 905ecf8..5f407d1 100644 --- a/src/rwlock/rwlock.rs +++ b/src/rwlock/rwlock.rs @@ -5,6 +5,7 @@ use std::panic::AssertUnwindSafe; use lock_api::RawRwLock; +use crate::collection::utils; use crate::handle_unwind::handle_unwind; use crate::lockable::{ Lockable, LockableGetMut, LockableIntoInner, OwnedLockable, RawLock, Sharable, @@ -18,7 +19,7 @@ unsafe impl<T: ?Sized, R: RawRwLock> RawLock for RwLock<T, R> { self.poison.poison(); } - unsafe fn raw_lock(&self) { + unsafe fn raw_write(&self) { assert!( !self.poison.is_poisoned(), "The read-write lock has been killed" @@ -29,7 +30,7 @@ unsafe impl<T: ?Sized, R: RawRwLock> RawLock for RwLock<T, R> { handle_unwind(|| this.raw.lock_exclusive(), || self.poison()) } - unsafe fn raw_try_lock(&self) -> bool { + unsafe fn raw_try_write(&self) -> bool { if self.poison.is_poisoned() { return false; } @@ -39,7 +40,7 @@ unsafe impl<T: ?Sized, R: RawRwLock> RawLock for RwLock<T, R> { handle_unwind(|| this.raw.try_lock_exclusive(), || self.poison()) } - unsafe fn raw_unlock(&self) { + unsafe fn raw_unlock_write(&self) { // if the closure unwraps, then the mutex will be killed let this = AssertUnwindSafe(self); handle_unwind(|| this.raw.unlock_exclusive(), || self.poison()) @@ -73,7 +74,7 @@ unsafe impl<T: ?Sized, R: RawRwLock> RawLock for RwLock<T, R> { } } -unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for RwLock<T, R> { +unsafe impl<T, R: RawRwLock> Lockable for RwLock<T, R> { type Guard<'g> = RwLockWriteRef<'g, T, R> where @@ -97,7 +98,7 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for RwLock<T, R> { } } -unsafe impl<T: Send, R: RawRwLock + Send + Sync> Sharable for RwLock<T, R> { +unsafe impl<T, R: RawRwLock> Sharable for RwLock<T, R> { type ReadGuard<'g> = RwLockReadRef<'g, T, R> where @@ -117,9 +118,9 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Sharable for RwLock<T, R> { } } -unsafe impl<T: Send, R: RawRwLock + Send + Sync> OwnedLockable for RwLock<T, R> {} +unsafe impl<T: Send, R: RawRwLock> OwnedLockable for RwLock<T, R> {} -impl<T: Send, R: RawRwLock + Send + Sync> LockableIntoInner for RwLock<T, R> { +impl<T: Send, R: RawRwLock> LockableIntoInner for RwLock<T, R> { type Inner = T; fn into_inner(self) -> Self::Inner { @@ -127,7 +128,7 @@ impl<T: Send, R: RawRwLock + Send + Sync> LockableIntoInner for RwLock<T, R> { } } -impl<T: Send, R: RawRwLock + Send + Sync> LockableGetMut for RwLock<T, R> { +impl<T: Send, R: RawRwLock> LockableGetMut for RwLock<T, R> { type Inner<'a> = &'a mut T where @@ -160,7 +161,7 @@ impl<T, R: RawRwLock> RwLock<T, R> { #[mutants::skip] #[cfg(not(tarpaulin_include))] -impl<T: ?Sized + Debug, R: RawRwLock> Debug for RwLock<T, R> { +impl<T: Debug, R: RawRwLock> Debug for RwLock<T, R> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // safety: this is just a try lock, and the value is dropped // immediately after, so there's no risk of blocking ourselves @@ -247,85 +248,29 @@ impl<T: ?Sized, R> RwLock<T, R> { } } -impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { - pub fn scoped_read<Ret>(&self, key: impl Keyable, f: impl Fn(&T) -> Ret) -> Ret { - unsafe { - // safety: we have the thread key - self.raw_read(); - - // safety: the rwlock was just locked - let r = f(self.data.get().as_ref().unwrap_unchecked()); - - // safety: the rwlock is already locked - self.raw_unlock_read(); - - drop(key); // ensure the key stays valid for long enough - - r - } +impl<T, R: RawRwLock> RwLock<T, R> { + pub fn scoped_read<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a T) -> Ret) -> Ret { + utils::scoped_read(self, key, f) } - pub fn scoped_try_read<Key: Keyable, Ret>( - &self, + pub fn scoped_try_read<'a, Key: Keyable, Ret>( + &'a self, key: Key, - f: impl Fn(&T) -> Ret, + f: impl Fn(&'a T) -> Ret, ) -> Result<Ret, Key> { - unsafe { - // safety: we have the thread key - if !self.raw_try_read() { - return Err(key); - } - - // safety: the rwlock was just locked - let r = f(self.data.get().as_ref().unwrap_unchecked()); - - // safety: the rwlock is already locked - self.raw_unlock_read(); - - drop(key); // ensure the key stays valid for long enough - - Ok(r) - } + utils::scoped_try_read(self, key, f) } - pub fn scoped_write<Ret>(&self, key: impl Keyable, f: impl Fn(&mut T) -> Ret) -> Ret { - unsafe { - // safety: we have the thread key - self.raw_lock(); - - // safety: we just locked the rwlock - let r = f(self.data.get().as_mut().unwrap_unchecked()); - - // safety: the rwlock is already locked - self.raw_unlock(); - - drop(key); // ensure the key stays valid for long enough - - r - } + pub fn scoped_write<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a mut T) -> Ret) -> Ret { + utils::scoped_write(self, key, f) } - pub fn scoped_try_write<Key: Keyable, Ret>( - &self, + pub fn scoped_try_write<'a, Key: Keyable, Ret>( + &'a self, key: Key, - f: impl Fn(&mut T) -> Ret, + f: impl Fn(&'a mut T) -> Ret, ) -> Result<Ret, Key> { - unsafe { - // safety: we have the thread key - if !self.raw_try_lock() { - return Err(key); - } - - // safety: the rwlock was just locked - let r = f(self.data.get().as_mut().unwrap_unchecked()); - - // safety: the rwlock is already locked - self.raw_unlock(); - - drop(key); // ensure the key stays valid for long enough - - Ok(r) - } + utils::scoped_try_write(self, key, f) } /// Locks this `RwLock` with shared read access, blocking the current @@ -426,7 +371,7 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// without exclusive access to the key is undefined behavior. #[cfg(test)] pub(crate) unsafe fn try_write_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> { - if self.raw_try_lock() { + if self.raw_try_write() { // safety: the lock is locked first Some(RwLockWriteRef(self, PhantomData)) } else { @@ -463,7 +408,7 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// [`ThreadKey`]: `crate::ThreadKey` pub fn write(&self, key: ThreadKey) -> RwLockWriteGuard<'_, T, R> { unsafe { - self.raw_lock(); + self.raw_write(); // safety: the lock is locked first RwLockWriteGuard::new(self, key) @@ -498,7 +443,7 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// ``` pub fn try_write(&self, key: ThreadKey) -> Result<RwLockWriteGuard<'_, T, R>, ThreadKey> { unsafe { - if self.raw_try_lock() { + if self.raw_try_write() { // safety: the lock is locked first Ok(RwLockWriteGuard::new(self, key)) } else { @@ -533,9 +478,7 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// ``` #[must_use] pub fn unlock_read(guard: RwLockReadGuard<'_, T, R>) -> ThreadKey { - unsafe { - guard.rwlock.0.raw_unlock_read(); - } + drop(guard.rwlock); guard.thread_key } @@ -560,9 +503,7 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// ``` #[must_use] pub fn unlock_write(guard: RwLockWriteGuard<'_, T, R>) -> ThreadKey { - unsafe { - guard.rwlock.0.raw_unlock(); - } + drop(guard.rwlock); guard.thread_key } } diff --git a/src/rwlock/write_guard.rs b/src/rwlock/write_guard.rs index 3fabf8e..c7676b5 100644 --- a/src/rwlock/write_guard.rs +++ b/src/rwlock/write_guard.rs @@ -71,7 +71,7 @@ impl<T: ?Sized, R: RawRwLock> Drop for RwLockWriteRef<'_, T, R> { fn drop(&mut self) { // safety: this guard is being destroyed, so the data cannot be // accessed without locking again - unsafe { self.0.raw_unlock() } + unsafe { self.0.raw_unlock_write() } } } @@ -79,7 +79,7 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> RwLockWriteRef<'a, T, R> { /// Creates a reference to the underlying data of an [`RwLock`] without /// locking or taking ownership of the key. #[must_use] - pub(crate) unsafe fn new(mutex: &'a RwLock<T, R>) -> Self { + pub(crate) const unsafe fn new(mutex: &'a RwLock<T, R>) -> Self { Self(mutex, PhantomData) } } @@ -136,7 +136,7 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> RwLockWriteGuard<'a, T, R> { /// Create a guard to the given mutex. Undefined if multiple guards to the /// same mutex exist at once. #[must_use] - pub(super) unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: ThreadKey) -> Self { + pub(super) const unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: ThreadKey) -> Self { Self { rwlock: RwLockWriteRef(rwlock, PhantomData), thread_key, diff --git a/src/rwlock/write_lock.rs b/src/rwlock/write_lock.rs index 8a44a2d..5ae4dda 100644 --- a/src/rwlock/write_lock.rs +++ b/src/rwlock/write_lock.rs @@ -3,11 +3,41 @@ use std::fmt::Debug; use lock_api::RawRwLock; use crate::lockable::{Lockable, RawLock}; -use crate::ThreadKey; +use crate::{Keyable, ThreadKey}; use super::{RwLock, RwLockWriteGuard, RwLockWriteRef, WriteLock}; -unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for WriteLock<'_, T, R> { +unsafe impl<T, R: RawRwLock> RawLock for WriteLock<'_, T, R> { + fn poison(&self) { + self.0.poison() + } + + unsafe fn raw_write(&self) { + self.0.raw_write() + } + + unsafe fn raw_try_write(&self) -> bool { + self.0.raw_try_write() + } + + unsafe fn raw_unlock_write(&self) { + self.0.raw_unlock_write() + } + + unsafe fn raw_read(&self) { + self.0.raw_write() + } + + unsafe fn raw_try_read(&self) -> bool { + self.0.raw_try_write() + } + + unsafe fn raw_unlock_read(&self) { + self.0.raw_unlock_write() + } +} + +unsafe impl<T, R: RawRwLock> Lockable for WriteLock<'_, T, R> { type Guard<'g> = RwLockWriteRef<'g, T, R> where @@ -19,7 +49,7 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for WriteLock<'_, T, R Self: 'a; fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn RawLock>) { - ptrs.push(self.as_ref()); + ptrs.push(self) } unsafe fn guard(&self) -> Self::Guard<'_> { @@ -36,7 +66,7 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for WriteLock<'_, T, R #[mutants::skip] #[cfg(not(tarpaulin_include))] -impl<T: ?Sized + Debug, R: RawRwLock> Debug for WriteLock<'_, T, R> { +impl<T: Debug, R: RawRwLock> Debug for WriteLock<'_, T, R> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // safety: this is just a try lock, and the value is dropped // immediately after, so there's no risk of blocking ourselves @@ -89,7 +119,19 @@ impl<'l, T, R> WriteLock<'l, T, R> { } } -impl<T: ?Sized, R: RawRwLock> WriteLock<'_, T, R> { +impl<T, R: RawRwLock> WriteLock<'_, T, R> { + pub fn scoped_lock<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a mut T) -> Ret) -> Ret { + self.0.scoped_write(key, f) + } + + pub fn scoped_try_lock<'a, Key: Keyable, Ret>( + &'a self, + key: Key, + f: impl Fn(&'a mut T) -> Ret, + ) -> Result<Ret, Key> { + self.0.scoped_try_write(key, f) + } + /// Locks the underlying [`RwLock`] with exclusive write access, blocking /// the current until it can be acquired. /// |
