Skip to content

Commit f00d344

Browse files
committed
add release sequence test
1 parent d8e7ff2 commit f00d344

File tree

1 file changed

+39
-3
lines changed

1 file changed

+39
-3
lines changed

tests/pass/0weak_memory/weak.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn spin_until(loc: &AtomicUsize, val: usize) -> usize {
3535

3636
/// Check that the function produces the intended set of outcomes.
3737
#[track_caller]
38-
fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Display>(
38+
fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Debug>(
3939
expected: impl IntoIterator<Item = T>,
4040
generate: impl Fn() -> T,
4141
) {
@@ -47,7 +47,7 @@ fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Display>(
4747
let tries = expected.len() * 12;
4848
for i in 0..tries {
4949
let val = generate();
50-
assert!(expected.contains(&val), "got an unexpected value: {val}");
50+
assert!(expected.contains(&val), "got an unexpected value: {val:?}");
5151
seen.insert(val);
5252
if i > tries / 2 && expected.len() == seen.len() {
5353
// We saw everything and we did quite a few tries, let's avoid wasting time.
@@ -57,7 +57,7 @@ fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Display>(
5757
// Let's see if we saw them all.
5858
for val in expected {
5959
if !seen.contains(&val) {
60-
panic!("did not get value that should be possible: {val}");
60+
panic!("did not get value that should be possible: {val:?}");
6161
}
6262
}
6363
}
@@ -163,10 +163,46 @@ fn faa_replaced_by_load() {
163163
});
164164
}
165165

166+
/// Checking that the weaker release sequence example from
167+
/// <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0982r0.html> can actually produce the
168+
/// new behavior (`Some(0)` in our version).
169+
fn weaker_release_sequences() {
170+
check_all_outcomes([None, Some(0), Some(1)], || {
171+
let x = static_atomic(0);
172+
let y = static_atomic(0);
173+
174+
let t1 = spawn(move || {
175+
x.store(2, Relaxed);
176+
});
177+
let t2 = spawn(move || {
178+
y.store(1, Relaxed);
179+
x.store(1, Release);
180+
x.store(3, Relaxed);
181+
});
182+
let t3 = spawn(move || {
183+
if x.load(Acquire) == 3 {
184+
// In C++11, if we read the 3 here, and if the store of 1 was just before the store
185+
// of 3 in mo order (which it is because we fix the schedule), this forms a release
186+
// sequence, meaning we acquire the release store of 1, and we can thus never see
187+
// the value 0.
188+
// In C++20, this is no longer a release sequence, so 0 can now be observed.
189+
Some(y.load(Relaxed))
190+
} else {
191+
None
192+
}
193+
});
194+
195+
t1.join().unwrap();
196+
t2.join().unwrap();
197+
t3.join().unwrap()
198+
});
199+
}
200+
166201
pub fn main() {
167202
relaxed();
168203
seq_cst();
169204
initialization_write(false);
170205
initialization_write(true);
171206
faa_replaced_by_load();
207+
weaker_release_sequences();
172208
}

0 commit comments

Comments
 (0)