summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs13
-rw-r--r--src/lockable.rs59
-rw-r--r--src/mutex.rs10
-rw-r--r--src/rwlock.rs342
4 files changed, 417 insertions, 7 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 3d30330..3897615 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,10 +7,21 @@
mod guard;
mod key;
mod lockable;
+
pub mod mutex;
+pub mod rwlock;
pub use guard::LockGuard;
pub use key::{Key, ThreadKey};
pub use lockable::Lockable;
-pub use mutex::ParkingMutex as Mutex;
pub use mutex::SpinLock;
+
+/// A mutual exclusion primitive useful for protecting shared data, which cannot deadlock.
+///
+/// By default, this uses `parking_lot` as a backend.
+pub type Mutex<T> = mutex::Mutex<T, parking_lot::RawMutex>;
+
+/// A reader-writer lock
+///
+/// By default, this uses `parking_lot` as a backend.
+pub type RwLock<T> = rwlock::RwLock<T, parking_lot::RawRwLock>;
diff --git a/src/lockable.rs b/src/lockable.rs
index 4271fc8..050f856 100644
--- a/src/lockable.rs
+++ b/src/lockable.rs
@@ -1,7 +1,11 @@
use std::mem::MaybeUninit;
-use crate::mutex::{Mutex, MutexRef};
-use lock_api::RawMutex;
+use crate::{
+ mutex::{Mutex, MutexRef},
+ rwlock::{ReadLock, RwLock, RwLockReadRef, RwLockWriteRef, WriteLock},
+};
+
+use lock_api::{RawMutex, RawRwLock};
mod sealed {
use super::Lockable as L;
@@ -10,6 +14,9 @@ mod sealed {
pub trait Sealed {}
impl<'a, T, R: RawMutex + 'a> Sealed for Mutex<T, R> {}
+ impl<'a, T, R: RawRwLock + 'a> Sealed for RwLock<T, R> {}
+ impl<'a, T, R: RawRwLock + 'a> Sealed for ReadLock<'a, T, R> {}
+ impl<'a, T, R: RawRwLock + 'a> Sealed for WriteLock<'a, T, R> {}
impl<T: Sealed> Sealed for &T {}
impl<T: Sealed> Sealed for &mut T {}
impl<'a, A: L<'a>> Sealed for (A,) {}
@@ -111,6 +118,54 @@ unsafe impl<'a, T: 'a, R: RawMutex + 'a> Lockable<'a> for Mutex<T, R> {
}
}
+unsafe impl<'a, T: 'a, R: RawRwLock + 'a> Lockable<'a> for RwLock<T, R> {
+ type Output = RwLockWriteRef<'a, T, R>;
+
+ unsafe fn lock(&'a self) -> Self::Output {
+ self.write_no_key()
+ }
+
+ unsafe fn try_lock(&'a self) -> Option<Self::Output> {
+ self.try_write_no_key()
+ }
+
+ fn unlock(guard: Self::Output) {
+ drop(guard);
+ }
+}
+
+unsafe impl<'a, T: 'a, R: RawRwLock + 'a> Lockable<'a> for ReadLock<'a, T, R> {
+ type Output = RwLockReadRef<'a, T, R>;
+
+ unsafe fn lock(&'a self) -> Self::Output {
+ self.lock_no_key()
+ }
+
+ unsafe fn try_lock(&'a self) -> Option<Self::Output> {
+ self.try_lock_no_key()
+ }
+
+ fn unlock(guard: Self::Output) {
+ drop(guard);
+ }
+}
+
+unsafe impl<'a, T: 'a, R: RawRwLock + 'a> Lockable<'a> for WriteLock<'a, T, R> {
+ type Output = RwLockWriteRef<'a, T, R>;
+
+ unsafe fn lock(&'a self) -> Self::Output {
+ self.lock_no_key()
+ }
+
+ unsafe fn try_lock(&'a self) -> Option<Self::Output> {
+ self.try_lock_no_key()
+ }
+
+ fn unlock(guard: Self::Output) {
+ drop(guard);
+ }
+}
+
unsafe impl<'a, A: Lockable<'a>> Lockable<'a> for (A,) {
type Output = (A::Output,);
diff --git a/src/mutex.rs b/src/mutex.rs
index 7252dfc..c78d398 100644
--- a/src/mutex.rs
+++ b/src/mutex.rs
@@ -26,6 +26,7 @@ pub type ParkingMutex<T> = Mutex<T, parking_lot::RawMutex>;
///
/// [`lock`]: `Mutex::lock`
/// [`try_lock`]: `Mutex::try_lock`
+/// [`ThreadKey`]: `crate::ThreadKey`
pub struct Mutex<T: ?Sized, R> {
raw: R,
value: UnsafeCell<T>,
@@ -185,10 +186,12 @@ impl<T: ?Sized, R: RawMutex> Mutex<T, R> {
/// assert_eq!(*mutex.lock(key), 10);
/// ```
pub fn lock<'s, 'k: 's, Key: Keyable>(&'s self, key: Key) -> MutexGuard<'_, 'k, T, Key, R> {
- self.raw.lock();
+ unsafe {
+ self.raw.lock();
- // safety: we just locked the mutex
- unsafe { MutexGuard::new(self, key) }
+ // safety: we just locked the mutex
+ MutexGuard::new(self, key)
+ }
}
/// Lock without a [`ThreadKey`]. You must exclusively own the
@@ -271,7 +274,6 @@ impl<T: ?Sized, R: RawMutex> Mutex<T, R> {
///
/// let key = Mutex::unlock(guard);
/// ```
- #[allow(clippy::missing_const_for_fn)]
pub fn unlock<'a, 'k: 'a, Key: Keyable + 'k>(guard: MutexGuard<'a, 'k, T, Key, R>) -> Key {
unsafe {
guard.mutex.0.force_unlock();
diff --git a/src/rwlock.rs b/src/rwlock.rs
new file mode 100644
index 0000000..16ad3c3
--- /dev/null
+++ b/src/rwlock.rs
@@ -0,0 +1,342 @@
+use std::{
+ cell::UnsafeCell,
+ marker::PhantomData,
+ ops::{Deref, DerefMut},
+};
+
+use lock_api::RawRwLock;
+
+use crate::key::Keyable;
+
+pub type SpinRwLock<T> = RwLock<T, spin::RwLock<()>>;
+
+pub type ParkingRwLock<T> = RwLock<T, parking_lot::RawRwLock>;
+
+pub struct RwLock<T: ?Sized, R> {
+ raw: R,
+ value: UnsafeCell<T>,
+}
+
+pub struct ReadLock<'a, T: ?Sized, R>(&'a RwLock<T, R>);
+
+pub struct WriteLock<'a, T: ?Sized, R>(&'a RwLock<T, R>);
+
+pub struct RwLockReadRef<'a, T: ?Sized, R: RawRwLock>(&'a RwLock<T, R>);
+
+pub struct RwLockWriteRef<'a, T: ?Sized, R: RawRwLock>(&'a RwLock<T, R>);
+
+pub struct RwLockReadGuard<'a, 'key, T: ?Sized, Key: Keyable + 'key, R: RawRwLock> {
+ rwlock: RwLockReadRef<'a, T, R>,
+ thread_key: Key,
+ _phantom: PhantomData<&'key ()>,
+}
+
+pub struct RwLockWriteGuard<'a, 'key, T: ?Sized, Key: Keyable + 'key, R: RawRwLock> {
+ rwlock: RwLockWriteRef<'a, T, R>,
+ thread_key: Key,
+ _phantom: PhantomData<&'key ()>,
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockReadRef<'a, T, R> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // safety: this is the only type that can use `value`, and there's
+ // a reference to this type, so there cannot be any mutable
+ // references to this value.
+ unsafe { &*self.0.value.get() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockReadRef<'a, T, R> {
+ fn drop(&mut self) {
+ // safety: this guard is being destroyed, so the data cannot be
+ // accessed without locking again
+ unsafe { self.0.force_unlock_read() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockWriteRef<'a, T, R> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // safety: this is the only type that can use `value`, and there's
+ // a reference to this type, so there cannot be any mutable
+ // references to this value.
+ unsafe { &*self.0.value.get() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> DerefMut for RwLockWriteRef<'a, T, R> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ // safety: this is the only type that can use `value`, and we have a
+ // mutable reference to this type, so there cannot be any other
+ // references to this value.
+ unsafe { &mut *self.0.value.get() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockWriteRef<'a, T, R> {
+ fn drop(&mut self) {
+ // safety: this guard is being destroyed, so the data cannot be
+ // accessed without locking again
+ unsafe { self.0.force_unlock_write() }
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
+ for RwLockReadGuard<'a, 'key, T, Key, R>
+{
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.rwlock
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
+ for RwLockWriteGuard<'a, 'key, T, Key, R>
+{
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.rwlock
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> DerefMut
+ for RwLockWriteGuard<'a, 'key, T, Key, R>
+{
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.rwlock
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
+ RwLockReadGuard<'a, 'key, T, Key, R>
+{
+ /// Create a guard to the given mutex. Undefined if multiple guards to the
+ /// same mutex exist at once.
+ const unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: Key) -> Self {
+ Self {
+ rwlock: RwLockReadRef(rwlock),
+ thread_key,
+ _phantom: PhantomData,
+ }
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
+ RwLockWriteGuard<'a, 'key, T, Key, R>
+{
+ /// Create a guard to the given mutex. Undefined if multiple guards to the
+ /// same mutex exist at once.
+ const unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: Key) -> Self {
+ Self {
+ rwlock: RwLockWriteRef(rwlock),
+ thread_key,
+ _phantom: PhantomData,
+ }
+ }
+}
+
+impl<T, R: RawRwLock> RwLock<T, R> {
+ pub const fn new(value: T) -> Self {
+ Self {
+ value: UnsafeCell::new(value),
+ raw: R::INIT,
+ }
+ }
+}
+
+impl<T, R> RwLock<T, R> {
+ pub fn into_inner(self) -> T {
+ self.value.into_inner()
+ }
+}
+
+impl<T: ?Sized, R> RwLock<T, R> {
+ pub fn get_mut(&mut self) -> &mut T {
+ self.value.get_mut()
+ }
+}
+
+impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
+ pub fn read<'s, 'key: 's, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> RwLockReadGuard<'_, 'key, T, Key, R> {
+ unsafe {
+ self.raw.lock_shared();
+
+ // safety: the lock is locked first
+ RwLockReadGuard::new(self, key)
+ }
+ }
+
+ pub(crate) unsafe fn read_no_key(&self) -> RwLockReadRef<'_, T, R> {
+ self.raw.lock_shared();
+
+ // safety: the lock is locked first
+ RwLockReadRef(self)
+ }
+
+ pub fn try_read<'s, 'key: 's, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> Option<RwLockReadGuard<'_, 'key, T, Key, R>> {
+ unsafe {
+ if self.raw.try_lock_shared() {
+ // safety: the lock is locked first
+ Some(RwLockReadGuard::new(self, key))
+ } else {
+ None
+ }
+ }
+ }
+
+ pub(crate) unsafe fn try_read_no_key(&self) -> Option<RwLockReadRef<'_, T, R>> {
+ if self.raw.try_lock_shared() {
+ // safety: the lock is locked first
+ Some(RwLockReadRef(self))
+ } else {
+ None
+ }
+ }
+
+ pub fn write<'s, 'key: 's, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> RwLockWriteGuard<'_, 'key, T, Key, R> {
+ unsafe {
+ self.raw.lock_exclusive();
+
+ // safety: the lock is locked first
+ RwLockWriteGuard::new(self, key)
+ }
+ }
+
+ pub(crate) unsafe fn write_no_key(&self) -> RwLockWriteRef<'_, T, R> {
+ self.raw.lock_exclusive();
+
+ // safety: the lock is locked first
+ RwLockWriteRef(self)
+ }
+
+ pub fn try_write<'s, 'key: 's, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> Option<RwLockWriteGuard<'_, 'key, T, Key, R>> {
+ unsafe {
+ if self.raw.try_lock_exclusive() {
+ // safety: the lock is locked first
+ Some(RwLockWriteGuard::new(self, key))
+ } else {
+ None
+ }
+ }
+ }
+
+ pub(crate) unsafe fn try_write_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> {
+ if self.raw.try_lock_exclusive() {
+ // safety: the lock is locked first
+ Some(RwLockWriteRef(self))
+ } else {
+ None
+ }
+ }
+
+ unsafe fn force_unlock_read(&self) {
+ self.raw.unlock_shared();
+ }
+
+ unsafe fn force_unlock_write(&self) {
+ self.raw.unlock_exclusive();
+ }
+
+ pub fn unlock_read<'key, Key: Keyable + 'key>(
+ guard: RwLockReadGuard<'_, 'key, T, Key, R>,
+ ) -> Key {
+ unsafe {
+ guard.rwlock.0.force_unlock_read();
+ }
+ guard.thread_key
+ }
+
+ pub fn unlock_write<'key, Key: Keyable + 'key>(
+ guard: RwLockWriteGuard<'_, 'key, T, Key, R>,
+ ) -> Key {
+ unsafe {
+ guard.rwlock.0.force_unlock_write();
+ }
+ guard.thread_key
+ }
+}
+
+impl<'a, T, R> ReadLock<'a, T, R> {
+ pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
+ Self(rwlock)
+ }
+}
+
+impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> {
+ pub fn lock<'s, 'key: 's, Key: Keyable + 'key>(
+ &'s self,
+ key: Key,
+ ) -> RwLockReadGuard<'_, 'key, T, Key, R> {
+ self.0.read(key)
+ }
+
+ pub(crate) unsafe fn lock_no_key(&self) -> RwLockReadRef<'_, T, R> {
+ self.0.read_no_key()
+ }
+
+ pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
+ &'s self,
+ key: Key,
+ ) -> Option<RwLockReadGuard<'_, 'key, T, Key, R>> {
+ self.0.try_read(key)
+ }
+
+ pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockReadRef<'_, T, R>> {
+ self.0.try_read_no_key()
+ }
+
+ pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockReadGuard<'_, 'key, T, Key, R>) -> Key {
+ RwLock::unlock_read(guard)
+ }
+}
+
+impl<'a, T, R> WriteLock<'a, T, R> {
+ pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
+ Self(rwlock)
+ }
+}
+
+impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> {
+ pub fn lock<'s, 'key: 's, Key: Keyable + 'key>(
+ &'s self,
+ key: Key,
+ ) -> RwLockWriteGuard<'_, 'key, T, Key, R> {
+ self.0.write(key)
+ }
+
+ pub(crate) unsafe fn lock_no_key(&self) -> RwLockWriteRef<'_, T, R> {
+ self.0.write_no_key()
+ }
+
+ pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
+ &'s self,
+ key: Key,
+ ) -> Option<RwLockWriteGuard<'_, 'key, T, Key, R>> {
+ self.0.try_write(key)
+ }
+
+ pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> {
+ self.0.try_write_no_key()
+ }
+
+ pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockWriteGuard<'_, 'key, T, Key, R>) -> Key {
+ RwLock::unlock_write(guard)
+ }
+}