diff options
| author | Botahamec <botahamec@outlook.com> | 2024-12-21 11:27:09 -0500 |
|---|---|---|
| committer | Botahamec <botahamec@outlook.com> | 2024-12-21 11:27:09 -0500 |
| commit | b2281e6aec631dc7c6d69edef9268ce7e00ed1dc (patch) | |
| tree | 4a3d9059e291016dcfaec8b08ac4aee48a7b815a /src/collection | |
| parent | 0ddbb5efa57fb36b2c83a5cd1dc43a5cf426e3ee (diff) | |
Implement lock death, but without any usages
Diffstat (limited to 'src/collection')
| -rw-r--r-- | src/collection/boxed.rs | 46 | ||||
| -rw-r--r-- | src/collection/guard.rs | 2 | ||||
| -rw-r--r-- | src/collection/owned.rs | 41 | ||||
| -rw-r--r-- | src/collection/ref.rs | 32 | ||||
| -rw-r--r-- | src/collection/retry.rs | 268 | ||||
| -rw-r--r-- | src/collection/utils.rs | 8 |
6 files changed, 160 insertions, 237 deletions
diff --git a/src/collection/boxed.rs b/src/collection/boxed.rs index c359098..bef3df2 100644 --- a/src/collection/boxed.rs +++ b/src/collection/boxed.rs @@ -21,43 +21,55 @@ fn contains_duplicates(l: &[&dyn RawLock]) -> bool { } unsafe impl<L: Lockable + Send + Sync> RawLock for BoxedLockCollection<L> { - unsafe fn lock(&self) { + fn kill(&self) { + for lock in &self.locks { + lock.kill(); + } + } + + unsafe fn raw_lock(&self) { for lock in self.locks() { - lock.lock(); + lock.raw_lock(); } } - unsafe fn try_lock(&self) -> bool { + unsafe fn raw_try_lock(&self) -> bool { utils::ordered_try_lock(self.locks()) } - unsafe fn unlock(&self) { + unsafe fn raw_unlock(&self) { for lock in self.locks() { - lock.unlock(); + lock.raw_unlock(); } } - unsafe fn read(&self) { + unsafe fn raw_read(&self) { for lock in self.locks() { - lock.read(); + lock.raw_read(); } } - unsafe fn try_read(&self) -> bool { + unsafe fn raw_try_read(&self) -> bool { utils::ordered_try_read(self.locks()) } - unsafe fn unlock_read(&self) { + unsafe fn raw_unlock_read(&self) { for lock in self.locks() { - lock.unlock_read(); + lock.raw_unlock_read(); } } } unsafe impl<L: Lockable> Lockable for BoxedLockCollection<L> { - type Guard<'g> = L::Guard<'g> where Self: 'g; + type Guard<'g> + = L::Guard<'g> + where + Self: 'g; - type ReadGuard<'g> = L::ReadGuard<'g> where Self: 'g; + type ReadGuard<'g> + = L::ReadGuard<'g> + where + Self: 'g; fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn RawLock>) { ptrs.extend(self.locks()) @@ -109,6 +121,8 @@ impl<L: OwnedLockable, I: FromIterator<L> + OwnedLockable> FromIterator<L> } } +// safety: the RawLocks must be send because they come from the Send Lockable +#[allow(clippy::non_send_fields_in_send_ty)] unsafe impl<L: Send> Send for BoxedLockCollection<L> {} unsafe impl<L: Sync> Sync for BoxedLockCollection<L> {} @@ -261,11 +275,11 @@ impl<L: Lockable> BoxedLockCollection<L> { data_ref.get_ptrs(&mut locks); // cast to *const () because fat pointers can't be converted to usize - locks.sort_by_key(|lock| (*lock as *const dyn RawLock).cast::<()>() as usize); + locks.sort_by_key(|lock| (&raw const **lock).cast::<()>() as usize); // safety we're just changing the lifetimes let locks: Vec<&'static dyn RawLock> = std::mem::transmute(locks); - let data = data as *const UnsafeCell<L>; + let data = &raw const *data; Self { data, locks } } @@ -323,7 +337,7 @@ impl<L: Lockable> BoxedLockCollection<L> { ) -> LockGuard<'key, L::Guard<'g>, Key> { for lock in self.locks() { // safety: we have the thread key - unsafe { lock.lock() }; + unsafe { lock.raw_lock() }; } LockGuard { @@ -427,7 +441,7 @@ impl<L: Sharable> BoxedLockCollection<L> { ) -> LockGuard<'key, L::ReadGuard<'g>, Key> { for lock in self.locks() { // safety: we have the thread key - unsafe { lock.read() }; + unsafe { lock.raw_read() }; } LockGuard { diff --git a/src/collection/guard.rs b/src/collection/guard.rs index 70bb3a6..d604680 100644 --- a/src/collection/guard.rs +++ b/src/collection/guard.rs @@ -48,8 +48,6 @@ mod tests { use crate::collection::OwnedLockCollection; use crate::{RwLock, ThreadKey}; - use super::*; - #[test] fn guard_display_works() { let key = ThreadKey::get().unwrap(); diff --git a/src/collection/owned.rs b/src/collection/owned.rs index 9aa7460..69347cc 100644 --- a/src/collection/owned.rs +++ b/src/collection/owned.rs @@ -12,49 +12,62 @@ fn get_locks<L: Lockable>(data: &L) -> Vec<&dyn RawLock> { } unsafe impl<L: Lockable + Send + Sync> RawLock for OwnedLockCollection<L> { - unsafe fn lock(&self) { + fn kill(&self) { let locks = get_locks(&self.data); for lock in locks { - lock.lock(); + lock.kill(); } } - unsafe fn try_lock(&self) -> bool { + unsafe fn raw_lock(&self) { + let locks = get_locks(&self.data); + for lock in locks { + lock.raw_lock(); + } + } + + unsafe fn raw_try_lock(&self) -> bool { let locks = get_locks(&self.data); utils::ordered_try_lock(&locks) } - unsafe fn unlock(&self) { + unsafe fn raw_unlock(&self) { let locks = get_locks(&self.data); for lock in locks { - lock.unlock(); + lock.raw_unlock(); } } - unsafe fn read(&self) { + unsafe fn raw_read(&self) { let locks = get_locks(&self.data); for lock in locks { - lock.read(); + lock.raw_read(); } } - unsafe fn try_read(&self) -> bool { + unsafe fn raw_try_read(&self) -> bool { let locks = get_locks(&self.data); utils::ordered_try_read(&locks) } - unsafe fn unlock_read(&self) { + unsafe fn raw_unlock_read(&self) { let locks = get_locks(&self.data); for lock in locks { - lock.unlock_read(); + lock.raw_unlock_read(); } } } unsafe impl<L: Lockable> Lockable for OwnedLockCollection<L> { - type Guard<'g> = L::Guard<'g> where Self: 'g; + type Guard<'g> + = L::Guard<'g> + where + Self: 'g; - type ReadGuard<'g> = L::ReadGuard<'g> where Self: 'g; + type ReadGuard<'g> + = L::ReadGuard<'g> + where + Self: 'g; fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn RawLock>) { self.data.get_ptrs(ptrs) @@ -196,7 +209,7 @@ impl<L: OwnedLockable> OwnedLockCollection<L> { for lock in locks { // safety: we have the thread key, and these locks happen in a // predetermined order - unsafe { lock.lock() }; + unsafe { lock.raw_lock() }; } // safety: we've locked all of this already @@ -310,7 +323,7 @@ impl<L: Sharable> OwnedLockCollection<L> { for lock in locks { // safety: we have the thread key, and these locks happen in a // predetermined order - unsafe { lock.read() }; + unsafe { lock.raw_read() }; } // safety: we've locked all of this already diff --git a/src/collection/ref.rs b/src/collection/ref.rs index 7c0d40a..0e2f057 100644 --- a/src/collection/ref.rs +++ b/src/collection/ref.rs @@ -10,7 +10,7 @@ use super::{utils, LockGuard, RefLockCollection}; pub fn get_locks<L: Lockable>(data: &L) -> Vec<&dyn RawLock> { let mut locks = Vec::new(); data.get_ptrs(&mut locks); - locks.sort_by_key(|lock| *lock as *const dyn RawLock); + locks.sort_by_key(|lock| &raw const **lock); locks } @@ -45,35 +45,41 @@ where } unsafe impl<L: Lockable + Send + Sync> RawLock for RefLockCollection<'_, L> { - unsafe fn lock(&self) { + fn kill(&self) { for lock in &self.locks { - lock.lock(); + lock.kill(); } } - unsafe fn try_lock(&self) -> bool { + unsafe fn raw_lock(&self) { + for lock in &self.locks { + lock.raw_lock(); + } + } + + unsafe fn raw_try_lock(&self) -> bool { utils::ordered_try_lock(&self.locks) } - unsafe fn unlock(&self) { + unsafe fn raw_unlock(&self) { for lock in &self.locks { - lock.unlock(); + lock.raw_unlock(); } } - unsafe fn read(&self) { + unsafe fn raw_read(&self) { for lock in &self.locks { - lock.read(); + lock.raw_read(); } } - unsafe fn try_read(&self) -> bool { + unsafe fn raw_try_read(&self) -> bool { utils::ordered_try_read(&self.locks) } - unsafe fn unlock_read(&self) { + unsafe fn raw_unlock_read(&self) { for lock in &self.locks { - lock.unlock_read(); + lock.raw_unlock_read(); } } } @@ -225,7 +231,7 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> { ) -> LockGuard<'key, L::Guard<'a>, Key> { for lock in &self.locks { // safety: we have the thread key - unsafe { lock.lock() }; + unsafe { lock.raw_lock() }; } LockGuard { @@ -333,7 +339,7 @@ impl<'a, L: Sharable> RefLockCollection<'a, L> { ) -> LockGuard<'key, L::ReadGuard<'a>, Key> { for lock in &self.locks { // safety: we have the thread key - unsafe { lock.read() }; + unsafe { lock.raw_read() }; } LockGuard { diff --git a/src/collection/retry.rs b/src/collection/retry.rs index 8a10fc3..05adc3e 100644 --- a/src/collection/retry.rs +++ b/src/collection/retry.rs @@ -8,11 +8,18 @@ use std::marker::PhantomData; use super::{LockGuard, RetryingLockCollection}; +/// Get all raw locks in the collection +fn get_locks<L: Lockable>(data: &L) -> Vec<&dyn RawLock> { + let mut locks = Vec::new(); + data.get_ptrs(&mut locks); + locks +} + /// Checks that a collection contains no duplicate references to a lock. fn contains_duplicates<L: Lockable>(data: L) -> bool { let mut locks = Vec::new(); data.get_ptrs(&mut locks); - let locks = locks.into_iter().map(|l| l as *const dyn RawLock); + let locks = locks.into_iter().map(|l| &raw const *l); let mut locks_set = HashSet::with_capacity(locks.len()); for lock in locks { @@ -24,11 +31,17 @@ fn contains_duplicates<L: Lockable>(data: L) -> bool { false } -unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { - unsafe fn lock(&self) { +unsafe impl<L: Lockable> RawLock for RetryingLockCollection<L> { + fn kill(&self) { + let locks = get_locks(&self.data); + for lock in locks { + lock.kill(); + } + } + + unsafe fn raw_lock(&self) { let mut first_index = 0; - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); + let locks = get_locks(&self.data); if locks.is_empty() { return; @@ -37,23 +50,27 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { unsafe { 'outer: loop { // safety: we have the thread key - locks[first_index].lock(); + locks[first_index].raw_lock(); for (i, lock) in locks.iter().enumerate() { if i == first_index { continue; } + // If the lock has been killed, then this returns false + // instead of panicking. This sounds like a problem, but if + // it does return false, then the lock function is called + // immediately after, causing a panic // safety: we have the thread key - if !lock.try_lock() { + if !lock.raw_try_lock() { for lock in locks.iter().take(i) { // safety: we already locked all of these - lock.unlock(); + lock.raw_unlock(); } if first_index >= i { // safety: this is already locked and can't be unlocked // by the previous loop - locks[first_index].unlock(); + locks[first_index].raw_unlock(); } first_index = i; @@ -67,9 +84,8 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { }; } - unsafe fn try_lock(&self) -> bool { - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); + unsafe fn raw_try_lock(&self) -> bool { + let locks = get_locks(&self.data); if locks.is_empty() { return true; @@ -78,10 +94,10 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { unsafe { for (i, lock) in locks.iter().enumerate() { // safety: we have the thread key - if !lock.try_lock() { + if !lock.raw_try_lock() { for lock in locks.iter().take(i) { // safety: we already locked all of these - lock.unlock(); + lock.raw_unlock(); } return false; } @@ -91,39 +107,37 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { true } - unsafe fn unlock(&self) { - let mut locks = Vec::new(); - self.get_ptrs(&mut locks); + unsafe fn raw_unlock(&self) { + let locks = get_locks(&self.data); for lock in locks { - lock.unlock(); + lock.raw_unlock(); } } - unsafe fn read(&self) { + unsafe fn raw_read(&self) { let mut first_index = 0; - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); + let locks = get_locks(&self.data); 'outer: loop { // safety: we have the thread key - locks[first_index].read(); + locks[first_index].raw_read(); for (i, lock) in locks.iter().enumerate() { if i == first_index { continue; } // safety: we have the thread key - if !lock.try_read() { + if !lock.raw_try_read() { for lock in locks.iter().take(i) { // safety: we already locked all of these - lock.unlock_read(); + lock.raw_unlock_read(); } if first_index >= i { // safety: this is already locked and can't be unlocked // by the previous loop - locks[first_index].unlock_read(); + locks[first_index].raw_unlock_read(); } first_index = i; @@ -133,9 +147,8 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { } } - unsafe fn try_read(&self) -> bool { - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); + unsafe fn raw_try_read(&self) -> bool { + let locks = get_locks(&self.data); if locks.is_empty() { return true; @@ -144,10 +157,10 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { unsafe { for (i, lock) in locks.iter().enumerate() { // safety: we have the thread key - if !lock.try_read() { + if !lock.raw_try_read() { for lock in locks.iter().take(i) { // safety: we already locked all of these - lock.unlock_read(); + lock.raw_unlock_read(); } return false; } @@ -157,20 +170,25 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> { true } - unsafe fn unlock_read(&self) { - let mut locks = Vec::new(); - self.get_ptrs(&mut locks); + unsafe fn raw_unlock_read(&self) { + let locks = get_locks(&self.data); for lock in locks { - lock.unlock_read(); + lock.raw_unlock_read(); } } } unsafe impl<L: Lockable> Lockable for RetryingLockCollection<L> { - type Guard<'g> = L::Guard<'g> where Self: 'g; + type Guard<'g> + = L::Guard<'g> + where + Self: 'g; - type ReadGuard<'g> = L::ReadGuard<'g> where Self: 'g; + type ReadGuard<'g> + = L::ReadGuard<'g> + where + Self: 'g; fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn RawLock>) { self.data.get_ptrs(ptrs) @@ -186,7 +204,8 @@ unsafe impl<L: Lockable> Lockable for RetryingLockCollection<L> { } impl<L: LockableAsMut> LockableAsMut for RetryingLockCollection<L> { - type Inner<'a> = L::Inner<'a> + type Inner<'a> + = L::Inner<'a> where Self: 'a; @@ -419,55 +438,16 @@ impl<L: Lockable> RetryingLockCollection<L> { &'g self, key: Key, ) -> LockGuard<'key, L::Guard<'g>, Key> { - let mut first_index = 0; - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); + unsafe { + // safety: we're taking the thread key + self.raw_lock(); - if locks.is_empty() { - return LockGuard { - // safety: there's no data being returned - guard: unsafe { self.data.guard() }, + LockGuard { + // safety: we just locked the collection + guard: self.guard(), key, _phantom: PhantomData, - }; - } - - let guard = unsafe { - 'outer: loop { - // safety: we have the thread key - locks[first_index].lock(); - for (i, lock) in locks.iter().enumerate() { - if i == first_index { - continue; - } - - // safety: we have the thread key - if !lock.try_lock() { - for lock in locks.iter().take(i) { - // safety: we already locked all of these - lock.unlock(); - } - - if first_index >= i { - // safety: this is already locked and can't be unlocked - // by the previous loop - locks[first_index].unlock(); - } - - first_index = i; - continue 'outer; - } - } - - // safety: we locked all the data - break self.data.guard(); } - }; - - LockGuard { - guard, - key, - _phantom: PhantomData, } } @@ -500,39 +480,15 @@ impl<L: Lockable> RetryingLockCollection<L> { &'g self, key: Key, ) -> Option<LockGuard<'key, L::Guard<'g>, Key>> { - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); - - if locks.is_empty() { - return Some(LockGuard { - // safety: there's no data being returned - guard: unsafe { self.data.guard() }, + unsafe { + // safety: we're taking the thread key + self.raw_try_lock().then(|| LockGuard { + // safety: we just succeeded in locking everything + guard: self.guard(), key, _phantom: PhantomData, - }); + }) } - - let guard = unsafe { - for (i, lock) in locks.iter().enumerate() { - // safety: we have the thread key - if !lock.try_lock() { - for lock in locks.iter().take(i) { - // safety: we already locked all of these - lock.unlock(); - } - return None; - } - } - - // safety: we locked all the data - self.data.guard() - }; - - Some(LockGuard { - guard, - key, - _phantom: PhantomData, - }) } /// Unlocks the underlying lockable data type, returning the key that's @@ -584,55 +540,16 @@ impl<L: Sharable> RetryingLockCollection<L> { &'g self, key: Key, ) -> LockGuard<'key, L::ReadGuard<'g>, Key> { - let mut first_index = 0; - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); + unsafe { + // safety: we're taking the thread key + self.raw_read(); - if locks.is_empty() { - return LockGuard { - // safety: there's no data being returned - guard: unsafe { self.data.read_guard() }, + LockGuard { + // safety: we just locked the collection + guard: self.read_guard(), key, _phantom: PhantomData, - }; - } - - let guard = unsafe { - 'outer: loop { - // safety: we have the thread key - locks[first_index].read(); - for (i, lock) in locks.iter().enumerate() { - if i == first_index { - continue; - } - - // safety: we have the thread key - if !lock.try_read() { - for lock in locks.iter().take(i) { - // safety: we already locked all of these - lock.unlock_read(); - } - - if first_index >= i { - // safety: this is already locked and can't be unlocked - // by the previous loop - locks[first_index].unlock_read(); - } - - first_index = i; - continue 'outer; - } - } - - // safety: we locked all the data - break self.data.read_guard(); } - }; - - LockGuard { - guard, - key, - _phantom: PhantomData, } } @@ -666,39 +583,15 @@ impl<L: Sharable> RetryingLockCollection<L> { &'g self, key: Key, ) -> Option<LockGuard<'key, L::ReadGuard<'g>, Key>> { - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); - - if locks.is_empty() { - return Some(LockGuard { - // safety: there's no data being returned - guard: unsafe { self.data.read_guard() }, + unsafe { + // safety: we're taking the thread key + self.raw_try_lock().then(|| LockGuard { + // safety: we just succeeded in locking everything + guard: self.read_guard(), key, _phantom: PhantomData, - }); + }) } - - let guard = unsafe { - for (i, lock) in locks.iter().enumerate() { - // safety: we have the thread key - if !lock.try_read() { - for lock in locks.iter().take(i) { - // safety: we already locked all of these - lock.unlock_read(); - } - return None; - } - } - - // safety: we locked all the data - self.data.read_guard() - }; - - Some(LockGuard { - guard, - key, - _phantom: PhantomData, - }) } /// Unlocks the underlying lockable data type, returning the key that's @@ -786,7 +679,6 @@ mod tests { use super::*; use crate::collection::BoxedLockCollection; use crate::{Mutex, RwLock, ThreadKey}; - use lock_api::{RawMutex, RawRwLock}; #[test] fn nonduplicate_lock_references_are_allowed() { diff --git a/src/collection/utils.rs b/src/collection/utils.rs index 8177c1d..c114541 100644 --- a/src/collection/utils.rs +++ b/src/collection/utils.rs @@ -7,12 +7,12 @@ pub unsafe fn ordered_try_lock(locks: &[&dyn RawLock]) -> bool { unsafe { for (i, lock) in locks.iter().enumerate() { // safety: we have the thread key - let success = lock.try_lock(); + let success = lock.raw_try_lock(); if !success { for lock in &locks[0..i] { // safety: this lock was already acquired - lock.unlock(); + lock.raw_unlock(); } return false; } @@ -28,12 +28,12 @@ pub unsafe fn ordered_try_read(locks: &[&dyn RawLock]) -> bool { unsafe { for (i, lock) in locks.iter().enumerate() { // safety: we have the thread key - let success = lock.try_read(); + let success = lock.raw_try_read(); if !success { for lock in &locks[0..i] { // safety: this lock was already acquired - lock.unlock_read(); + lock.raw_unlock_read(); } return false; } |
