#![deny(warnings, rust_2018_idioms)]
use loom::cell::UnsafeCell;
use loom::sync::atomic::{fence, AtomicBool};
use loom::thread;
use std::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
use std::sync::Arc;
#[test]
fn fence_sw_base() {
loom::model(|| {
let data = Arc::new(UnsafeCell::new(0));
let flag = Arc::new(AtomicBool::new(false));
let th = {
let (data, flag) = (data.clone(), flag.clone());
thread::spawn(move || {
data.with_mut(|ptr| unsafe { *ptr = 42 });
fence(Release);
flag.store(true, Relaxed);
})
};
if flag.load(Relaxed) {
fence(Acquire);
assert_eq!(42, data.with_mut(|ptr| unsafe { *ptr }));
}
th.join().unwrap();
});
}
#[test]
fn fence_sw_collapsed_store() {
loom::model(|| {
let data = Arc::new(UnsafeCell::new(0));
let flag = Arc::new(AtomicBool::new(false));
let th = {
let (data, flag) = (data.clone(), flag.clone());
thread::spawn(move || {
data.with_mut(|ptr| unsafe { *ptr = 42 });
flag.store(true, Release);
})
};
if flag.load(Relaxed) {
fence(Acquire);
assert_eq!(42, data.with_mut(|ptr| unsafe { *ptr }));
}
th.join().unwrap();
});
}
#[test]
fn fence_sw_collapsed_load() {
loom::model(|| {
let data = Arc::new(UnsafeCell::new(0));
let flag = Arc::new(AtomicBool::new(false));
let th = {
let (data, flag) = (data.clone(), flag.clone());
thread::spawn(move || {
data.with_mut(|ptr| unsafe { *ptr = 42 });
fence(Release);
flag.store(true, Relaxed);
})
};
if flag.load(Acquire) {
assert_eq!(42, data.with_mut(|ptr| unsafe { *ptr }));
}
th.join().unwrap();
});
}
#[test]
fn sb_fences() {
loom::model(|| {
let x = Arc::new(AtomicBool::new(false));
let y = Arc::new(AtomicBool::new(false));
let a = {
let (x, y) = (x.clone(), y.clone());
thread::spawn(move || {
x.store(true, Relaxed);
fence(SeqCst);
y.load(Relaxed)
})
};
y.store(true, Relaxed);
fence(SeqCst);
let b = x.load(Relaxed);
if !a.join().unwrap() {
assert!(b);
}
});
}
#[test]
fn fence_hazard_pointer() {
loom::model(|| {
let reachable = Arc::new(AtomicBool::new(true));
let protected = Arc::new(AtomicBool::new(false));
let allocated = Arc::new(AtomicBool::new(true));
let th = {
let (reachable, protected, allocated) =
(reachable.clone(), protected.clone(), allocated.clone());
thread::spawn(move || {
protected.store(true, Relaxed);
fence(SeqCst);
if reachable.load(Relaxed) {
assert!(allocated.load(Relaxed));
}
})
};
reachable.store(false, Relaxed);
fence(SeqCst);
if !protected.load(Relaxed) {
allocated.store(false, Relaxed);
}
th.join().unwrap();
});
}
#[test]
fn rwc_syncs() {
#![allow(clippy::many_single_char_names)]
loom::model(|| {
let x = Arc::new(AtomicBool::new(false));
let y = Arc::new(AtomicBool::new(false));
let t2 = {
let (x, y) = (x.clone(), y.clone());
thread::spawn(move || {
let a = x.load(Relaxed);
fence(SeqCst);
let b = y.load(Relaxed);
(a, b)
})
};
let t3 = {
let x = x.clone();
thread::spawn(move || {
y.store(true, Relaxed);
fence(SeqCst);
x.load(Relaxed)
})
};
x.store(true, Relaxed);
let (a, b) = t2.join().unwrap();
let c = t3.join().unwrap();
if a && !b && !c {
panic!();
}
});
}
#[test]
fn w_rwc() {
#![allow(clippy::many_single_char_names)]
loom::model(|| {
let x = Arc::new(AtomicBool::new(false));
let y = Arc::new(AtomicBool::new(false));
let z = Arc::new(AtomicBool::new(false));
let t2 = {
let (y, z) = (y.clone(), z.clone());
thread::spawn(move || {
let a = z.load(Acquire);
fence(SeqCst);
let b = y.load(Relaxed);
(a, b)
})
};
let t3 = {
let x = x.clone();
thread::spawn(move || {
y.store(true, Relaxed);
fence(SeqCst);
x.load(Relaxed)
})
};
x.store(true, Relaxed);
z.store(true, Release);
let (a, b) = t2.join().unwrap();
let c = t3.join().unwrap();
if a && !b && !c {
panic!();
}
});
}