#pragma once #include "../relacy/relacy_std.hpp" struct coherent_read_read_test : rl::test_suite { std::atomic x; std::atomic y; void before() { x($) = 0; y($) = 0; } void thread(unsigned th) { if (0 == th) x.store(1, rl::memory_order_relaxed); else if (1 == th) { if (0 == x.load(rl::memory_order_relaxed)) return; y.store(1, rl::memory_order_release); x.load(rl::memory_order_relaxed); } else { if (0 == y.load(rl::memory_order_acquire)) return; RL_ASSERT(1 == x.load(rl::memory_order_relaxed)); } } }; template struct order_relaxed_test : rl::test_suite, 2> { std::atomic x1; std::atomic x2; void before() { x1($) = 0; x2($) = 0; } void thread(unsigned th) { if (th) { x1.store(1, order().first, $); x2.store(1, order().first, $); } else { int y2 = x2.load(order().second, $); int y1 = x1.load(order().second, $); //RL_UNTIL(0 == y1 && 0 != y2); (void)y2; (void)y1; } } std::pair order() { switch (index) { default: RL_VERIFY(false); case 0: return std::make_pair(rl::mo_relaxed, rl::mo_relaxed); case 1: return std::make_pair(rl::mo_release, rl::mo_relaxed); case 2: return std::make_pair(rl::mo_seq_cst, rl::mo_relaxed); case 3: return std::make_pair(rl::mo_relaxed, rl::mo_acquire); case 4: return std::make_pair(rl::mo_relaxed, rl::mo_seq_cst); } } }; struct reorder_single_var_test : rl::test_suite { std::atomic x; void before() { x($) = 0; } void thread(unsigned index) { if (index) { x.store(1, rl::memory_order_relaxed); } else { int y1 = x.load(rl::memory_order_relaxed); int y2 = x.load(rl::memory_order_relaxed); RL_ASSERT(y1 == 0 || y2 == 1); } } }; struct acq_rel_test : rl::test_suite { std::atomic x; rl::var y; void before() { x($) = 0; } void thread(unsigned index) { if (index) { VAR(y) = 1; x.store(1, std::memory_order_release); } else { int f = x.load(rl::memory_order_acquire); if (f) { int d = VAR(y); RL_ASSERT(1 == d); } } } }; template struct seq_cst_test : rl::test_suite, 4, (rl::test_result_e)((1 - index) * rl::test_result_until_condition_hit)> { std::atomic x1; std::atomic x2; int res; void before() { x1($) = 0; x2($) = 0; res = 0; } void thread(unsigned th) { if (0 == th) { x1.store(1, order().first, $); } else if (1 == th) { x2.store(1, order().first, $); } else if (2 == th) { int v1 = x1.load(order().second, $); int v2 = x2.load(order().second, $); res += (v1 == 1 && v2 == 0); } else if (3 == th) { int v2 = x2.load(order().second, $); int v1 = x1.load(order().second, $); res += (v2 == 1 && v1 == 0); } } void after() { if ((void)0, 0 == index) { RL_UNTIL(2 == res); } else { RL_ASSERT(2 != res); } } std::pair order() { switch (index) { default: RL_VERIFY(false); case 0: return std::make_pair(rl::mo_release, rl::mo_acquire); case 1: return std::make_pair(rl::mo_seq_cst, rl::mo_seq_cst); } } }; struct modification_order_test : rl::test_suite { std::atomic a; rl::var x; void before() { a($) = 0; x($) = 0; } void thread(unsigned index) { if (index) { x($) = 1; a.store(1, rl::memory_order_release); a.store(2, rl::memory_order_relaxed); } else { if (a.load(rl::memory_order_acquire)) x($).load(); } } }; struct reordering_test : rl::test_suite { std::atomic x; std::atomic y; std::atomic r; void before() { x($) = 0; y($) = 0; r($) = 0; } void thread(unsigned index) { if (0 == index) { x.store(1, rl::memory_order_relaxed); } else if (1 == index) { if (x.load(rl::memory_order_relaxed)) r.store(1, rl::memory_order_relaxed); y.store(1, rl::memory_order_release); } else { if (y.load(rl::memory_order_acquire)) { if (r.load(rl::memory_order_relaxed)) { RL_ASSERT(x.load(rl::memory_order_relaxed)); } } } } }; struct reordering_test2 : rl::test_suite { std::atomic x1; std::atomic x2; std::atomic y; std::atomic r; void before() { std::atomic x (0); char* ch = 0; x.compare_exchange_weak(ch, 0, std::memory_order_seq_cst); x1($) = 0; x2($) = 0; y($) = 0; r($) = 0; } void thread(unsigned index) { if (0 == index) { x1.store(1, rl::memory_order_relaxed); x2.store(1, rl::memory_order_relaxed); } else if (1 == index) { if (x2.load(rl::memory_order_relaxed)) r.store(1, rl::memory_order_relaxed); y.store(1, rl::memory_order_release); } else { if (y.load(rl::memory_order_acquire)) { if (r.load(rl::memory_order_relaxed)) { RL_UNTIL(0 == x1.load(rl::memory_order_relaxed)); } } } } }; struct transitive_test : rl::test_suite { std::atomic x; rl::var y; void before() { x($) = 0; } void thread(unsigned index) { if (0 == index) { VAR(y) = 1; x.fetch_add(1, rl::memory_order_release); } else if (1 == index) { x.fetch_add(2, rl::memory_order_acquire); } else { x.load(rl::memory_order_acquire); int w = x.load(rl::memory_order_acquire); if (1 == w || 3 == w) { y($).load(); } } } }; struct cc_transitive_test : rl::test_suite { std::atomic x; std::atomic y; void before() { x.store(0, std::memory_order_relaxed); y.store(0, std::memory_order_relaxed); } void thread(unsigned index) { if (0 == index) { x.store(1, std::memory_order_relaxed); } else if (1 == index) { if (x.load(std::memory_order_relaxed)) y.store(1, std::memory_order_release); } else { if (y.load(std::memory_order_acquire)) assert(x.load(std::memory_order_relaxed)); } } }; struct occasional_test : rl::test_suite { std::atomic x, y, z; void before() { x.store(0, std::memory_order_relaxed); y.store(0, std::memory_order_relaxed); z.store(0, std::memory_order_relaxed); } void thread(unsigned index) { if (0 == index) { x.store(1, rl::memory_order_relaxed); y.store(1, rl::memory_order_release); } else if (1 == index) { if (y.load(rl::memory_order_relaxed)) z.store(1, rl::memory_order_release); } else { if (z.load(rl::memory_order_acquire)) { RL_ASSERT(y.load(rl::memory_order_relaxed)); RL_UNTIL(0 == x.load(rl::memory_order_relaxed)); } } } };