summaryrefslogtreecommitdiff
path: root/src/collection
diff options
context:
space:
mode:
Diffstat (limited to 'src/collection')
-rw-r--r--src/collection/boxed.rs34
-rw-r--r--src/collection/guard.rs16
-rw-r--r--src/collection/owned.rs17
-rw-r--r--src/collection/ref.rs34
-rw-r--r--src/collection/retry.rs127
5 files changed, 209 insertions, 19 deletions
diff --git a/src/collection/boxed.rs b/src/collection/boxed.rs
index b0d1e3b..c359098 100644
--- a/src/collection/boxed.rs
+++ b/src/collection/boxed.rs
@@ -532,3 +532,37 @@ where
self.into_iter()
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{Mutex, ThreadKey};
+
+ #[test]
+ fn non_duplicates_allowed() {
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(1);
+ assert!(BoxedLockCollection::try_new([&mutex1, &mutex2]).is_some())
+ }
+
+ #[test]
+ fn duplicates_not_allowed() {
+ let mutex1 = Mutex::new(0);
+ assert!(BoxedLockCollection::try_new([&mutex1, &mutex1]).is_none())
+ }
+
+ #[test]
+ fn works_in_collection() {
+ let key = ThreadKey::get().unwrap();
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(1);
+ let collection =
+ BoxedLockCollection::try_new(BoxedLockCollection::try_new([&mutex1, &mutex2]).unwrap())
+ .unwrap();
+
+ let guard = collection.lock(key);
+ assert!(mutex1.is_locked());
+ assert!(mutex2.is_locked());
+ drop(guard);
+ }
+}
diff --git a/src/collection/guard.rs b/src/collection/guard.rs
index 8857c5f..0b8a583 100644
--- a/src/collection/guard.rs
+++ b/src/collection/guard.rs
@@ -42,3 +42,19 @@ impl<'key, Guard, Key: Keyable> AsMut<Guard> for LockGuard<'key, Guard, Key> {
&mut self.guard
}
}
+
+#[cfg(test)]
+mod tests {
+ use crate::collection::OwnedLockCollection;
+ use crate::{RwLock, ThreadKey};
+
+ use super::*;
+
+ #[test]
+ fn guard_display_works() {
+ let key = ThreadKey::get().unwrap();
+ let lock = OwnedLockCollection::new(RwLock::new("Hello, world!"));
+ let guard = lock.read(key);
+ assert_eq!(guard.to_string(), "Hello, world!".to_string());
+ }
+}
diff --git a/src/collection/owned.rs b/src/collection/owned.rs
index f2b6cc9..9aa7460 100644
--- a/src/collection/owned.rs
+++ b/src/collection/owned.rs
@@ -393,3 +393,20 @@ impl<L: Sharable> OwnedLockCollection<L> {
guard.key
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::Mutex;
+
+ #[test]
+ fn can_be_extended() {
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(1);
+ let mut collection = OwnedLockCollection::new(vec![mutex1, mutex2]);
+
+ collection.extend([Mutex::new(2)]);
+
+ assert_eq!(collection.data.len(), 3);
+ }
+}
diff --git a/src/collection/ref.rs b/src/collection/ref.rs
index 8b9e0f8..60abdfa 100644
--- a/src/collection/ref.rs
+++ b/src/collection/ref.rs
@@ -436,3 +436,37 @@ where
self.into_iter()
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{Mutex, ThreadKey};
+
+ #[test]
+ fn non_duplicates_allowed() {
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(1);
+ assert!(RefLockCollection::try_new(&[&mutex1, &mutex2]).is_some())
+ }
+
+ #[test]
+ fn duplicates_not_allowed() {
+ let mutex1 = Mutex::new(0);
+ assert!(RefLockCollection::try_new(&[&mutex1, &mutex1]).is_none())
+ }
+
+ #[test]
+ fn works_in_collection() {
+ let key = ThreadKey::get().unwrap();
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(1);
+ let collection0 = [&mutex1, &mutex2];
+ let collection1 = RefLockCollection::try_new(&collection0).unwrap();
+ let collection = RefLockCollection::try_new(&collection1).unwrap();
+
+ let guard = collection.lock(key);
+ assert!(mutex1.is_locked());
+ assert!(mutex2.is_locked());
+ drop(guard);
+ }
+}
diff --git a/src/collection/retry.rs b/src/collection/retry.rs
index 7aa4ef4..8a10fc3 100644
--- a/src/collection/retry.rs
+++ b/src/collection/retry.rs
@@ -30,32 +30,41 @@ unsafe impl<L: Lockable + Send + Sync> RawLock for RetryingLockCollection<L> {
let mut locks = Vec::new();
self.data.get_ptrs(&mut locks);
- 'outer: loop {
- // safety: we have the thread key
- locks[first_index].lock();
- for (i, lock) in locks.iter().enumerate() {
- if i == first_index {
- continue;
- }
+ if locks.is_empty() {
+ return;
+ }
+ unsafe {
+ 'outer: loop {
// 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();
+ locks[first_index].lock();
+ for (i, lock) in locks.iter().enumerate() {
+ if i == first_index {
+ continue;
}
- if first_index >= i {
- // safety: this is already locked and can't be unlocked
- // by the previous loop
- locks[first_index].unlock();
- }
+ // 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();
+ }
- first_index = i;
- continue 'outer;
+ 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;
}
- }
+ };
}
unsafe fn try_lock(&self) -> bool {
@@ -771,3 +780,83 @@ where
self.into_iter()
}
}
+
+#[cfg(test)]
+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() {
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(0);
+ assert!(RetryingLockCollection::try_new([&mutex1, &mutex2]).is_some());
+ }
+
+ #[test]
+ fn duplicate_lock_references_are_disallowed() {
+ let mutex = Mutex::new(0);
+ assert!(RetryingLockCollection::try_new([&mutex, &mutex]).is_none());
+ }
+
+ #[test]
+ fn locks_all_inner_mutexes() {
+ let key = ThreadKey::get().unwrap();
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(0);
+ let collection = RetryingLockCollection::try_new([&mutex1, &mutex2]).unwrap();
+
+ let guard = collection.lock(key);
+
+ assert!(mutex1.is_locked());
+ assert!(mutex2.is_locked());
+
+ drop(guard);
+ }
+
+ #[test]
+ fn locks_all_inner_rwlocks() {
+ let key = ThreadKey::get().unwrap();
+ let rwlock1 = RwLock::new(0);
+ let rwlock2 = RwLock::new(0);
+ let collection = RetryingLockCollection::try_new([&rwlock1, &rwlock2]).unwrap();
+ // TODO Poisonable::read
+
+ let guard = collection.read(key);
+
+ assert!(rwlock1.is_locked());
+ assert!(rwlock2.is_locked());
+
+ drop(guard);
+ }
+
+ #[test]
+ fn works_with_other_collections() {
+ let key = ThreadKey::get().unwrap();
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(0);
+ let collection = BoxedLockCollection::try_new(
+ RetryingLockCollection::try_new([&mutex1, &mutex2]).unwrap(),
+ )
+ .unwrap();
+
+ let guard = collection.lock(key);
+
+ assert!(mutex1.is_locked());
+ assert!(mutex2.is_locked());
+ drop(guard);
+ }
+
+ #[test]
+ fn extend_collection() {
+ let mutex1 = Mutex::new(0);
+ let mutex2 = Mutex::new(0);
+ let mut collection = RetryingLockCollection::new(vec![mutex1]);
+
+ collection.extend([mutex2]);
+
+ assert_eq!(collection.into_inner().len(), 2);
+ }
+}