#[test]
#[should_panic]
#[ignore]
fn relaxed() {
use loom::sync::atomic::AtomicUsize;
use loom::thread;
use std::sync::atomic::Ordering::Relaxed;
loom::model(|| {
let x1: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
let x2 = x1;
let y1: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
let y2 = y1;
let t1 = thread::spawn(move || {
let r1 = y1.load(Relaxed);
x1.store(r1, Relaxed);
r1
});
let t2 = thread::spawn(move || {
let r2 = x2.load(Relaxed);
y2.store(42, Relaxed);
r2
});
let r1 = t1.join().unwrap();
let r2 = t2.join().unwrap();
if r1 == 42 && r2 == 42 {
panic!("This case is possible with Relaxed, so we should hit this panic.");
}
});
}
#[test]
fn acq_rel() {
use loom::sync::atomic::AtomicBool;
use loom::thread;
use std::sync::atomic::Ordering;
let mut builder = loom::model::Builder::new();
builder.preemption_bound = Some(1);
let seen: &'static _ = Box::leak(Box::new(std::sync::Mutex::new(
std::collections::HashSet::new(),
)));
builder.check(move || {
let x: &'static _ = Box::leak(Box::new(AtomicBool::new(false)));
let y: &'static _ = Box::leak(Box::new(AtomicBool::new(false)));
let z: &'static _ = Box::leak(Box::new(std::sync::atomic::AtomicUsize::new(0)));
thread::spawn(move || {
y.store(true, Ordering::Release);
});
let t1 = thread::spawn(move || {
while !x.load(Ordering::Acquire) {
loom::thread::yield_now();
}
if y.load(Ordering::Acquire) {
z.fetch_add(1, Ordering::Relaxed);
}
});
let t2 = thread::spawn(move || {
while !y.load(Ordering::Acquire) {
loom::thread::yield_now();
}
if x.load(Ordering::Acquire) {
z.fetch_add(1, Ordering::Relaxed);
}
});
x.store(true, Ordering::Release);
t1.join().unwrap();
t2.join().unwrap();
let z = z.load(Ordering::SeqCst);
seen.lock().unwrap().insert(z);
});
let seen = seen.lock().unwrap();
assert!(seen.contains(&0));
assert!(seen.contains(&1));
assert!(seen.contains(&2));
assert_eq!(seen.len(), 3);
}
#[test]
#[ignore]
fn test_seq_cst() {
use loom::sync::atomic::AtomicBool;
use loom::thread;
use std::sync::atomic::Ordering;
let mut builder = loom::model::Builder::new();
builder.preemption_bound = Some(1);
let seen: &'static _ = Box::leak(Box::new(std::sync::Mutex::new(
std::collections::HashSet::new(),
)));
builder.check(move || {
let x: &'static _ = Box::leak(Box::new(AtomicBool::new(false)));
let y: &'static _ = Box::leak(Box::new(AtomicBool::new(false)));
let z: &'static _ = Box::leak(Box::new(std::sync::atomic::AtomicUsize::new(0)));
thread::spawn(move || {
y.store(true, Ordering::SeqCst);
});
let t1 = thread::spawn(move || {
while !x.load(Ordering::SeqCst) {
loom::thread::yield_now();
}
if y.load(Ordering::SeqCst) {
z.fetch_add(1, Ordering::Relaxed);
}
});
let t2 = thread::spawn(move || {
while !y.load(Ordering::SeqCst) {
loom::thread::yield_now();
}
if x.load(Ordering::SeqCst) {
z.fetch_add(1, Ordering::Relaxed);
}
});
x.store(true, Ordering::SeqCst);
t1.join().unwrap();
t2.join().unwrap();
let z = z.load(Ordering::SeqCst);
assert_ne!(z, 0, "z == 0 is not possible with SeqCst");
seen.lock().unwrap().insert(z);
});
let seen = seen.lock().unwrap();
assert!(seen.contains(&1));
assert!(seen.contains(&2));
assert_eq!(seen.len(), 2);
}