diff --git a/tests/atomic.rs b/tests/atomic.rs index 9150e0b0..bcaa061c 100644 --- a/tests/atomic.rs +++ b/tests/atomic.rs @@ -3,7 +3,7 @@ use loom::sync::atomic::AtomicUsize; use loom::thread; -use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; +use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst}; use std::sync::Arc; #[test] @@ -52,3 +52,60 @@ fn compare_and_swap_reads_old_values() { } }); } + +#[test] +fn check_multiple_compare_and_swap() { + loom::model(|| { + let n1 = Arc::new(AtomicUsize::new(0)); + let n2 = n1.clone(); + let n3 = n1.clone(); + + thread::spawn(move || { + n1.store(2, SeqCst); + }); + + thread::spawn(move || { + let prev = n2.compare_and_swap(0, 2, SeqCst); + if (prev & 1) == 0 { + // This only gets executed if the above compare_and_swap observed 0 or 2 + + // This asserts that if we observed 0 in the lowest bit, then we continue to observe + // 0 in the lowest bit. This must be true because the only transition that changes + // the lowest bit from 0 to 1 is the compare_and_swap below. That compare_and_swap + // will fail if this compare_and_swap is executed first (such that this + // compare_and_swap observes a 0 in the lowest bit), and this assert should never + // fail if that compare_and_swap is executed first (such that the only possible 0 to + // 1 transition of the lowest bit has already occurred and cannot possibly occur + // after this compare_and_swap). + assert_eq!(0, n2.load(SeqCst) & 1); + } + }); + + // This only succeeds in setting to 1 if it observes 0 + let _ = n3.compare_and_swap(0, 1, SeqCst); + }); +} + +// Variant of check_multiple_compare_and_swap above +#[test] +fn check_fetch_add_and_compare_and_swap() { + loom::model(|| { + let n1 = Arc::new(AtomicUsize::new(0)); + let n2 = n1.clone(); + let n3 = n1.clone(); + + thread::spawn(move || { + let _ = n1.fetch_add(2, SeqCst); + }); + + thread::spawn(move || { + let prev = n2.fetch_add(2, SeqCst); + if (prev & 1) == 0 { + assert_eq!(0, n2.load(SeqCst) & 1); + } + }); + + let _ = n3.compare_and_swap(0, 1, SeqCst); + n3.store(0, SeqCst); + }); +}