drd/tests/Makefile.am: Add dlopen.stdout.exp to EXTRA_DIST
[valgrind.git] / helgrind / tests / annotate_hbefore.c
blob74cf9d86c73d41c07596073cefd93af107d97545
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)
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, exit_0" "\n\t"
238 "nop" "\n\t"
239 "sc $t3, 0($t0)" "\n\t"
240 "move %0, $t3" "\n\t"
241 "b exit" "\n\t"
242 "nop" "\n\t"
243 "exit_0:" "\n\t"
244 "move %0, $zero" "\n\t"
245 "exit:" "\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_mips64)
257 // mips64
258 /* return 1 if success, 0 if failure */
259 UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
261 UWord success;
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"
271 "nop" "\n\t"
272 "sc $t3, 0($t0)" "\n\t"
273 "move %0, $t3" "\n\t"
274 "b exit" "\n\t"
275 "nop" "\n\t"
276 "exit_0:" "\n\t"
277 "move %0, $zero" "\n\t"
278 "exit:" "\n\t"
279 : /*out*/ "=r"(success)
280 : /*in*/ "r"(&block[0])
281 : /*trash*/ "t0", "t1", "t2", "t3", "memory"
284 assert(success == 0 || success == 1);
285 return success;
288 #endif
290 void atomic_incW ( UWord* w )
292 while (1) {
293 UWord old = *w;
294 UWord nyu = old + 1;
295 UWord ok = do_acasW( w, old, nyu );
296 if (ok) break;
300 #if 0
302 #define NNN 1000000
304 void* thread_fn ( void* arg )
306 UWord* w = (UWord*)arg;
307 int i;
308 for (i = 0; i < NNN; i++)
309 atomic_incW( w );
310 return NULL;
314 int main ( void )
316 int r;
317 //ANNOTATE_HAPPENS_BEFORE(0);
318 //return 0;
319 UWord w = 0;
320 pthread_t t1, t2;
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 );
329 return 0;
332 #endif
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
344 // sgcheck.
345 while (i > 0) {
346 nanosleep(&ts, NULL);
347 i--;
351 void do_wait ( UWord* w )
353 UWord w0 = *w;
354 UWord volatile * wV = w;
355 while (*wV == w0)
356 delayXms(1); // small sleeps, ensuring context switches
357 ANNOTATE_HAPPENS_AFTER(w);
360 void do_signal ( UWord* w )
362 ANNOTATE_HAPPENS_BEFORE(w);
363 atomic_incW(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
375 delayXms(500);
376 return NULL;
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
385 delayXms(500);
386 return NULL;
394 int main ( void )
396 int r;
397 UWord w = 0;
398 pthread_t t1, t2;
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);
405 return 0;