2 /* Program which uses a happens-before edge to coordinate an access to
3 variable 'shared_var' between two threads. The h-b edge is created
4 by a custom (kludgesome!) mechanism and hence we need to use
5 ANNOTATES_HAPPEN_{BEFORE,AFTER} to explain to Helgrind what's going
6 on (else it reports a race). */
12 #include "../../helgrind/helgrind.h"
14 /* Todo: move all this do_acasW guff into a support library. It's
15 useful for multiple tests, not just this one.
17 XXX: all the do_acasW routines assume the supplied address
18 is UWord (naturally) aligned. */
21 typedef unsigned long int UWord
;
23 #if defined(VGA_ppc64be) || defined(VGA_ppc64le)
26 /* return 1 if success, 0 if failure */
27 UWord
do_acasW ( UWord
* addr
, UWord expected
, UWord nyu
)
31 /* Fetch the old value, and set the reservation */
32 __asm__
__volatile__ (
33 "ldarx %0, 0,%1" "\n" // rD,rA,rB
36 : /*trash*/ "memory","cc"
39 /* If the old value isn't as expected, we've had it */
40 if (old
!= expected
) return 0;
42 /* otherwise try to stuff the new value in */
44 "stdcx. %2, 0,%1" "\n" // rS,rA,rB
46 "srdi %0,%0,29" "\n\t"
48 : /*out*/ "=b"(success
)
49 : /*in*/ "b"(addr
), "b"(nyu
)
52 assert(success
== 0 || success
== 1);
56 #elif defined(VGA_ppc32)
59 /* return 1 if success, 0 if failure */
60 UWord
do_acasW ( UWord
* addr
, UWord expected
, UWord nyu
)
64 /* Fetch the old value, and set the reservation */
65 __asm__
__volatile__ (
66 "lwarx %0, 0,%1" "\n" // rD,rA,rB
69 : /*trash*/ "memory","cc"
72 /* If the old value isn't as expected, we've had it */
73 if (old
!= expected
) return 0;
75 /* otherwise try to stuff the new value in */
77 "stwcx. %2, 0,%1" "\n" // rS,rA,rB
79 "srwi %0,%0,29" "\n\t"
81 : /*out*/ "=b"(success
)
82 : /*in*/ "b"(addr
), "b"(nyu
)
85 assert(success
== 0 || success
== 1);
89 #elif defined(VGA_amd64)
92 /* return 1 if success, 0 if failure */
93 UWord
do_acasW ( UWord
* addr
, UWord expected
, UWord nyu
)
95 UWord block
[4] = { (UWord
)addr
, expected
, nyu
, 2 };
97 "movq 0(%%rsi), %%rdi" "\n\t" // addr
98 "movq 8(%%rsi), %%rax" "\n\t" // expected
99 "movq 16(%%rsi), %%rbx" "\n\t" // nyu
100 "xorq %%rcx,%%rcx" "\n\t"
101 "lock; cmpxchgq %%rbx,(%%rdi)" "\n\t"
103 "movq %%rcx, 24(%%rsi)" "\n"
105 : /*in*/ "S"(&block
[0])
106 : /*trash*/"memory","cc","rdi","rax","rbx","rcx"
108 assert(block
[3] == 0 || block
[3] == 1);
112 #elif defined(VGA_x86)
115 /* return 1 if success, 0 if failure */
116 UWord
do_acasW ( UWord
* addr
, UWord expected
, UWord nyu
)
118 UWord block
[4] = { (UWord
)addr
, expected
, nyu
, 2 };
119 __asm__
__volatile__(
121 "movl 0(%%esi), %%edi" "\n\t" // addr
122 "movl 4(%%esi), %%eax" "\n\t" // expected
123 "movl 8(%%esi), %%ebx" "\n\t" // nyu
124 "xorl %%ecx,%%ecx" "\n\t"
125 "lock; cmpxchgl %%ebx,(%%edi)" "\n\t"
127 "movl %%ecx, 12(%%esi)" "\n\t"
130 : /*in*/ "S"(&block
[0])
131 : /*trash*/"memory","cc","edi","eax","ecx"
133 assert(block
[3] == 0 || block
[3] == 1);
137 #elif defined(VGA_arm)
140 /* return 1 if success, 0 if failure */
141 UWord
do_acasW ( UWord
* addr
, UWord expected
, UWord nyu
)
144 UWord block
[2] = { (UWord
)addr
, nyu
};
146 /* Fetch the old value, and set the reservation */
147 __asm__
__volatile__ (
148 "ldrex %0, [%1]" "\n"
153 /* If the old value isn't as expected, we've had it */
154 if (old
!= expected
) return 0;
156 /* otherwise try to stuff the new value in */
157 __asm__
__volatile__(
158 "ldr r4, [%1, #0]" "\n\t"
159 "ldr r5, [%1, #4]" "\n\t"
160 "strex r6, r5, [r4, #0]" "\n\t"
161 "eor %0, r6, #1" "\n\t"
162 : /*out*/ "=r"(success
)
163 : /*in*/ "r"(&block
[0])
164 : /*trash*/ "r4","r5","r6","memory"
166 assert(success
== 0 || success
== 1);
170 #elif defined(VGA_arm64)
173 /* return 1 if success, 0 if failure */
174 UWord
do_acasW ( UWord
* addr
, UWord expected
, UWord nyu
)
177 UWord block
[2] = { (UWord
)addr
, nyu
};
179 /* Fetch the old value, and set the reservation */
180 __asm__
__volatile__ (
186 /* If the old value isn't as expected, we've had it */
187 if (old
!= expected
) return 0;
189 /* otherwise try to stuff the new value in */
190 __asm__
__volatile__(
191 "ldr x4, [%1, #0]" "\n\t"
192 "ldr x5, [%1, #8]" "\n\t"
193 "stxr w6, x5, [x4, #0]" "\n\t"
194 "eor %0, x6, #1" "\n\t"
195 : /*out*/ "=r"(success
)
196 : /*in*/ "r"(&block
[0])
197 : /*trash*/ "x4","x5","x6","memory"
199 assert(success
== 0 || success
== 1);
203 #elif defined(VGA_s390x)
206 /* return 1 if success, 0 if failure */
207 UWord
do_acasW(UWord
* addr
, UWord expected
, UWord nyu
)
211 __asm__
__volatile__ (
215 : /* out */ "=r" (cc
)
216 : /* in */ "Q" (*addr
), "d" (expected
), "d" (nyu
)
222 #elif defined(VGA_mips32)
225 /* return 1 if success, 0 if failure */
226 UWord
do_acasW ( UWord
* addr
, UWord expected
, UWord nyu
)
229 UWord block
[3] = { (UWord
)addr
, nyu
, expected
};
231 __asm__
__volatile__(
232 ".set noreorder" "\n\t"
233 "lw $t0, 0(%1)" "\n\t"
234 "lw $t2, 8(%1)" "\n\t"
235 "lw $t3, 4(%1)" "\n\t"
236 "ll $t1, 0($t0)" "\n\t"
237 "bne $t1, $t2, exit_0" "\n\t"
239 "sc $t3, 0($t0)" "\n\t"
240 "move %0, $t3" "\n\t"
244 "move %0, $zero" "\n\t"
246 : /*out*/ "=r"(success
)
247 : /*in*/ "r"(&block
[0])
248 : /*trash*/ "t0", "t1", "t2", "t3", "memory"
251 assert(success
== 0 || success
== 1);
255 #elif defined(VGA_mips64)
258 /* return 1 if success, 0 if failure */
259 UWord
do_acasW ( UWord
* addr
, UWord expected
, UWord nyu
)
262 UWord block
[3] = { (UWord
)addr
, nyu
, expected
};
264 __asm__
__volatile__(
265 ".set noreorder" "\n\t"
266 "ld $t0, 0(%1)" "\n\t"
267 "ld $t2, 16(%1)" "\n\t"
268 "ld $t3, 8(%1)" "\n\t"
269 "ll $t1, 0($t0)" "\n\t"
270 "bne $t1, $t2, exit_0" "\n\t"
272 "sc $t3, 0($t0)" "\n\t"
273 "move %0, $t3" "\n\t"
277 "move %0, $zero" "\n\t"
279 : /*out*/ "=r"(success
)
280 : /*in*/ "r"(&block
[0])
281 : /*trash*/ "t0", "t1", "t2", "t3", "memory"
284 assert(success
== 0 || success
== 1);
290 void atomic_incW ( UWord
* w
)
295 UWord ok
= do_acasW( w
, old
, nyu
);
304 void* thread_fn ( void* arg
)
306 UWord
* w
= (UWord
*)arg
;
308 for (i
= 0; i
< NNN
; i
++)
317 //ANNOTATE_HAPPENS_BEFORE(0);
322 r
= pthread_create( &t1
, NULL
, &thread_fn
, (void*)&w
); assert(!r
);
323 r
= pthread_create( &t2
, NULL
, &thread_fn
, (void*)&w
); assert(!r
);
325 r
= pthread_join( t1
, NULL
); assert(!r
);
326 r
= pthread_join( t2
, NULL
); assert(!r
);
328 printf("result = %lu\n", w
);
334 int shared_var
= 0; // is not raced upon
337 void delayXms ( int i
)
339 struct timespec ts
= { 0, 1 * 1000 * 1000 };
340 // We do the sleep in small pieces to have scheduling
341 // events ensuring a fair switch between threads, even
342 // without --fair-sched=yes. This is a.o. needed for
343 // running this test under an outer helgrind or an outer
346 nanosleep(&ts
, NULL
);
351 void do_wait ( UWord
* w
)
354 UWord
volatile * wV
= w
;
356 delayXms(1); // small sleeps, ensuring context switches
357 ANNOTATE_HAPPENS_AFTER(w
);
360 void do_signal ( UWord
* w
)
362 ANNOTATE_HAPPENS_BEFORE(w
);
368 void* thread_fn1 ( void* arg
)
370 UWord
* w
= (UWord
*)arg
;
371 delayXms(500); // ensure t2 gets to its wait first
372 shared_var
= 1; // first access
373 do_signal(w
); // cause h-b edge to second thread
379 void* thread_fn2 ( void* arg
)
381 UWord
* w
= (UWord
*)arg
;
382 do_wait(w
); // wait for h-b edge from first thread
383 shared_var
= 2; // second access
400 r
= pthread_create( &t1
, NULL
, &thread_fn1
, (void*)&w
); assert(!r
);
401 r
= pthread_create( &t2
, NULL
, &thread_fn2
, (void*)&w
); assert(!r
);
403 r
= pthread_join( t1
, NULL
); assert(!r
);
404 r
= pthread_join( t2
, NULL
); assert(!r
);