annotate_hbefore.c revision 9bea4c13fca0e3bb4b719dcb3ed63d47d479294e
1 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). */ 7 8#include <pthread.h> 9#include <stdio.h> 10#include <assert.h> 11 12#include "../../helgrind/helgrind.h" 13 14/* Todo: move all this do_acasW guff into a support library. It's 15 useful for multiple tests, not just this one. 16 17 XXX: all the do_acasW routines assume the supplied address 18 is UWord (naturally) aligned. */ 19 20 21typedef unsigned long int UWord; 22 23#if defined(VGA_ppc64) 24 25// ppc64 26/* return 1 if success, 0 if failure */ 27UWord do_acasW ( UWord* addr, UWord expected, UWord nyu ) 28{ 29 UWord old, success; 30 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" 37 ); 38 39 /* If the old value isn't as expected, we've had it */ 40 if (old != expected) return 0; 41 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) 50 ); 51 52 assert(success == 0 || success == 1); 53 return success; 54} 55 56#elif defined(VGA_ppc32) 57 58// ppc32 59/* return 1 if success, 0 if failure */ 60UWord do_acasW ( UWord* addr, UWord expected, UWord nyu ) 61{ 62 UWord old, success; 63 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" 70 ); 71 72 /* If the old value isn't as expected, we've had it */ 73 if (old != expected) return 0; 74 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) 83 ); 84 85 assert(success == 0 || success == 1); 86 return success; 87} 88 89#elif defined(VGA_amd64) 90 91// amd64 92/* return 1 if success, 0 if failure */ 93UWord do_acasW ( UWord* addr, UWord expected, UWord nyu ) 94{ 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" 107 ); 108 assert(block[3] == 0 || block[3] == 1); 109 return block[3] & 1; 110} 111 112#elif defined(VGA_x86) 113 114// x86 115/* return 1 if success, 0 if failure */ 116UWord do_acasW ( UWord* addr, UWord expected, UWord nyu ) 117{ 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" 132 ); 133 assert(block[3] == 0 || block[3] == 1); 134 return block[3] & 1; 135} 136 137#elif defined(VGA_arm) 138 139// arm 140/* return 1 if success, 0 if failure */ 141UWord do_acasW ( UWord* addr, UWord expected, UWord nyu ) 142{ 143 UWord old, success; 144 UWord block[2] = { (UWord)addr, nyu }; 145 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) 151 ); 152 153 /* If the old value isn't as expected, we've had it */ 154 if (old != expected) return 0; 155 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" 165 ); 166 assert(success == 0 || success == 1); 167 return success; 168} 169 170#endif 171 172void atomic_incW ( UWord* w ) 173{ 174 while (1) { 175 UWord old = *w; 176 UWord nyu = old + 1; 177 UWord ok = do_acasW( w, old, nyu ); 178 if (ok) break; 179 }; 180} 181 182#if 0 183 184#define NNN 1000000 185 186void* thread_fn ( void* arg ) 187{ 188 UWord* w = (UWord*)arg; 189 int i; 190 for (i = 0; i < NNN; i++) 191 atomic_incW( w ); 192 return NULL; 193} 194 195 196int main ( void ) 197{ 198 int r; 199 //ANNOTATE_HAPPENS_BEFORE(0); 200 //return 0; 201 UWord w = 0; 202 pthread_t t1, t2; 203 204 r= pthread_create( &t1, NULL, &thread_fn, (void*)&w ); assert(!r); 205 r= pthread_create( &t2, NULL, &thread_fn, (void*)&w ); assert(!r); 206 207 r= pthread_join( t1, NULL ); assert(!r); 208 r= pthread_join( t2, NULL ); assert(!r); 209 210 printf("result = %lu\n", w ); 211 return 0; 212} 213 214#endif 215 216int shared_var = 0; // is not raced upon 217 218 219void delay100ms ( void ) 220{ 221 struct timespec ts = { 0, 100 * 1000 * 1000 }; 222 nanosleep(&ts, NULL); 223} 224 225void do_wait ( UWord* w ) 226{ 227 UWord w0 = *w; 228 UWord volatile * wV = w; 229 while (*wV == w0) 230 ; 231 ANNOTATE_HAPPENS_AFTER(w); 232} 233 234void do_signal ( UWord* w ) 235{ 236 ANNOTATE_HAPPENS_BEFORE(w); 237 atomic_incW(w); 238} 239 240 241 242void* thread_fn1 ( void* arg ) 243{ 244 UWord* w = (UWord*)arg; 245 delay100ms(); // ensure t2 gets to its wait first 246 shared_var = 1; // first access 247 do_signal(w); // cause h-b edge to second thread 248 249 delay100ms(); 250 return NULL; 251} 252 253void* thread_fn2 ( void* arg ) 254{ 255 UWord* w = (UWord*)arg; 256 do_wait(w); // wait for h-b edge from first thread 257 shared_var = 2; // second access 258 259 delay100ms(); 260 return NULL; 261} 262 263 264 265 266 267 268int main ( void ) 269{ 270 int r; 271 UWord w = 0; 272 pthread_t t1, t2; 273 274 r= pthread_create( &t1, NULL, &thread_fn1, (void*)&w ); assert(!r); 275 r= pthread_create( &t2, NULL, &thread_fn2, (void*)&w ); assert(!r); 276 277 r= pthread_join( t1, NULL ); assert(!r); 278 r= pthread_join( t2, NULL ); assert(!r); 279 return 0; 280} 281