summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/collection.rs32
-rw-r--r--src/collection/collection.rs180
-rw-r--r--src/collection/guard.rs2
-rw-r--r--src/lib.rs4
-rw-r--r--src/lockable.rs706
-rw-r--r--src/mutex/guard.rs6
-rw-r--r--src/mutex/mutex.rs26
-rw-r--r--src/rwlock/read_guard.rs6
-rw-r--r--src/rwlock/read_lock.rs6
-rw-r--r--src/rwlock/rwlock.rs32
-rw-r--r--src/rwlock/write_guard.rs6
-rw-r--r--src/rwlock/write_lock.rs6
12 files changed, 386 insertions, 626 deletions
diff --git a/src/collection.rs b/src/collection.rs
index c6cbe2d..1c276a6 100644
--- a/src/collection.rs
+++ b/src/collection.rs
@@ -1,23 +1,41 @@
-use std::marker::PhantomData;
+use std::marker::{PhantomData, PhantomPinned};
+use std::ptr::NonNull;
-use crate::{key::Keyable, lockable::Lockable};
+use crate::{
+ key::Keyable,
+ lockable::{Lock, Lockable},
+};
mod collection;
mod guard;
+pub struct OwnedLockCollection<L> {
+ data: L,
+}
+
/// A type which can be locked.
///
/// This could be a tuple of [`Lockable`] types, an array, or a `Vec`. But it
-/// can be safely locked without causing a deadlock. To do this, it is very
-/// important that no duplicate locks are included within.
-#[derive(Debug, Clone, Copy)]
-pub struct LockCollection<L> {
+/// can be safely locked without causing a deadlock.
+pub struct RefLockCollection<'a, L> {
+ locks: Vec<&'a dyn Lock>,
+ data: &'a L,
+}
+
+pub struct BoxedLockCollection<L: 'static>(RefLockCollection<'static, L>);
+
+pub struct PinnedLockCollection<L> {
+ _unpin: PhantomPinned,
data: L,
+ locks: Vec<NonNull<dyn Lock>>,
}
+unsafe impl<L: Send> Send for PinnedLockCollection<L> {}
+unsafe impl<L: Sync> Sync for PinnedLockCollection<L> {}
+
/// A RAII guard for a generic [`Lockable`] type.
pub struct LockGuard<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable + 'key> {
- guard: L::Output,
+ guard: L::Guard,
key: Key,
_phantom: PhantomData<&'key ()>,
}
diff --git a/src/collection/collection.rs b/src/collection/collection.rs
index ae9f3f6..a8d25a5 100644
--- a/src/collection/collection.rs
+++ b/src/collection/collection.rs
@@ -1,63 +1,43 @@
use std::marker::PhantomData;
-use crate::{key::Keyable, Lockable, OwnedLockable};
+use crate::{key::Keyable, lockable::Lock, Lockable, OwnedLockable};
-use super::{LockCollection, LockGuard};
+use super::{LockGuard, RefLockCollection};
-/// returns `true` if the list contains a duplicate
-#[must_use]
-fn contains_duplicates(l: &[usize]) -> bool {
- for i in 0..l.len() {
- for j in (i + 1)..l.len() {
- if l[i] == l[j] {
- return true;
- }
- }
- }
-
- false
+fn get_locks<'a, L: Lockable<'a> + 'a>(data: &'a L) -> Vec<&'a dyn Lock> {
+ let mut locks = Vec::new();
+ data.get_ptrs(&mut locks);
+ locks.sort_by_key(|lock| std::ptr::from_ref(*lock));
+ locks
}
-impl<'a, L: OwnedLockable<'a>> From<L> for LockCollection<L> {
- fn from(value: L) -> Self {
- Self::new(value)
- }
+/// returns `true` if the sorted list contains a duplicate
+#[must_use]
+fn contains_duplicates(l: &[&dyn Lock]) -> bool {
+ l.windows(2).any(|window| {
+ std::ptr::addr_eq(std::ptr::from_ref(window[0]), std::ptr::from_ref(window[1]))
+ })
}
-impl<'a, L: Lockable<'a>> AsRef<L> for LockCollection<L> {
+impl<'a, L: Lockable<'a>> AsRef<L> for RefLockCollection<'a, L> {
fn as_ref(&self) -> &L {
- &self.data
- }
-}
-
-impl<'a, L: Lockable<'a>> AsMut<L> for LockCollection<L> {
- fn as_mut(&mut self) -> &mut L {
- &mut self.data
+ self.data
}
}
-impl<'a, L: Lockable<'a>> AsRef<Self> for LockCollection<L> {
+impl<'a, L: Lockable<'a>> AsRef<Self> for RefLockCollection<'a, L> {
fn as_ref(&self) -> &Self {
self
}
}
-impl<'a, L: Lockable<'a>> AsMut<Self> for LockCollection<L> {
+impl<'a, L: Lockable<'a>> AsMut<Self> for RefLockCollection<'a, L> {
fn as_mut(&mut self) -> &mut Self {
self
}
}
-impl<L: IntoIterator> IntoIterator for LockCollection<L> {
- type Item = L::Item;
- type IntoIter = L::IntoIter;
-
- fn into_iter(self) -> Self::IntoIter {
- self.data.into_iter()
- }
-}
-
-impl<'a, L> IntoIterator for &'a LockCollection<L>
+impl<'a, L> IntoIterator for &'a RefLockCollection<'a, L>
where
&'a L: IntoIterator,
{
@@ -69,51 +49,7 @@ where
}
}
-impl<'a, L> IntoIterator for &'a mut LockCollection<L>
-where
- &'a mut L: IntoIterator,
-{
- type Item = <&'a mut L as IntoIterator>::Item;
- type IntoIter = <&'a mut L as IntoIterator>::IntoIter;
-
- fn into_iter(self) -> Self::IntoIter {
- self.data.into_iter()
- }
-}
-
-impl<'a, L: OwnedLockable<'a>, I: FromIterator<L> + OwnedLockable<'a>> FromIterator<L>
- for LockCollection<I>
-{
- fn from_iter<T: IntoIterator<Item = L>>(iter: T) -> Self {
- let iter: I = iter.into_iter().collect();
- Self::new(iter)
- }
-}
-
-impl<'a, E: OwnedLockable<'a> + Extend<L>, L: OwnedLockable<'a>> Extend<L> for LockCollection<E> {
- fn extend<T: IntoIterator<Item = L>>(&mut self, iter: T) {
- self.data.extend(iter)
- }
-}
-
-impl<'a, L: OwnedLockable<'a>> LockCollection<L> {
- /// Creates a new collection of owned locks.
- ///
- /// Because the locks are owned, there's no need to do any checks for
- /// duplicate values.
- ///
- /// # Examples
- ///
- /// ```
- /// use happylock::{LockCollection, Mutex};
- ///
- /// let lock = LockCollection::new((Mutex::new(0), Mutex::new("")));
- /// ```
- #[must_use]
- pub const fn new(data: L) -> Self {
- Self { data }
- }
-
+impl<'a, L: OwnedLockable<'a> + 'a> RefLockCollection<'a, L> {
/// Creates a new collection of owned locks.
///
/// Because the locks are owned, there's no need to do any checks for
@@ -125,15 +61,18 @@ impl<'a, L: OwnedLockable<'a>> LockCollection<L> {
/// use happylock::{LockCollection, Mutex};
///
/// let data = (Mutex::new(0), Mutex::new(""));
- /// let lock = LockCollection::new_ref(&data);
+ /// let lock = LockCollection::new(&data);
/// ```
#[must_use]
- pub const fn new_ref(data: &L) -> LockCollection<&L> {
- LockCollection { data }
+ pub fn new(data: &'a L) -> RefLockCollection<L> {
+ RefLockCollection {
+ locks: get_locks(data),
+ data,
+ }
}
}
-impl<L> LockCollection<L> {
+impl<'a, L: Lockable<'a>> RefLockCollection<'a, L> {
/// Creates a new collections of locks.
///
/// # Safety
@@ -153,23 +92,18 @@ impl<L> LockCollection<L> {
/// let lock = unsafe { LockCollection::new_unchecked((&data1, &data2)) };
/// ```
#[must_use]
- pub const unsafe fn new_unchecked(data: L) -> Self {
- Self { data }
+ pub unsafe fn new_unchecked(data: &'a L) -> Self {
+ Self {
+ data,
+ locks: get_locks(data),
+ }
}
-}
-impl<'a, L: Lockable<'a>> LockCollection<L> {
/// Creates a new collection of locks.
///
/// This returns `None` if any locks are found twice in the given
/// collection.
///
- /// # Performance
- ///
- /// This does a check at runtime to make sure that the collection contains
- /// no two copies of the same lock. This is an `O(n^2)` operation. Prefer
- /// [`LockCollection::new`] or [`LockCollection::new_ref`] instead.
- ///
/// # Examples
///
/// ```
@@ -182,13 +116,13 @@ impl<'a, L: Lockable<'a>> LockCollection<L> {
/// let lock = LockCollection::try_new((&data1, &data2)).unwrap();
/// ```
#[must_use]
- pub fn try_new(data: L) -> Option<Self> {
- let ptrs = data.get_ptrs();
- if contains_duplicates(&ptrs) {
+ pub fn try_new(data: &'a L) -> Option<Self> {
+ let locks = get_locks(data);
+ if contains_duplicates(&locks) {
return None;
}
- Some(Self { data })
+ Some(Self { locks, data })
}
/// Locks the collection
@@ -210,9 +144,14 @@ impl<'a, L: Lockable<'a>> LockCollection<L> {
/// *guard.1 = "1";
/// ```
pub fn lock<'key: 'a, Key: Keyable + 'key>(&'a self, key: Key) -> LockGuard<'a, 'key, L, Key> {
+ for lock in &self.locks {
+ // safety: we have the thread key
+ unsafe { lock.lock() };
+ }
+
LockGuard {
- // safety: we have the thread's key
- guard: unsafe { self.data.lock() },
+ // safety: we've already acquired the lock
+ guard: unsafe { self.data.guard() },
key,
_phantom: PhantomData,
}
@@ -245,8 +184,25 @@ impl<'a, L: Lockable<'a>> LockCollection<L> {
&'a self,
key: Key,
) -> Option<LockGuard<'a, 'key, L, Key>> {
- // safety: we have the thread's key
- unsafe { self.data.try_lock() }.map(|guard| LockGuard {
+ let guard = unsafe {
+ for (i, lock) in self.locks.iter().enumerate() {
+ // safety: we have the thread key
+ let success = lock.try_lock();
+
+ if !success {
+ for lock in &self.locks[0..i] {
+ // safety: this lock was already acquired
+ lock.unlock();
+ }
+ return None;
+ }
+ }
+
+ // safety: we've acquired the locks
+ self.data.guard()
+ };
+
+ Some(LockGuard {
guard,
key,
_phantom: PhantomData,
@@ -276,23 +232,13 @@ impl<'a, L: Lockable<'a>> LockCollection<L> {
}
}
-impl<'a, L: 'a> LockCollection<L>
+impl<'a, L: 'a> RefLockCollection<'a, L>
where
&'a L: IntoIterator,
{
/// Returns an iterator over references to each value in the collection.
+ #[must_use]
pub fn iter(&'a self) -> <&'a L as IntoIterator>::IntoIter {
self.into_iter()
}
}
-
-impl<'a, L: 'a> LockCollection<L>
-where
- &'a mut L: IntoIterator,
-{
- /// Returns an iterator over mutable references to each value in the
- /// collection.
- pub fn iter_mut(&'a mut self) -> <&'a mut L as IntoIterator>::IntoIter {
- self.into_iter()
- }
-}
diff --git a/src/collection/guard.rs b/src/collection/guard.rs
index 110a935..3b98d29 100644
--- a/src/collection/guard.rs
+++ b/src/collection/guard.rs
@@ -5,7 +5,7 @@ use crate::{key::Keyable, Lockable};
use super::LockGuard;
impl<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable> Deref for LockGuard<'a, 'key, L, Key> {
- type Target = L::Output;
+ type Target = L::Guard;
fn deref(&self) -> &Self::Target {
&self.guard
diff --git a/src/lib.rs b/src/lib.rs
index 4093ac4..64813af 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,14 +106,14 @@
//! println!("{}", *data.1);
//! ```
-mod collection;
mod key;
mod lockable;
+pub mod collection;
pub mod mutex;
pub mod rwlock;
-pub use collection::LockCollection;
+pub use collection::RefLockCollection;
pub use key::{Keyable, ThreadKey};
pub use lockable::{Lockable, OwnedLockable};
diff --git a/src/lockable.rs b/src/lockable.rs
index 086ab33..a09b84b 100644
--- a/src/lockable.rs
+++ b/src/lockable.rs
@@ -7,15 +7,6 @@ use crate::{
use lock_api::{RawMutex, RawRwLock};
-/// A type that may be locked and unlocked, and is known to be the only valid
-/// instance of the lock.
-///
-/// # Safety
-///
-/// There must not be any two values which can unlock the value at the same
-/// time, i.e., this must either be an owned value or a mutable reference.
-pub unsafe trait OwnedLockable<'a>: Lockable<'a> {}
-
/// A type that may be locked and unlocked
///
/// # Safety
@@ -23,30 +14,21 @@ pub unsafe trait OwnedLockable<'a>: Lockable<'a> {}
/// A deadlock must never occur. The `unlock` method must correctly unlock the
/// data. The `get_ptrs` method must be implemented correctly. The `Output`
/// must be unlocked when it is dropped.
-pub unsafe trait Lockable<'a> {
- /// The output of the lock
- type Output;
-
- /// Returns a list of all pointers to locks. This is used to ensure that
- /// the same lock isn't included twice
- #[must_use]
- fn get_ptrs(&self) -> Vec<usize>;
-
+pub unsafe trait Lock: Send + Sync {
/// Blocks until the lock is acquired
///
/// # Safety
///
- /// It is undefined behavior to:
- /// * Use this without ownership or mutable access to the [`ThreadKey`],
- /// which should last as long as the return value is alive.
- /// * Call this on multiple locks without unlocking first.
+ /// It is undefined behavior to use this without ownership or mutable
+ /// access to the [`ThreadKey`], which should last as long as the return
+ /// value is alive.
///
/// [`ThreadKey`]: `crate::ThreadKey`
- unsafe fn lock(&'a self) -> Self::Output;
+ unsafe fn lock(&self);
/// Attempt to lock without blocking.
///
- /// Returns `Some` if successful, `None` otherwise.
+ /// Returns `true` if successful, `false` otherwise.
///
/// # Safety
///
@@ -55,304 +37,225 @@ pub unsafe trait Lockable<'a> {
/// value is alive.
///
/// [`ThreadKey`]: `crate::ThreadKey`
- unsafe fn try_lock(&'a self) -> Option<Self::Output>;
+ unsafe fn try_lock(&self) -> bool;
+
+ /// Releases the lock
+ ///
+ /// # Safety
+ ///
+ /// It is undefined behavior to use this if the lock is not acquired
+ unsafe fn unlock(&self);
+}
+
+pub unsafe trait Lockable<'a> {
+ /// The guard returned that does not hold a key
+ type Guard;
+
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>);
+
+ #[must_use]
+ unsafe fn guard(&'a self) -> Self::Guard;
}
-unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for &T {
- type Output = T::Output;
+/// A type that may be locked and unlocked, and is known to be the only valid
+/// instance of the lock.
+///
+/// # Safety
+///
+/// There must not be any two values which can unlock the value at the same
+/// time, i.e., this must either be an owned value or a mutable reference.
+pub unsafe trait OwnedLockable<'a>: Lockable<'a> {}
- fn get_ptrs(&self) -> Vec<usize> {
- (*self).get_ptrs()
+unsafe impl<T: Send, R: RawMutex + Send + Sync> Lock for Mutex<T, R> {
+ unsafe fn lock(&self) {
+ self.raw().lock()
}
- unsafe fn lock(&'a self) -> Self::Output {
- (*self).lock()
+ unsafe fn try_lock(&self) -> bool {
+ self.raw().try_lock()
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- (*self).try_lock()
+ unsafe fn unlock(&self) {
+ self.raw().unlock()
}
}
-unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for &mut T {
- type Output = T::Output;
-
- fn get_ptrs(&self) -> Vec<usize> {
- (**self).get_ptrs()
+unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lock for RwLock<T, R> {
+ unsafe fn lock(&self) {
+ self.raw().lock_exclusive()
}
- unsafe fn lock(&'a self) -> Self::Output {
- (**self).lock()
+ unsafe fn try_lock(&self) -> bool {
+ self.raw().try_lock_exclusive()
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- (**self).try_lock()
+ unsafe fn unlock(&self) {
+ self.raw().unlock_exclusive()
}
}
-unsafe impl<'a, T: OwnedLockable<'a>> OwnedLockable<'a> for &mut T {}
+unsafe impl<'a, T: Send + 'a, R: RawMutex + Send + Sync + 'a> Lockable<'a> for Mutex<T, R> {
+ type Guard = MutexRef<'a, T, R>;
-unsafe impl<'a, T: 'a, R: RawMutex + 'a> Lockable<'a> for Mutex<T, R> {
- type Output = MutexRef<'a, T, R>;
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ ptrs.push(self);
+ }
- fn get_ptrs(&self) -> Vec<usize> {
- vec![self as *const Self as usize]
+ unsafe fn guard(&'a self) -> Self::Guard {
+ MutexRef::new(self)
}
+}
- unsafe fn lock(&'a self) -> Self::Output {
- self.lock_no_key()
+unsafe impl<'a, T: Send + 'a, R: RawRwLock + Send + Sync + 'a> Lockable<'a> for RwLock<T, R> {
+ type Guard = RwLockWriteRef<'a, T, R>;
+
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ ptrs.push(self);
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- self.try_lock_no_key()
+ unsafe fn guard(&'a self) -> Self::Guard {
+ RwLockWriteRef::new(self)
}
}
-unsafe impl<'a, T: 'a, R: RawRwLock + 'a> Lockable<'a> for RwLock<T, R> {
- type Output = RwLockWriteRef<'a, T, R>;
+unsafe impl<'a, T: Send + 'a, R: RawMutex + Send + Sync + 'a> OwnedLockable<'a> for Mutex<T, R> {}
- fn get_ptrs(&self) -> Vec<usize> {
- vec![self as *const Self as usize]
- }
+unsafe impl<'a, T: Send + 'a, R: RawRwLock + Send + Sync + 'a> OwnedLockable<'a> for RwLock<T, R> {}
+
+unsafe impl<'a, T: Send + 'a, R: RawRwLock + Send + Sync + 'a> Lockable<'a> for ReadLock<'a, T, R> {
+ type Guard = RwLockReadRef<'a, T, R>;
- unsafe fn lock(&'a self) -> Self::Output {
- self.write_no_key()
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ ptrs.push(self.as_ref());
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- self.try_write_no_key()
+ unsafe fn guard(&'a self) -> Self::Guard {
+ RwLockReadRef::new(self.as_ref())
}
}
-unsafe impl<'a, T: 'a, R: RawMutex + 'a> OwnedLockable<'a> for Mutex<T, R> {}
-
-unsafe impl<'a, T: 'a, R: RawRwLock + 'a> OwnedLockable<'a> for RwLock<T, R> {}
+unsafe impl<'a, T: Send + 'a, R: RawRwLock + Send + Sync + 'a> Lockable<'a>
+ for WriteLock<'a, T, R>
+{
+ type Guard = RwLockWriteRef<'a, T, R>;
-unsafe impl<'a, T: 'a, R: RawRwLock + 'a> Lockable<'a> for ReadLock<'a, T, R> {
- type Output = RwLockReadRef<'a, T, R>;
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ ptrs.push(self.as_ref());
+ }
- fn get_ptrs(&self) -> Vec<usize> {
- vec![self.as_ref() as *const RwLock<T, R> as usize]
+ unsafe fn guard(&'a self) -> Self::Guard {
+ RwLockWriteRef::new(self.as_ref())
}
+}
- unsafe fn lock(&'a self) -> Self::Output {
- self.lock_no_key()
+unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for &'a T {
+ type Guard = T::Guard;
+
+ fn get_ptrs(&self, ptrs: &mut Vec<&'a dyn Lock>) {
+ (*self).get_ptrs(ptrs);
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- self.try_lock_no_key()
+ unsafe fn guard(&self) -> Self::Guard {
+ (*self).guard()
}
}
-unsafe impl<'a, T: 'a, R: RawRwLock + 'a> Lockable<'a> for WriteLock<'a, T, R> {
- type Output = RwLockWriteRef<'a, T, R>;
-
- fn get_ptrs(&self) -> Vec<usize> {
- vec![self.as_ref() as *const RwLock<T, R> as usize]
- }
+unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for &mut T {
+ type Guard = T::Guard;
- unsafe fn lock(&'a self) -> Self::Output {
- self.lock_no_key()
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ (**self).get_ptrs(ptrs)
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- self.try_lock_no_key()
+ unsafe fn guard(&'a self) -> Self::Guard {
+ (**self).guard()
}
}
-unsafe impl<'a, A: Lockable<'a>> Lockable<'a> for (A,) {
- type Output = (A::Output,);
+unsafe impl<'a, T: OwnedLockable<'a>> OwnedLockable<'a> for &mut T {}
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(1);
- ptrs.append(&mut self.0.get_ptrs());
- ptrs
- }
+unsafe impl<'a, A: Lockable<'a>> Lockable<'a> for (A,) {
+ type Guard = (A::Guard,);
- unsafe fn lock(&'a self) -> Self::Output {
- (self.0.lock(),)
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ self.0.get_ptrs(ptrs);
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- self.0.try_lock().map(|a| (a,))
+ unsafe fn guard(&'a self) -> Self::Guard {
+ (self.0.guard(),)
}
}
unsafe impl<'a, A: Lockable<'a>, B: Lockable<'a>> Lockable<'a> for (A, B) {
- type Output = (A::Output, B::Output);
-
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(2);
- ptrs.append(&mut self.0.get_ptrs());
- ptrs.append(&mut self.1.get_ptrs());
- ptrs
- }
+ type Guard = (A::Guard, B::Guard);
- unsafe fn lock(&'a self) -> Self::Output {
- loop {
- let lock0 = self.0.lock();
- let Some(lock1) = self.1.try_lock() else {
- continue;
- };
-
- return (lock0, lock1);
- }
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ self.0.get_ptrs(ptrs);
+ self.1.get_ptrs(ptrs);
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- let Some(lock0) = self.0.try_lock() else {
- return None;
- };
- let Some(lock1) = self.1.try_lock() else {
- return None;
- };
-
- Some((lock0, lock1))
+ unsafe fn guard(&'a self) -> Self::Guard {
+ (self.0.guard(), self.1.guard())
}
}
unsafe impl<'a, A: Lockable<'a>, B: Lockable<'a>, C: Lockable<'a>> Lockable<'a> for (A, B, C) {
- type Output = (A::Output, B::Output, C::Output);
-
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(3);
- ptrs.append(&mut self.0.get_ptrs());
- ptrs.append(&mut self.1.get_ptrs());
- ptrs.append(&mut self.2.get_ptrs());
- ptrs
- }
-
- unsafe fn lock(&'a self) -> Self::Output {
- loop {
- let lock0 = self.0.lock();
- let Some(lock1) = self.1.try_lock() else {
- continue;
- };
- let Some(lock2) = self.2.try_lock() else {
- continue;
- };
-
- return (lock0, lock1, lock2);
- }
- }
+ type Guard = (A::Guard, B::Guard, C::Guard);
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- let Some(lock0) = self.0.try_lock() else {
- return None;
- };
- let Some(lock1) = self.1.try_lock() else {
- return None;
- };
- let Some(lock2) = self.2.try_lock() else {
- return None;
- };
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ self.0.get_ptrs(ptrs);
+ self.1.get_ptrs(ptrs);
+ self.2.get_ptrs(ptrs);
+ }
- Some((lock0, lock1, lock2))
+ unsafe fn guard(&'a self) -> Self::Guard {
+ (self.0.guard(), self.1.guard(), self.2.guard())
}
}
unsafe impl<'a, A: Lockable<'a>, B: Lockable<'a>, C: Lockable<'a>, D: Lockable<'a>> Lockable<'a>
for (A, B, C, D)
{
- type Output = (A::Output, B::Output, C::Output, D::Output);
-
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(4);
- ptrs.append(&mut self.0.get_ptrs());
- ptrs.append(&mut self.1.get_ptrs());
- ptrs.append(&mut self.2.get_ptrs());
- ptrs.append(&mut self.3.get_ptrs());
- ptrs
- }
-
- unsafe fn lock(&'a self) -> Self::Output {
- loop {
- let lock0 = self.0.lock();
- let Some(lock1) = self.1.try_lock() else {
- continue;
- };
- let Some(lock2) = self.2.try_lock() else {
- continue;
- };
- let Some(lock3) = self.3.try_lock() else {
- continue;
- };
-
- return (lock0, lock1, lock2, lock3);
- }
- }
+ type Guard = (A::Guard, B::Guard, C::Guard, D::Guard);
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- let Some(lock0) = self.0.try_lock() else {
- return None;
- };
- let Some(lock1) = self.1.try_lock() else {
- return None;
- };
- let Some(lock2) = self.2.try_lock() else {
- return None;
- };
- let Some(lock3) = self.3.try_lock() else {
- return None;
- };
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ self.0.get_ptrs(ptrs);
+ self.1.get_ptrs(ptrs);
+ self.2.get_ptrs(ptrs);
+ self.3.get_ptrs(ptrs);
+ }
- Some((lock0, lock1, lock2, lock3))
+ unsafe fn guard(&'a self) -> Self::Guard {
+ (
+ self.0.guard(),
+ self.1.guard(),
+ self.2.guard(),
+ self.3.guard(),
+ )
}
}
unsafe impl<'a, A: Lockable<'a>, B: Lockable<'a>, C: Lockable<'a>, D: Lockable<'a>, E: Lockable<'a>>
Lockable<'a> for (A, B, C, D, E)
{
- type Output = (A::Output, B::Output, C::Output, D::Output, E::Output);
-
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(5);
- ptrs.append(&mut self.0.get_ptrs());
- ptrs.append(&mut self.1.get_ptrs());
- ptrs.append(&mut self.2.get_ptrs());
- ptrs.append(&mut self.3.get_ptrs());
- ptrs.append(&mut self.4.get_ptrs());
- ptrs
- }
-
- unsafe fn lock(&'a self) -> Self::Output {
- loop {
- let lock0 = self.0.lock();
- let Some(lock1) = self.1.try_lock() else {
- continue;
- };
- let Some(lock2) = self.2.try_lock() else {
- continue;
- };
- let Some(lock3) = self.3.try_lock() else {
- continue;
- };
- let Some(lock4) = self.4.try_lock() else {
- continue;
- };
-
- return (lock0, lock1, lock2, lock3, lock4);
- }
+ type Guard = (A::Guard, B::Guard, C::Guard, D::Guard, E::Guard);
+
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ self.0.get_ptrs(ptrs);
+ self.1.get_ptrs(ptrs);
+ self.2.get_ptrs(ptrs);
+ self.3.get_ptrs(ptrs);
+ self.4.get_ptrs(ptrs);
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- let Some(lock0) = self.0.try_lock() else {
- return None;
- };
- let Some(lock1) = self.1.try_lock() else {
- return None;
- };
- let Some(lock2) = self.2.try_lock() else {
- return None;
- };
- let Some(lock3) = self.3.try_lock() else {
- return None;
- };
- let Some(lock4) = self.4.try_lock() else {
- return None;
- };
-
- Some((lock0, lock1, lock2, lock3, lock4))
+ unsafe fn guard(&'a self) -> Self::Guard {
+ (
+ self.0.guard(),
+ self.1.guard(),
+ self.2.guard(),
+ self.3.guard(),
+ self.4.guard(),
+ )
}
}
@@ -366,79 +269,81 @@ unsafe impl<
F: Lockable<'a>,
> Lockable<'a> for (A, B, C, D, E, F)
{
- type Output = (
- A::Output,
- B::Output,
- C::Output,
- D::Output,
- E::Output,
- F::Output,
- );
-
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(6);
- ptrs.append(&mut self.0.get_ptrs());
- ptrs.append(&mut self.1.get_ptrs());
- ptrs.append(&mut self.2.get_ptrs());
- ptrs.append(&mut self.3.get_ptrs());
- ptrs.append(&mut self.4.get_ptrs());
- ptrs.append(&mut self.5.get_ptrs());
- ptrs
- }
-
- unsafe fn lock(&'a self) -> Self::Output {
- loop {
- let lock0 = self.0.lock();
- let Some(lock1) = self.1.try_lock() else {
- continue;
- };
- let Some(lock2) = self.2.try_lock() else {
- continue;
- };
- let Some(lock3) = self.3.try_lock() else {
- continue;
- };
- let Some(lock4) = self.4.try_lock() else {
- continue;
- };
- let Some(lock5) = self.5.try_lock() else {
- continue;
- };
-
- return (lock0, lock1, lock2, lock3, lock4, lock5);
- }
+ type Guard = (A::Guard, B::Guard, C::Guard, D::Guard, E::Guard, F::Guard);
+
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ self.0.get_ptrs(ptrs);
+ self.1.get_ptrs(ptrs);
+ self.2.get_ptrs(ptrs);
+ self.3.get_ptrs(ptrs);
+ self.4.get_ptrs(ptrs);
+ self.5.get_ptrs(ptrs);
+ }
+
+ unsafe fn guard(&'a self) -> Self::Guard {
+ (
+ self.0.guard(),
+ self.1.guard(),
+ self.2.guard(),
+ self.3.guard(),
+ self.4.guard(),
+ self.5.guard(),
+ )
}
+}
+
+unsafe impl<
+ 'a,
+ A: Lockable<'a>,
+ B: Lockable<'a>,
+ C: Lockable<'a>,
+ D: Lockable<'a>,
+ E: Lockable<'a>,
+ F: Lockable<'a>,
+ G: Lockable<'a>,
+ > Lockable<'a> for (A, B, C, D, E, F, G)
+{
+ type Guard = (
+ A::Guard,
+ B::Guard,
+ C::Guard,
+ D::Guard,
+ E::Guard,
+ F::Guard,
+ G::Guard,
+ );
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- let Some(lock0) = self.0.try_lock() else {
- return None;
- };
- let Some(lock1) = self.1.try_lock() else {
- return None;
- };
- let Some(lock2) = self.2.try_lock() else {
- return None;
- };
- let Some(lock3) = self.3.try_lock() else {
- return None;
- };
- let Some(lock4) = self.4.try_lock() else {
- return None;
- };
- let Some(lock5) = self.5.try_lock() else {
- return None;
- };
-
- Some((lock0, lock1, lock2, lock3, lock4, lock5))
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ self.0.get_ptrs(ptrs);
+ self.1.get_ptrs(ptrs);
+ self.2.get_ptrs(ptrs);
+ self.3.get_ptrs(ptrs);
+ self.4.get_ptrs(ptrs);
+ self.5.get_ptrs(ptrs);
+ self.6.get_ptrs(ptrs);
+ }
+
+ unsafe fn guard(&'a self) -> Self::Guard {
+ (
+ self.0.guard(),
+ self.1.guard(),
+ self.2.guard(),
+ self.3.guard(),
+ self.4.guard(),
+ self.5.guard(),
+ self.6.guard(),
+ )
}
}
unsafe impl<'a, A: OwnedLockable<'a>> OwnedLockable<'a> for (A,) {}
unsafe impl<'a, A: OwnedLockable<'a>, B: OwnedLockable<'a>> OwnedLockable<'a> for (A, B) {}
+
unsafe impl<'a, A: OwnedLockable<'a>, B: OwnedLockable<'a>, C: OwnedLockable<'a>> OwnedLockable<'a>
for (A, B, C)
{
}
+
unsafe impl<
'a,
A: OwnedLockable<'a>,
@@ -448,6 +353,7 @@ unsafe impl<
> OwnedLockable<'a> for (A, B, C, D)
{
}
+
unsafe impl<
'a,
A: OwnedLockable<'a>,
@@ -458,6 +364,7 @@ unsafe impl<
> OwnedLockable<'a> for (A, B, C, D, E)
{
}
+
unsafe impl<
'a,
A: OwnedLockable<'a>,
@@ -470,194 +377,73 @@ unsafe impl<
{
}
+unsafe impl<
+ 'a,
+ A: OwnedLockable<'a>,
+ B: OwnedLockable<'a>,
+ C: OwnedLockable<'a>,
+ D: OwnedLockable<'a>,
+ E: OwnedLockable<'a>,
+ F: OwnedLockable<'a>,
+ G: OwnedLockable<'a>,
+ > OwnedLockable<'a> for (A, B, C, D, E, F, G)
+{
+}
+
unsafe impl<'a, T: Lockable<'a>, const N: usize> Lockable<'a> for [T; N] {
- type Output = [T::Output; N];
+ type Guard = [T::Guard; N];
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(N);
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
for lock in self {
- ptrs.append(&mut lock.get_ptrs());
- }
- ptrs
- }
-
- unsafe fn lock(&'a self) -> Self::Output {
- unsafe fn unlock_partial<'a, T: Lockable<'a>, const N: usize>(
- guards: [MaybeUninit<T::Output>; N],
- upto: usize,
- ) {
- for (i, guard) in guards.into_iter().enumerate() {
- if i == upto {
- break;
- }
- drop(guard.assume_init());
- }
- }
-
- let mut first_idx = 0;
- 'outer: loop {
- let mut outputs = MaybeUninit::<[MaybeUninit<T::Output>; N]>::uninit().assume_init();
- if N == 0 {
- return outputs.map(|mu| mu.assume_init());
- }
-
- outputs[0].write(self[0].lock());
- for i in 0..N {
- if first_idx == i {
- continue;
- }
-
- match self[i].try_lock() {
- Some(guard) => outputs[i].write(guard),
- None => {
- unlock_partial::<T, N>(outputs, i);
- first_idx = i;
- continue 'outer;
- }
- };
- }
-
- return outputs.map(|mu| mu.assume_init());
+ lock.get_ptrs(ptrs);
}
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- unsafe fn unlock_partial<'a, T: Lockable<'a>, const N: usize>(
- guards: [MaybeUninit<T::Output>; N],
- upto: usize,
- ) {
- for (i, guard) in guards.into_iter().enumerate() {
- if i == upto {
- break;
- }
- drop(guard.assume_init());
- }
- }
-
- let mut outputs = MaybeUninit::<[MaybeUninit<T::Output>; N]>::uninit().assume_init();
+ unsafe fn guard(&'a self) -> Self::Guard {
+ let mut guards = MaybeUninit::<[MaybeUninit<T::Guard>; N]>::uninit().assume_init();
for i in 0..N {
- match self[i].try_lock() {
- Some(guard) => outputs[i].write(guard),
- None => {
- unlock_partial::<T, N>(outputs, i);
- return None;
- }
- };
+ guards[i].write(self[i].guard());
}
- Some(outputs.map(|mu| mu.assume_init()))
+ guards.map(|g| g.assume_init())
}
}
unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for Box<[T]> {
- type Output = Box<[T::Output]>;
-
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(self.len());
- for lock in &**self {
- ptrs.append(&mut lock.get_ptrs());
- }
- ptrs
- }
+ type Guard = Box<[T::Guard]>;
- unsafe fn lock(&'a self) -> Self::Output {
- let mut first_idx = 0;
- if self.is_empty() {
- return Box::new([]);
- }
-
- 'outer: loop {
- let mut outputs = Vec::with_capacity(self.len());
-
- outputs.push(self[first_idx].lock());
- for (idx, lock) in self.iter().enumerate() {
- if first_idx == idx {
- continue;
- }
-
- match lock.try_lock() {
- Some(guard) => {
- outputs.push(guard);
- }
- None => {
- first_idx = idx;
- continue 'outer;
- }
- };
- }
-
- return outputs.into_boxed_slice();
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
+ for lock in self.iter() {
+ lock.get_ptrs(ptrs);
}
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- let mut outputs = Vec::with_capacity(self.len());
- for lock in &**self {
- match lock.try_lock() {
- Some(guard) => {
- outputs.push(guard);
- }
- None => return None,
- };
+ unsafe fn guard(&'a self) -> Self::Guard {
+ let mut guards = Vec::new();
+ for lock in self.iter() {
+ guards.push(lock.guard());
}
- Some(outputs.into_boxed_slice())
+ guards.into_boxed_slice()
}
}
unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for Vec<T> {
- type Output = Vec<T::Output>;
+ type Guard = Vec<T::Guard>;
- fn get_ptrs(&self) -> Vec<usize> {
- let mut ptrs = Vec::with_capacity(self.len());
+ fn get_ptrs(&'a self, ptrs: &mut Vec<&'a dyn Lock>) {
for lock in self {
- ptrs.append(&mut lock.get_ptrs());
- }
- ptrs
- }
-
- unsafe fn lock(&'a self) -> Self::Output {
- let mut first_idx = 0;
- if self.is_empty() {
- return Vec::new();
- }
-
- 'outer: loop {
- let mut outputs = Vec::with_capacity(self.len());
-
- outputs.push(self[first_idx].lock());
- for (idx, lock) in self.iter().enumerate() {
- if first_idx == idx {
- continue;
- }
-
- match lock.try_lock() {
- Some(guard) => {
- outputs.push(guard);
- }
- None => {
- first_idx = idx;
- continue 'outer;
- }
- };
- }
-
- return outputs;
+ lock.get_ptrs(ptrs);
}
}
- unsafe fn try_lock(&'a self) -> Option<Self::Output> {
- let mut outputs = Vec::with_capacity(self.len());
+ unsafe fn guard(&'a self) -> Self::Guard {
+ let mut guards = Vec::new();
for lock in self {
- match lock.try_lock() {
- Some(guard) => {
- outputs.push(guard);
- }
- None => return None,
- };
+ guards.push(lock.guard());
}
- Some(outputs)
+ guards
}
}
diff --git a/src/mutex/guard.rs b/src/mutex/guard.rs
index c7f25e4..38ea125 100644
--- a/src/mutex/guard.rs
+++ b/src/mutex/guard.rs
@@ -35,6 +35,12 @@ impl<'a, T: ?Sized + 'a, R: RawMutex> DerefMut for MutexRef<'a, T, R> {
}
}
+impl<'a, T: ?Sized + 'a, R: RawMutex> MutexRef<'a, T, R> {
+ pub unsafe fn new(mutex: &'a Mutex<T, R>) -> Self {
+ Self(mutex, PhantomData)
+ }
+}
+
impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> Deref
for MutexGuard<'a, 'key, T, Key, R>
{
diff --git a/src/mutex/mutex.rs b/src/mutex/mutex.rs
index 917ab78..3b8c221 100644
--- a/src/mutex/mutex.rs
+++ b/src/mutex/mutex.rs
@@ -24,6 +24,23 @@ impl<T, R: RawMutex> Mutex<T, R> {
data: UnsafeCell::new(data),
}
}
+
+ /// Returns the raw underlying mutex.
+ ///
+ /// Note that you will most likely need to import the [`RawMutex`] trait
+ /// from `lock_api` to be able to call functions on the raw mutex.
+ ///
+ /// # Safety
+ ///
+ /// This method is unsafe because it allows unlocking a mutex while still
+ /// holding a reference to a [`MutexGuard`], and locking a mutex without
+ /// holding the [`ThreadKey`].
+ ///
+ /// [`ThreadKey`]: `crate::ThreadKey`
+ #[must_use]
+ pub const unsafe fn raw(&self) -> &R {
+ &self.raw
+ }
}
impl<T: ?Sized + Default, R: RawMutex> Default for Mutex<T, R> {
@@ -138,15 +155,6 @@ impl<T: ?Sized, R: RawMutex> Mutex<T, R> {
}
}
- /// Lock without a [`ThreadKey`]. You must exclusively own the
- /// [`ThreadKey`] as long as the [`MutexRef`] is alive. This may cause
- /// deadlock if called multiple times without unlocking first.
- pub(crate) unsafe fn lock_no_key(&self) -> MutexRef<'_, T, R> {
- self.raw.lock();
-
- MutexRef(self, PhantomData)
- }
-
/// Attempts to lock the `Mutex` without blocking.
///
/// # Errors
diff --git a/src/rwlock/read_guard.rs b/src/rwlock/read_guard.rs
index 532a6e7..8428987 100644
--- a/src/rwlock/read_guard.rs
+++ b/src/rwlock/read_guard.rs
@@ -26,6 +26,12 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockReadRef<'a, T, R> {
}
}
+impl<'a, T: ?Sized + 'a, R: RawRwLock> RwLockReadRef<'a, T, R> {
+ pub unsafe fn new(mutex: &'a RwLock<T, R>) -> Self {
+ Self(mutex, PhantomData)
+ }
+}
+
impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
for RwLockReadGuard<'a, 'key, T, Key, R>
{
diff --git a/src/rwlock/read_lock.rs b/src/rwlock/read_lock.rs
index 176fc01..133ca7d 100644
--- a/src/rwlock/read_lock.rs
+++ b/src/rwlock/read_lock.rs
@@ -67,12 +67,6 @@ impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> {
self.0.read(key)
}
- /// Creates a shared lock without a key. Locking this without exclusive
- /// access to the key is undefined behavior.
- pub(crate) unsafe fn lock_no_key(&self) -> RwLockReadRef<'_, T, R> {
- self.0.read_no_key()
- }
-
/// Attempts to acquire the underlying [`RwLock`] with shared read access
/// without blocking.
pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs
index dc5ab30..d16befe 100644
--- a/src/rwlock/rwlock.rs
+++ b/src/rwlock/rwlock.rs
@@ -24,6 +24,20 @@ impl<T, R: RawRwLock> RwLock<T, R> {
raw: R::INIT,
}
}
+
+ /// Returns the underlying raw reader-writer lock object.
+ ///
+ /// Note that you will most likely need to import the [`RawRwLock`] trait
+ /// from `lock_api` to be able to call functions on the raw reader-writer
+ /// lock.
+ ///
+ /// # Safety
+ ///
+ /// This method is unsafe because it allows unlocking a mutex while
+ /// still holding a reference to a lock guard.
+ pub const unsafe fn raw(&self) -> &R {
+ &self.raw
+ }
}
impl<T: ?Sized + Default, R: RawRwLock> Default for RwLock<T, R> {
@@ -155,15 +169,6 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
- /// Creates a shared lock without a key. Locking this without exclusive
- /// access to the key is undefined behavior.
- pub(crate) unsafe fn read_no_key(&self) -> RwLockReadRef<'_, T, R> {
- self.raw.lock_shared();
-
- // safety: the lock is locked first
- RwLockReadRef(self, PhantomData)
- }
-
/// Attempts to acquire this `RwLock` with shared read access without
/// blocking.
///
@@ -246,15 +251,6 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
- /// Creates an exclusive lock without a key. Locking this without exclusive
- /// access to the key is undefined behavior.
- pub(crate) unsafe fn write_no_key(&self) -> RwLockWriteRef<'_, T, R> {
- self.raw.lock_exclusive();
-
- // safety: the lock is locked first
- RwLockWriteRef(self, PhantomData)
- }
-
/// Attempts to lock this `RwLock` with exclusive write access.
///
/// This function does not block. If the lock could not be acquired at this
diff --git a/src/rwlock/write_guard.rs b/src/rwlock/write_guard.rs
index 6549822..16b474e 100644
--- a/src/rwlock/write_guard.rs
+++ b/src/rwlock/write_guard.rs
@@ -35,6 +35,12 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockWriteRef<'a, T, R> {
}
}
+impl<'a, T: ?Sized + 'a, R: RawRwLock> RwLockWriteRef<'a, T, R> {
+ pub unsafe fn new(mutex: &'a RwLock<T, R>) -> Self {
+ Self(mutex, PhantomData)
+ }
+}
+
impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
for RwLockWriteGuard<'a, 'key, T, Key, R>
{
diff --git a/src/rwlock/write_lock.rs b/src/rwlock/write_lock.rs
index d7333ae..c6b4c24 100644
--- a/src/rwlock/write_lock.rs
+++ b/src/rwlock/write_lock.rs
@@ -67,12 +67,6 @@ impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> {
self.0.write(key)
}
- /// Creates an exclusive lock without a key. Locking this without exclusive
- /// access to the key is undefined behavior.
- pub(crate) unsafe fn lock_no_key(&self) -> RwLockWriteRef<'_, T, R> {
- self.0.write_no_key()
- }
-
/// Attempts to lock the underlying [`RwLock`] with exclusive write access.
pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
&'s self,