1+ use std:: sync:: atomic:: { AtomicUsize , fence, Ordering } ;
2+ use std:: thread:: spawn;
3+
4+ #[ derive( Copy , Clone ) ]
5+ struct EvilSend < T > ( pub T ) ;
6+
7+ unsafe impl < T > Send for EvilSend < T > { }
8+ unsafe impl < T > Sync for EvilSend < T > { }
9+
10+ static SYNC : AtomicUsize = AtomicUsize :: new ( 0 ) ;
11+
12+ fn test_fence_sync ( ) {
13+ let mut var = 0u32 ;
14+ let ptr = & mut var as * mut u32 ;
15+ let evil_ptr = EvilSend ( ptr) ;
16+
17+
18+ let j1 = spawn ( move || {
19+ unsafe { * evil_ptr. 0 = 1 ; }
20+ fence ( Ordering :: Release ) ;
21+ SYNC . store ( 1 , Ordering :: Relaxed )
22+ } ) ;
23+
24+ let j2 = spawn ( move || {
25+ if SYNC . load ( Ordering :: Relaxed ) == 1 {
26+ fence ( Ordering :: Acquire ) ;
27+ unsafe { * evil_ptr. 0 }
28+ } else {
29+ 0
30+ }
31+ } ) ;
32+
33+ j1. join ( ) . unwrap ( ) ;
34+ j2. join ( ) . unwrap ( ) ;
35+ }
36+
37+
38+ fn test_multiple_reads ( ) {
39+ let mut var = 42u32 ;
40+ let ptr = & mut var as * mut u32 ;
41+ let evil_ptr = EvilSend ( ptr) ;
42+
43+ let j1 = spawn ( move || unsafe { * evil_ptr. 0 } ) ;
44+ let j2 = spawn ( move || unsafe { * evil_ptr. 0 } ) ;
45+ let j3 = spawn ( move || unsafe { * evil_ptr. 0 } ) ;
46+ let j4 = spawn ( move || unsafe { * evil_ptr. 0 } ) ;
47+
48+ assert_eq ! ( j1. join( ) . unwrap( ) , 42 ) ;
49+ assert_eq ! ( j2. join( ) . unwrap( ) , 42 ) ;
50+ assert_eq ! ( j3. join( ) . unwrap( ) , 42 ) ;
51+ assert_eq ! ( j4. join( ) . unwrap( ) , 42 ) ;
52+
53+ var = 10 ;
54+ assert_eq ! ( var, 10 ) ;
55+ }
56+
57+ pub fn test_rmw_no_block ( ) {
58+ let mut a = 0u32 ;
59+ let b = & mut a as * mut u32 ;
60+ let c = EvilSend ( b) ;
61+
62+ unsafe {
63+ let j1 = spawn ( move || {
64+ * c. 0 = 1 ;
65+ SYNC . store ( 1 , Ordering :: Release ) ;
66+ } ) ;
67+
68+ let j2 = spawn ( move || {
69+ if SYNC . swap ( 2 , Ordering :: Relaxed ) == 1 {
70+ //No op, blocking store removed
71+ }
72+ } ) ;
73+
74+ let j3 = spawn ( move || {
75+ if SYNC . load ( Ordering :: Acquire ) == 2 {
76+ * c. 0
77+ } else {
78+ 0
79+ }
80+ } ) ;
81+
82+ j1. join ( ) . unwrap ( ) ;
83+ j2. join ( ) . unwrap ( ) ;
84+ let v = j3. join ( ) . unwrap ( ) ;
85+ assert ! ( v == 1 || v == 2 ) ;
86+ }
87+ }
88+
89+ pub fn test_release_no_block ( ) {
90+ let mut a = 0u32 ;
91+ let b = & mut a as * mut u32 ;
92+ let c = EvilSend ( b) ;
93+
94+ unsafe {
95+ let j1 = spawn ( move || {
96+ * c. 0 = 1 ;
97+ SYNC . store ( 1 , Ordering :: Release ) ;
98+ SYNC . store ( 3 , Ordering :: Relaxed ) ;
99+ } ) ;
100+
101+ let j2 = spawn ( move || {
102+ if SYNC . load ( Ordering :: Acquire ) == 3 {
103+ * c. 0
104+ } else {
105+ 0
106+ }
107+ } ) ;
108+
109+ j1. join ( ) . unwrap ( ) ;
110+ assert_eq ! ( j2. join( ) . unwrap( ) , 1 ) ;
111+ }
112+ }
113+
114+ pub fn main ( ) {
115+ test_fence_sync ( ) ;
116+ test_multiple_reads ( ) ;
117+ test_rmw_no_block ( ) ;
118+ test_release_no_block ( ) ;
119+ }
0 commit comments