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_ppc64)
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_s390x)
173 /* return 1 if success, 0 if failure */
174 UWord do_acasW(UWord* addr, UWord expected, UWord nyu )
178 __asm__ __volatile__ (
182 : /* out */ "=r" (cc)
183 : /* in */ "Q" (*addr), "d" (expected), "d" (nyu)
191 void atomic_incW ( UWord* w )
196 UWord ok = do_acasW( w, old, nyu );
205 void* thread_fn ( void* arg )
207 UWord* w = (UWord*)arg;
209 for (i = 0; i < NNN; i++)
218 //ANNOTATE_HAPPENS_BEFORE(0);
223 r= pthread_create( &t1, NULL, &thread_fn, (void*)&w ); assert(!r);
224 r= pthread_create( &t2, NULL, &thread_fn, (void*)&w ); assert(!r);
226 r= pthread_join( t1, NULL ); assert(!r);
227 r= pthread_join( t2, NULL ); assert(!r);
229 printf("result = %lu\n", w );
235 int shared_var = 0; // is not raced upon
238 void delay100ms ( void )
240 struct timespec ts = { 0, 100 * 1000 * 1000 };
241 nanosleep(&ts, NULL);
244 void do_wait ( UWord* w )
247 UWord volatile * wV = w;
250 ANNOTATE_HAPPENS_AFTER(w);
253 void do_signal ( UWord* w )
255 ANNOTATE_HAPPENS_BEFORE(w);
261 void* thread_fn1 ( void* arg )
263 UWord* w = (UWord*)arg;
264 delay100ms(); // ensure t2 gets to its wait first
265 shared_var = 1; // first access
266 do_signal(w); // cause h-b edge to second thread
272 void* thread_fn2 ( void* arg )
274 UWord* w = (UWord*)arg;
275 do_wait(w); // wait for h-b edge from first thread
276 shared_var = 2; // second access
293 r= pthread_create( &t1, NULL, &thread_fn1, (void*)&w ); assert(!r);
294 r= pthread_create( &t2, NULL, &thread_fn2, (void*)&w ); assert(!r);
296 r= pthread_join( t1, NULL ); assert(!r);
297 r= pthread_join( t2, NULL ); assert(!r);