summaryrefslogtreecommitdiff
path: root/src/rwlock
diff options
context:
space:
mode:
Diffstat (limited to 'src/rwlock')
-rw-r--r--src/rwlock/read_guard.rs4
-rw-r--r--src/rwlock/read_lock.rs54
-rw-r--r--src/rwlock/rwlock.rs115
-rw-r--r--src/rwlock/write_guard.rs6
-rw-r--r--src/rwlock/write_lock.rs52
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.
///