#![cfg(loom)]
use loom::sync::Arc;
use loom::thread;
#[test]
fn loom_latch_shared_blocking() {
use ferntree::latch::HybridLatch;
loom::model(|| {
let latch = Arc::new(HybridLatch::new(0i32));
let t1 = {
let latch = Arc::clone(&latch);
thread::spawn(move || {
let guard = latch.shared();
let val = *guard;
drop(guard);
val
})
};
let t2 = {
let latch = Arc::clone(&latch);
thread::spawn(move || {
let mut guard = latch.exclusive();
*guard = 42;
})
};
let v1 = t1.join().unwrap();
t2.join().unwrap();
assert!(v1 == 0 || v1 == 42);
let final_val = *latch.shared();
assert_eq!(final_val, 42);
});
}
#[test]
fn loom_latch_exclusive_serialization() {
use ferntree::latch::HybridLatch;
loom::model(|| {
let latch = Arc::new(HybridLatch::new(0i32));
let t1 = {
let latch = Arc::clone(&latch);
thread::spawn(move || {
let mut guard = latch.exclusive();
*guard += 1;
})
};
let t2 = {
let latch = Arc::clone(&latch);
thread::spawn(move || {
let mut guard = latch.exclusive();
*guard += 1;
})
};
t1.join().unwrap();
t2.join().unwrap();
let final_val = *latch.shared();
assert_eq!(final_val, 2);
});
}
#[test]
fn loom_latch_concurrent_shared() {
use ferntree::latch::HybridLatch;
loom::model(|| {
let latch = Arc::new(HybridLatch::new(42i32));
let t1 = {
let latch = Arc::clone(&latch);
thread::spawn(move || {
let guard = latch.shared();
*guard
})
};
let t2 = {
let latch = Arc::clone(&latch);
thread::spawn(move || {
let guard = latch.shared();
*guard
})
};
let v1 = t1.join().unwrap();
let v2 = t2.join().unwrap();
assert_eq!(v1, 42);
assert_eq!(v2, 42);
});
}
#[test]
fn loom_latch_exclusive_mutual_exclusion() {
use ferntree::latch::HybridLatch;
use loom::sync::atomic::{AtomicUsize, Ordering};
loom::model(|| {
let latch = Arc::new(HybridLatch::new(0i32));
let counter = Arc::new(AtomicUsize::new(0));
let t1 = {
let latch = Arc::clone(&latch);
let counter = Arc::clone(&counter);
thread::spawn(move || {
let mut guard = latch.exclusive();
let prev = counter.fetch_add(1, Ordering::SeqCst);
assert_eq!(prev, 0);
*guard = 1;
counter.fetch_sub(1, Ordering::SeqCst);
})
};
let t2 = {
let latch = Arc::clone(&latch);
let counter = Arc::clone(&counter);
thread::spawn(move || {
let mut guard = latch.exclusive();
let prev = counter.fetch_add(1, Ordering::SeqCst);
assert_eq!(prev, 0);
*guard = 2;
counter.fetch_sub(1, Ordering::SeqCst);
})
};
t1.join().unwrap();
t2.join().unwrap();
let final_val = *latch.shared();
assert!(final_val == 1 || final_val == 2);
});
}
#[test]
fn loom_latch_shared_then_exclusive() {
use ferntree::latch::HybridLatch;
loom::model(|| {
let latch = Arc::new(HybridLatch::new(0i32));
{
let guard = latch.shared();
assert_eq!(*guard, 0);
}
{
let mut guard = latch.exclusive();
*guard = 42;
}
assert_eq!(*latch.shared(), 42);
});
}
#[test]
fn loom_latch_exclusive_then_shared() {
use ferntree::latch::HybridLatch;
loom::model(|| {
let latch = Arc::new(HybridLatch::new(0i32));
{
let mut guard = latch.exclusive();
*guard = 42;
}
{
let guard = latch.shared();
assert_eq!(*guard, 42);
}
});
}