-> 3.17.0.RC2
[valgrind.git] / helgrind / tests / annotate_hbefore.c
blob259d3b64c895800390375d16b10206014a8affb9
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). */
8 #include <pthread.h>
9 #include <stdio.h>
10 #include <assert.h>
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)
25 // ppc64
26 /* return 1 if success, 0 if failure */
27 UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
29 UWord old, success;
31 /* Fetch the old value, and set the reservation */
32 __asm__ __volatile__ (
33 "ldarx %0, 0,%1" "\n" // rD,rA,rB
34 : /*out*/ "=b"(old)
35 : /*in*/ "b"(addr)
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 */
43 __asm__ __volatile__(
44 "stdcx. %2, 0,%1" "\n" // rS,rA,rB
45 "mfcr %0" "\n\t"
46 "srdi %0,%0,29" "\n\t"
47 "andi. %0,%0,1" "\n"
48 : /*out*/ "=b"(success)
49 : /*in*/ "b"(addr), "b"(nyu)
52 assert(success == 0 || success == 1);
53 return success;
56 #elif defined(VGA_ppc32)
58 // ppc32
59 /* return 1 if success, 0 if failure */
60 UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
62 UWord old, success;
64 /* Fetch the old value, and set the reservation */
65 __asm__ __volatile__ (
66 "lwarx %0, 0,%1" "\n" // rD,rA,rB
67 : /*out*/ "=b"(old)
68 : /*in*/ "b"(addr)
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 */
76 __asm__ __volatile__(
77 "stwcx. %2, 0,%1" "\n" // rS,rA,rB
78 "mfcr %0" "\n\t"
79 "srwi %0,%0,29" "\n\t"
80 "andi. %0,%0,1" "\n"
81 : /*out*/ "=b"(success)
82 : /*in*/ "b"(addr), "b"(nyu)
85 assert(success == 0 || success == 1);
86 return success;
89 #elif defined(VGA_amd64)
91 // 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 };
96 __asm__ __volatile__(
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"
102 "setz %%cl" "\n\t"
103 "movq %%rcx, 24(%%rsi)" "\n"
104 : /*out*/
105 : /*in*/ "S"(&block[0])
106 : /*trash*/"memory","cc","rdi","rax","rbx","rcx"
108 assert(block[3] == 0 || block[3] == 1);
109 return block[3] & 1;
112 #elif defined(VGA_x86)
114 // 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__(
120 "pushl %%ebx" "\n\t"
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"
126 "setz %%cl" "\n\t"
127 "movl %%ecx, 12(%%esi)" "\n\t"
128 "popl %%ebx" "\n"
129 : /*out*/
130 : /*in*/ "S"(&block[0])
131 : /*trash*/"memory","cc","edi","eax","ecx"
133 assert(block[3] == 0 || block[3] == 1);
134 return block[3] & 1;
137 #elif defined(VGA_arm)
139 // arm
140 /* return 1 if success, 0 if failure */
141 UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
143 UWord old, success;
144 UWord block[2] = { (UWord)addr, nyu };
146 /* Fetch the old value, and set the reservation */
147 __asm__ __volatile__ (
148 "ldrex %0, [%1]" "\n"
149 : /*out*/ "=r"(old)
150 : /*in*/ "r"(addr)
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);
167 return success;
170 #elif defined(VGA_arm64)
172 // arm64
173 /* return 1 if success, 0 if failure */
174 UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
176 UWord old, success;
177 UWord block[2] = { (UWord)addr, nyu };
179 /* Fetch the old value, and set the reservation */
180 __asm__ __volatile__ (
181 "ldxr %0, [%1]" "\n"
182 : /*out*/ "=r"(old)
183 : /*in*/ "r"(addr)
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);
200 return success;
203 #elif defined(VGA_s390x)
205 // s390x
206 /* return 1 if success, 0 if failure */
207 UWord do_acasW(UWord* addr, UWord expected, UWord nyu )
209 int cc;
211 __asm__ __volatile__ (
212 "csg %2,%3,%1\n\t"
213 "ipm %0\n\t"
214 "srl %0,28\n\t"
215 : /* out */ "=r" (cc)
216 : /* in */ "Q" (*addr), "d" (expected), "d" (nyu)
217 : "memory", "cc"
219 return cc == 0;
222 #elif defined(VGA_mips32) || (defined(VGA_mips64) && defined(VGABI_N32))
224 // mips32
225 /* return 1 if success, 0 if failure */
226 UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
228 UWord success;
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, 1f" "\n\t"
238 "nop" "\n\t"
239 "sc $t3, 0($t0)" "\n\t"
240 "move %0, $t3" "\n\t"
241 "b 2f" "\n\t"
242 "nop" "\n\t"
243 "1:" "\n\t"
244 "move %0, $zero" "\n\t"
245 "2:" "\n\t"
246 : /*out*/ "=r"(success)
247 : /*in*/ "r"(&block[0])
248 : /*trash*/ "t0", "t1", "t2", "t3", "memory"
251 assert(success == 0 || success == 1);
252 return success;
255 #elif defined(VGA_nanomips)
257 /* return 1 if success, 0 if failure */
258 UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
260 UWord success;
261 UWord block[3] = { (UWord)addr, nyu, expected};
263 __asm__ __volatile__(
264 "lw $t0, 0(%1)" "\n\t"
265 "lw $t2, 8(%1)" "\n\t"
266 "lw $t3, 4(%1)" "\n\t"
267 "ll $t1, 0($t0)" "\n\t"
268 "bnec $t1, $t2, 1f" "\n\t"
269 "sc $t3, 0($t0)" "\n\t"
270 "move %0, $t3" "\n\t"
271 "bc 2f" "\n\t"
272 "1:" "\n\t"
273 "move %0, $zero" "\n\t"
274 "2:" "\n\t"
275 : /*out*/ "=r"(success)
276 : /*in*/ "r"(&block[0])
277 : /*trash*/ "t0", "t1", "t2", "t3", "memory"
280 assert(success == 0 || success == 1);
281 return success;
284 #elif defined(VGA_mips64) && !defined(VGABI_N32)
286 // mips64
287 /* return 1 if success, 0 if failure */
288 UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
290 UWord success;
291 UWord block[3] = { (UWord)addr, nyu, expected};
293 __asm__ __volatile__(
294 ".set noreorder" "\n\t"
295 "ld $t0, 0(%1)" "\n\t"
296 "ld $t2, 16(%1)" "\n\t"
297 "ld $t3, 8(%1)" "\n\t"
298 "ll $t1, 0($t0)" "\n\t"
299 "bne $t1, $t2, 1f" "\n\t"
300 "nop" "\n\t"
301 "sc $t3, 0($t0)" "\n\t"
302 "move %0, $t3" "\n\t"
303 "b 2f" "\n\t"
304 "nop" "\n\t"
305 "1:" "\n\t"
306 "move %0, $zero" "\n\t"
307 "2:" "\n\t"
308 : /*out*/ "=r"(success)
309 : /*in*/ "r"(&block[0])
310 : /*trash*/ "t0", "t1", "t2", "t3", "memory"
313 assert(success == 0 || success == 1);
314 return success;
317 #endif
319 void atomic_incW ( UWord* w )
321 while (1) {
322 UWord old = *w;
323 UWord nyu = old + 1;
324 UWord ok = do_acasW( w, old, nyu );
325 if (ok) break;
329 #if 0
331 #define NNN 1000000
333 void* thread_fn ( void* arg )
335 UWord* w = (UWord*)arg;
336 int i;
337 for (i = 0; i < NNN; i++)
338 atomic_incW( w );
339 return NULL;
343 int main ( void )
345 int r;
346 //ANNOTATE_HAPPENS_BEFORE(0);
347 //return 0;
348 UWord w = 0;
349 pthread_t t1, t2;
351 r= pthread_create( &t1, NULL, &thread_fn, (void*)&w ); assert(!r);
352 r= pthread_create( &t2, NULL, &thread_fn, (void*)&w ); assert(!r);
354 r= pthread_join( t1, NULL ); assert(!r);
355 r= pthread_join( t2, NULL ); assert(!r);
357 printf("result = %lu\n", w );
358 return 0;
361 #endif
363 int shared_var = 0; // is not raced upon
366 void delayXms ( int i )
368 struct timespec ts = { 0, 1 * 1000 * 1000 };
369 // We do the sleep in small pieces to have scheduling
370 // events ensuring a fair switch between threads, even
371 // without --fair-sched=yes. This is a.o. needed for
372 // running this test under an outer helgrind.
373 while (i > 0) {
374 nanosleep(&ts, NULL);
375 i--;
379 void do_wait ( UWord* w )
381 UWord w0 = *w;
382 UWord volatile * wV = w;
383 while (*wV == w0)
384 delayXms(1); // small sleeps, ensuring context switches
385 ANNOTATE_HAPPENS_AFTER(w);
388 void do_signal ( UWord* w )
390 ANNOTATE_HAPPENS_BEFORE(w);
391 atomic_incW(w);
396 void* thread_fn1 ( void* arg )
398 UWord* w = (UWord*)arg;
399 delayXms(500); // ensure t2 gets to its wait first
400 shared_var = 1; // first access
401 do_signal(w); // cause h-b edge to second thread
403 delayXms(500);
404 return NULL;
407 void* thread_fn2 ( void* arg )
409 UWord* w = (UWord*)arg;
410 do_wait(w); // wait for h-b edge from first thread
411 shared_var = 2; // second access
413 delayXms(500);
414 return NULL;
422 int main ( void )
424 int r;
425 UWord w = 0;
426 pthread_t t1, t2;
428 r= pthread_create( &t1, NULL, &thread_fn1, (void*)&w ); assert(!r);
429 r= pthread_create( &t2, NULL, &thread_fn2, (void*)&w ); assert(!r);
431 r= pthread_join( t1, NULL ); assert(!r);
432 r= pthread_join( t2, NULL ); assert(!r);
433 return 0;