9
9
10
10
use std:: sync:: atomic:: Ordering :: * ;
11
11
use std:: sync:: atomic:: { AtomicUsize , fence} ;
12
- use std:: thread:: spawn;
12
+ use std:: thread:: { spawn, yield_now } ;
13
13
14
14
#[ allow( dead_code) ]
15
15
#[ derive( Copy , Clone ) ]
@@ -33,69 +33,67 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize {
33
33
34
34
fn relaxed ( initial_read : bool ) -> bool {
35
35
let x = static_atomic ( 0 ) ;
36
- let j1 = spawn ( move || {
37
- x. store ( 1 , Relaxed ) ;
38
- // Preemption is disabled, so the store above will never be the
39
- // latest store visible to another thread.
40
- x. store ( 2 , Relaxed ) ;
41
- } ) ;
36
+ let j = spawn ( move || x. load ( Relaxed ) ) ;
42
37
43
- let j2 = spawn ( move || x. load ( Relaxed ) ) ;
38
+ x. store ( 1 , Relaxed ) ;
39
+ // Preemption is disabled, so the store above will never be the
40
+ // latest store visible to the other thread.
41
+ x. store ( 2 , Relaxed ) ;
44
42
45
- j1. join ( ) . unwrap ( ) ;
46
- let r2 = j2. join ( ) . unwrap ( ) ;
43
+ let r = j. join ( ) . unwrap ( ) ;
47
44
48
45
// There are three possible values here: 0 (from the initial read), 1 (from the first relaxed
49
46
// read), and 2 (the last read). The last case is boring and we cover the other two.
50
- r2 == if initial_read { 0 } else { 1 }
47
+ r == if initial_read { 0 } else { 1 }
51
48
}
52
49
53
50
// https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf Figure 8
54
- fn seq_cst ( ) -> bool {
51
+ fn seq_cst ( relaxed_write : bool ) -> bool {
55
52
let x = static_atomic ( 0 ) ;
56
53
57
54
let j1 = spawn ( move || {
58
- x. store ( 1 , Relaxed ) ;
55
+ // Make the second thread execute without synchronizing with it.
56
+ // After that, the initial thread will continue executing.
57
+ yield_now ( ) ;
58
+ // This can either load the relaxed write or the second SC-write, but
59
+ // not the first, as that would violate the ordering guarantee.
60
+ x. load ( SeqCst )
59
61
} ) ;
62
+ let j2 = spawn ( move || x. store ( 1 , Relaxed ) ) ;
60
63
61
- let j2 = spawn ( move || {
62
- x . store ( 2 , SeqCst ) ;
63
- x. store ( 3 , SeqCst ) ;
64
- } ) ;
64
+ // Make the first thread execute.
65
+ yield_now ( ) ;
66
+ x. store ( 2 , SeqCst ) ;
67
+ x . store ( 3 , SeqCst ) ;
65
68
66
- let j3 = spawn ( move || x. load ( SeqCst ) ) ;
67
-
68
- j1. join ( ) . unwrap ( ) ;
69
69
j2. join ( ) . unwrap ( ) ;
70
- let r3 = j3 . join ( ) . unwrap ( ) ;
70
+ let r = j1 . join ( ) . unwrap ( ) ;
71
71
72
- r3 == 1
72
+ assert_ne ! ( r, 2 ) ;
73
+ r == if relaxed_write { 1 } else { 3 }
73
74
}
74
75
75
76
fn initialization_write ( add_fence : bool ) -> bool {
76
77
let x = static_atomic ( 11 ) ;
77
78
78
79
let wait = static_atomic ( 0 ) ;
79
80
80
- let j1 = spawn ( move || {
81
- x. store ( 22 , Relaxed ) ;
82
- // Relaxed is intentional. We want to test if the thread 2 reads the initialisation write
83
- // after a relaxed write
84
- wait. store ( 1 , Relaxed ) ;
85
- } ) ;
86
-
87
- let j2 = spawn ( move || {
81
+ let j = spawn ( move || {
88
82
reads_value ( wait, 1 ) ;
89
83
if add_fence {
90
84
fence ( AcqRel ) ;
91
85
}
92
86
x. load ( Relaxed )
93
87
} ) ;
94
88
95
- j1. join ( ) . unwrap ( ) ;
96
- let r2 = j2. join ( ) . unwrap ( ) ;
89
+ x. store ( 22 , Relaxed ) ;
90
+ // Relaxed is intentional. We want to test if the thread 2 reads the initialisation write
91
+ // after a relaxed write
92
+ wait. store ( 1 , Relaxed ) ;
93
+
94
+ let r = j. join ( ) . unwrap ( ) ;
97
95
98
- r2 == 11
96
+ r == 11
99
97
}
100
98
101
99
fn faa_replaced_by_load ( ) -> bool {
@@ -119,12 +117,16 @@ fn faa_replaced_by_load() -> bool {
119
117
let go = static_atomic ( 0 ) ;
120
118
121
119
let t1 = spawn ( move || {
122
- while go. load ( Relaxed ) == 0 { }
120
+ while go. load ( Relaxed ) == 0 {
121
+ yield_now ( ) ;
122
+ }
123
123
rdmw ( y, x, z)
124
124
} ) ;
125
125
126
126
let t2 = spawn ( move || {
127
- while go. load ( Relaxed ) == 0 { }
127
+ while go. load ( Relaxed ) == 0 {
128
+ yield_now ( ) ;
129
+ }
128
130
rdmw ( z, x, y)
129
131
} ) ;
130
132
@@ -144,7 +146,8 @@ fn assert_once(f: fn() -> bool) {
144
146
pub fn main ( ) {
145
147
assert_once ( || relaxed ( false ) ) ;
146
148
assert_once ( || relaxed ( true ) ) ;
147
- assert_once ( seq_cst) ;
149
+ assert_once ( || seq_cst ( false ) ) ;
150
+ assert_once ( || seq_cst ( true ) ) ;
148
151
assert_once ( || initialization_write ( false ) ) ;
149
152
assert_once ( || initialization_write ( true ) ) ;
150
153
assert_once ( faa_replaced_by_load) ;
0 commit comments