summaryrefslogtreecommitdiff
path: root/src/collection
diff options
context:
space:
mode:
Diffstat (limited to 'src/collection')
-rw-r--r--src/collection/boxed.rs46
-rw-r--r--src/collection/guard.rs2
-rw-r--r--src/collection/owned.rs41
-rw-r--r--src/collection/ref.rs32
-rw-r--r--src/collection/retry.rs268
-rw-r--r--src/collection/utils.rs8
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;
}