diff options
| -rw-r--r-- | examples/dining_philosophers.rs | 2 | ||||
| -rw-r--r-- | examples/double_mutex.rs | 2 | ||||
| -rw-r--r-- | examples/list.rs | 2 | ||||
| -rw-r--r-- | src/collection.rs | 18 | ||||
| -rw-r--r-- | src/collection/boxed_collection.rs | 60 | ||||
| -rw-r--r-- | src/collection/owned_collection.rs | 68 | ||||
| -rw-r--r-- | src/collection/ref_collection.rs (renamed from src/collection/collection.rs) | 1 | ||||
| -rw-r--r-- | src/lib.rs | 1 |
8 files changed, 137 insertions, 17 deletions
diff --git a/examples/dining_philosophers.rs b/examples/dining_philosophers.rs index 34efb0e..2f2fa0d 100644 --- a/examples/dining_philosophers.rs +++ b/examples/dining_philosophers.rs @@ -1,6 +1,6 @@ use std::{thread, time::Duration}; -use happylock::{Mutex, RefLockCollection, ThreadKey}; +use happylock::{collection::RefLockCollection, Mutex, ThreadKey}; static PHILOSOPHERS: [Philosopher; 5] = [ Philosopher { diff --git a/examples/double_mutex.rs b/examples/double_mutex.rs index cd627c4..e2b08df 100644 --- a/examples/double_mutex.rs +++ b/examples/double_mutex.rs @@ -1,6 +1,6 @@ use std::thread; -use happylock::{Mutex, RefLockCollection, ThreadKey}; +use happylock::{collection::RefLockCollection, Mutex, ThreadKey}; const N: usize = 10; diff --git a/examples/list.rs b/examples/list.rs index cf344e7..dda468a 100644 --- a/examples/list.rs +++ b/examples/list.rs @@ -1,6 +1,6 @@ use std::thread; -use happylock::{Mutex, RefLockCollection, ThreadKey}; +use happylock::{collection::RefLockCollection, Mutex, ThreadKey}; const N: usize = 10; diff --git a/src/collection.rs b/src/collection.rs index 1c276a6..93adf16 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -1,13 +1,14 @@ -use std::marker::{PhantomData, PhantomPinned}; -use std::ptr::NonNull; +use std::{marker::PhantomData, ptr::NonNull}; use crate::{ key::Keyable, lockable::{Lock, Lockable}, }; -mod collection; +mod boxed_collection; mod guard; +mod owned_collection; +mod ref_collection; pub struct OwnedLockCollection<L> { data: L, @@ -22,16 +23,7 @@ pub struct RefLockCollection<'a, L> { 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> {} +pub struct BoxedLockCollection<'a, L>(RefLockCollection<'a, L>); /// A RAII guard for a generic [`Lockable`] type. pub struct LockGuard<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable + 'key> { diff --git a/src/collection/boxed_collection.rs b/src/collection/boxed_collection.rs new file mode 100644 index 0000000..bcb941b --- /dev/null +++ b/src/collection/boxed_collection.rs @@ -0,0 +1,60 @@ +use std::ops::{Deref, DerefMut}; + +use crate::{Lockable, OwnedLockable}; + +use super::{BoxedLockCollection, RefLockCollection}; + +impl<'a, L> Deref for BoxedLockCollection<'a, L> { + type Target = RefLockCollection<'a, L>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, L> DerefMut for BoxedLockCollection<'a, L> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl<'a, L> Drop for BoxedLockCollection<'a, L> { + fn drop(&mut self) { + // this was created with Box::new + let boxed = unsafe { Box::from_raw((self.0.data as *const L).cast_mut()) }; + drop(boxed); + } +} + +impl<'a, L: OwnedLockable<'a> + 'a> BoxedLockCollection<'a, L> { + #[must_use] + pub fn new(data: L) -> Self { + let boxed = Box::leak(Box::new(data)); + Self(RefLockCollection::new(boxed)) + } +} + +impl<'a, L: OwnedLockable<'a> + 'a> BoxedLockCollection<'a, &'a L> { + #[must_use] + pub fn new_ref(data: &'a L) -> Self { + let boxed = Box::leak(Box::new(data)); + + // this is a reference to an OwnedLockable, which can't possibly + // contain inner duplicates + Self(unsafe { RefLockCollection::new_unchecked(boxed) }) + } +} + +impl<'a, L: Lockable<'a> + 'a> BoxedLockCollection<'a, L> { + #[must_use] + pub unsafe fn new_unchecked(data: L) -> Self { + let boxed = Box::leak(Box::new(data)); + Self(RefLockCollection::new_unchecked(boxed)) + } + + #[must_use] + pub fn try_new(data: L) -> Option<Self> { + let boxed = Box::leak(Box::new(data)); + RefLockCollection::try_new(boxed).map(Self) + } +} diff --git a/src/collection/owned_collection.rs b/src/collection/owned_collection.rs new file mode 100644 index 0000000..dbc9a45 --- /dev/null +++ b/src/collection/owned_collection.rs @@ -0,0 +1,68 @@ +use std::marker::PhantomData; + +use crate::{lockable::Lock, Keyable, Lockable, OwnedLockable}; + +use super::{LockGuard, OwnedLockCollection}; + +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 +} + +impl<'a, L: OwnedLockable<'a>> OwnedLockCollection<L> { + #[must_use] + pub const fn new(data: L) -> Self { + Self { data } + } + + pub fn lock<'s: 'a, 'key, Key: Keyable + 'key>( + &'s self, + key: Key, + ) -> LockGuard<'a, 'key, L, Key> { + let locks = get_locks(&self.data); + for lock in locks { + // safety: we have the thread key, and these locks happen in a + // predetermined order + unsafe { lock.lock() }; + } + + // safety: we've locked all of this already + let guard = unsafe { self.data.guard() }; + LockGuard { + guard, + key, + _phantom: PhantomData, + } + } + + pub fn try_lock<'key: 'a, Key: Keyable + 'key>( + &'a self, + key: Key, + ) -> Option<LockGuard<'a, 'key, L, Key>> { + let locks = get_locks(&self.data); + let guard = unsafe { + for (i, lock) in locks.iter().enumerate() { + // safety: we have the thread key + let success = lock.try_lock(); + + if !success { + for lock in &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, + }) + } +} diff --git a/src/collection/collection.rs b/src/collection/ref_collection.rs index a8d25a5..3e4d5f8 100644 --- a/src/collection/collection.rs +++ b/src/collection/ref_collection.rs @@ -4,6 +4,7 @@ use crate::{key::Keyable, lockable::Lock, Lockable, OwnedLockable}; use super::{LockGuard, RefLockCollection}; +#[must_use] 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); @@ -113,7 +113,6 @@ pub mod collection; pub mod mutex; pub mod rwlock; -pub use collection::RefLockCollection; pub use key::{Keyable, ThreadKey}; pub use lockable::{Lockable, OwnedLockable}; |
