2222// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf.
2323
2424use std:: sync:: atomic:: Ordering :: * ;
25- use std:: sync:: atomic:: { AtomicBool , AtomicI32 , fence} ;
25+ use std:: sync:: atomic:: { AtomicBool , AtomicI32 , Ordering , fence} ;
2626use std:: thread:: spawn;
2727
2828#[ derive( Copy , Clone ) ]
@@ -45,8 +45,8 @@ fn static_atomic_bool(val: bool) -> &'static AtomicBool {
4545}
4646
4747// Spins until it acquires a pre-determined value.
48- fn acquires_value ( loc : & AtomicI32 , val : i32 ) -> i32 {
49- while loc. load ( Acquire ) != val {
48+ fn loads_value ( loc : & AtomicI32 , ord : Ordering , val : i32 ) -> i32 {
49+ while loc. load ( ord ) != val {
5050 std:: hint:: spin_loop ( ) ;
5151 }
5252 val
@@ -69,7 +69,7 @@ fn test_corr() {
6969 } ) ; // | |
7070 #[ rustfmt:: skip] // |synchronizes-with |happens-before
7171 let j3 = spawn ( move || { // | |
72- acquires_value ( & y, 1 ) ; // <------ ------------+ |
72+ loads_value ( & y, Acquire , 1 ) ; // <------------+ |
7373 x. load ( Relaxed ) // <----------------------------------------------+
7474 // The two reads on x are ordered by hb, so they cannot observe values
7575 // differently from the modification order. If the first read observed
@@ -94,12 +94,12 @@ fn test_wrc() {
9494 } ) ; // | |
9595 #[ rustfmt:: skip] // |synchronizes-with |
9696 let j2 = spawn ( move || { // | |
97- acquires_value ( & x, 1 ) ; // <------ ------------+ |
97+ loads_value ( & x, Acquire , 1 ) ; // <------------+ |
9898 y. store ( 1 , Release ) ; // ---------------------+ |happens-before
9999 } ) ; // | |
100100 #[ rustfmt:: skip] // |synchronizes-with |
101101 let j3 = spawn ( move || { // | |
102- acquires_value ( & y, 1 ) ; // <------ ------------+ |
102+ loads_value ( & y, Acquire , 1 ) ; // <------------+ |
103103 x. load ( Relaxed ) // <-----------------------------------------------+
104104 } ) ;
105105
@@ -125,7 +125,7 @@ fn test_message_passing() {
125125 #[ rustfmt:: skip] // |synchronizes-with | happens-before
126126 let j2 = spawn ( move || { // | |
127127 let x = x; // avoid field capturing | |
128- acquires_value ( & y, 1 ) ; // <------ ------------+ |
128+ loads_value ( & y, Acquire , 1 ) ; // <------------+ |
129129 unsafe { * x. 0 } // <---------------------------------------------+
130130 } ) ;
131131
@@ -268,9 +268,6 @@ fn test_iriw_sc_rlx() {
268268 let x = static_atomic_bool ( false ) ;
269269 let y = static_atomic_bool ( false ) ;
270270
271- x. store ( false , Relaxed ) ;
272- y. store ( false , Relaxed ) ;
273-
274271 let a = spawn ( move || x. store ( true , Relaxed ) ) ;
275272 let b = spawn ( move || y. store ( true , Relaxed ) ) ;
276273 let c = spawn ( move || {
@@ -290,6 +287,84 @@ fn test_iriw_sc_rlx() {
290287 assert ! ( c || d) ;
291288}
292289
290+ // Similar to `test_iriw_sc_rlx` but with fences instead of SC accesses.
291+ fn test_cpp20_sc_fence_fix ( ) {
292+ let x = static_atomic_bool ( false ) ;
293+ let y = static_atomic_bool ( false ) ;
294+
295+ let thread1 = spawn ( || {
296+ let a = x. load ( Relaxed ) ;
297+ fence ( SeqCst ) ;
298+ let b = y. load ( Relaxed ) ;
299+ ( a, b)
300+ } ) ;
301+
302+ let thread2 = spawn ( || {
303+ x. store ( true , Relaxed ) ;
304+ } ) ;
305+ let thread3 = spawn ( || {
306+ y. store ( true , Relaxed ) ;
307+ } ) ;
308+
309+ let thread4 = spawn ( || {
310+ let c = y. load ( Relaxed ) ;
311+ fence ( SeqCst ) ;
312+ let d = x. load ( Relaxed ) ;
313+ ( c, d)
314+ } ) ;
315+
316+ let ( a, b) = thread1. join ( ) . unwrap ( ) ;
317+ thread2. join ( ) . unwrap ( ) ;
318+ thread3. join ( ) . unwrap ( ) ;
319+ let ( c, d) = thread4. join ( ) . unwrap ( ) ;
320+ let bad = a == true && b == false && c == true && d == false ;
321+ assert ! ( !bad) ;
322+ }
323+
324+ // https://plv.mpi-sws.org/scfix/paper.pdf
325+ // 2.2 Second Problem: SC Fences are Too Weak
326+ fn test_cpp20_rwc_syncs ( ) {
327+ /*
328+ int main() {
329+ atomic_int x = 0;
330+ atomic_int y = 0;
331+ {{{ x.store(1,mo_relaxed);
332+ ||| { r1=x.load(mo_relaxed).readsvalue(1);
333+ fence(mo_seq_cst);
334+ r2=y.load(mo_relaxed); }
335+ ||| { y.store(1,mo_relaxed);
336+ fence(mo_seq_cst);
337+ r3=x.load(mo_relaxed); }
338+ }}}
339+ return 0;
340+ }
341+ */
342+ let x = static_atomic ( 0 ) ;
343+ let y = static_atomic ( 0 ) ;
344+
345+ let j1 = spawn ( move || {
346+ x. store ( 1 , Relaxed ) ;
347+ } ) ;
348+
349+ let j2 = spawn ( move || {
350+ loads_value ( & x, Relaxed , 1 ) ;
351+ fence ( SeqCst ) ;
352+ y. load ( Relaxed )
353+ } ) ;
354+
355+ let j3 = spawn ( move || {
356+ y. store ( 1 , Relaxed ) ;
357+ fence ( SeqCst ) ;
358+ x. load ( Relaxed )
359+ } ) ;
360+
361+ j1. join ( ) . unwrap ( ) ;
362+ let b = j2. join ( ) . unwrap ( ) ;
363+ let c = j3. join ( ) . unwrap ( ) ;
364+
365+ assert ! ( ( b, c) != ( 0 , 0 ) ) ;
366+ }
367+
293368pub fn main ( ) {
294369 for _ in 0 ..50 {
295370 test_single_thread ( ) ;
@@ -301,5 +376,7 @@ pub fn main() {
301376 test_sc_store_buffering ( ) ;
302377 test_sync_through_rmw_and_fences ( ) ;
303378 test_iriw_sc_rlx ( ) ;
379+ test_cpp20_sc_fence_fix ( ) ;
380+ test_cpp20_rwc_syncs ( ) ;
304381 }
305382}
0 commit comments