Skip to content

Instantly share code, notes, and snippets.

@thomcc
Created August 7, 2021 21:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thomcc/6ca2bef4b7526caeda06f4cceaabfe70 to your computer and use it in GitHub Desktop.
Save thomcc/6ca2bef4b7526caeda06f4cceaabfe70 to your computer and use it in GitHub Desktop.
// use `cobb = "0.0.1"`
#[track_caller]
fn cobb_test<Lock: RawLock>() {
let threads = 16;
cobb::run_test(cobb::TestCfg {
threads,
iterations: 1000,
setup: || Mutex::<Vec<usize>, Lock>::new(vec![]),
// teardown: (),
test: |lock, context| {
lock.with_lock(|data| data.push(context.thread_index()));
},
before_each: |lock| {
assert!(!lock.is_locked());
lock.with_lock(|v| *v = vec![]);
},
after_each: |l| {
assert!(!l.is_locked());
// Ensure every thread id is present exactly once.
l.with_lock(|v| {
v.sort();
v.dedup();
assert_eq!(&*v, &(0..16usize).collect::<Vec<_>>());
});
},
// name: (),
// reprioritize: (),
..cobb::TestCfg::default()
})
}
#[test]
fn test_testsuite_can_pass() {
use parking_lot::lock_api::RawMutex as _;
unsafe impl RawLock for parking_lot::RawMutex {
fn new() -> Self {
parking_lot::RawMutex::INIT
}
fn try_acquire(&self) -> bool {
self.try_lock()
}
fn acquire(&self) {
self.lock()
}
unsafe fn release(&self) {
self.unlock()
}
fn is_locked(&self) -> bool {
parking_lot::lock_api::RawMutex::is_locked(self)
}
}
cobb_test::<parking_lot::RawMutex>();
}
pub unsafe trait RawLock: 'static + Send + Sync {
fn new() -> Self;
fn try_acquire(&self) -> bool;
fn acquire(&self);
unsafe fn release(&self);
#[inline]
fn is_locked(&self) -> bool {
let succeeded = self.try_acquire();
if succeeded {
unsafe {
self.release();
}
}
!succeeded
}
}
pub struct Mutex<T, L> {
lock: L,
data: std::cell::UnsafeCell<T>,
}
unsafe impl<T: Send, L: RawLock> Sync for Mutex<T, L> {}
unsafe impl<T: Send, L: RawLock> Send for Mutex<T, L> {}
impl<T, L: RawLock> Mutex<T, L> {
#[inline]
pub fn new(v: T) -> Self {
Self {
lock: L::new(),
data: std::cell::UnsafeCell::new(v),
}
}
#[inline]
pub fn with_lock<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
unsafe {
self.lock.acquire();
let result = f(&mut *self.data.get());
self.lock.release();
result
}
}
#[inline]
pub fn is_locked(&self) -> bool {
self.lock.is_locked()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment