1 2 #include "config.h" 3 #include <pthread.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <assert.h> 7 8 /* Simple test program, no race. Parent and child both modify x and 9 use the hardware bus lock (implicitly, since XCHG r,m on x86/amd64 10 does not require an explicit LOCK prefix.). */ 11 12 #undef PLAT_x86_darwin 13 #undef PLAT_amd64_darwin 14 #undef PLAT_x86_linux 15 #undef PLAT_amd64_linux 16 #undef PLAT_ppc32_linux 17 #undef PLAT_ppc64_linux 18 #undef PLAT_arm_linux 19 #undef PLAT_s390x_linux 20 #undef PLAT_mips32_linux 21 22 #if defined(__APPLE__) && defined(__i386__) 23 # define PLAT_x86_darwin 1 24 #elif defined(__APPLE__) && defined(__x86_64__) 25 # define PLAT_amd64_darwin 1 26 #elif defined(__linux__) && defined(__i386__) 27 # define PLAT_x86_linux 1 28 #elif defined(__linux__) && defined(__x86_64__) 29 # define PLAT_amd64_linux 1 30 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) 31 # define PLAT_ppc32_linux 1 32 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) 33 # define PLAT_ppc64_linux 1 34 #elif defined(__linux__) && defined(__arm__) 35 # define PLAT_arm_linux 1 36 #elif defined(__linux__) && defined(__s390x__) 37 # define PLAT_s390x_linux 1 38 #elif defined(__linux__) && defined(__mips__) 39 # define PLAT_mips32_linux 1 40 #endif 41 42 43 #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \ 44 || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) 45 # define XCHG_M_R(_addr,_lval) \ 46 __asm__ __volatile__( \ 47 "xchgl %0, %1" \ 48 : /*out*/ "+r"(_lval) \ 49 : /*in*/ "m"(_addr) \ 50 : "memory", "cc" \ 51 ) 52 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \ 53 __asm__ __volatile__( \ 54 "lock xchgl %0, %1" \ 55 : /*out*/ "+r"(_lval) \ 56 : /*in*/ "m"(_addr) \ 57 : "memory", "cc" \ 58 ) 59 60 #elif defined(PLAT_s390x_linux) 61 # define XCHG_M_R(_addr,_lval) \ 62 do { \ 63 __asm__ __volatile__( \ 64 "0: l 0,%[global]\n\t" \ 65 " cs 0,%[local],%[global]\n\t" \ 66 " bne 0b\n\t" \ 67 " lr %[local],0\n\t" \ 68 : /*out*/ [global]"+m"(_addr), [local]"+d"(_lval) \ 69 : /*in*/ \ 70 : "0", "memory", "cc" \ 71 ); \ 72 } while (0) 73 74 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \ 75 XCHG_M_R(_addr,_lval) 76 77 #elif defined(PLAT_mips32_linux) || defined(PLAT_mips64_linux) 78 # define XCHG_M_R(_addr,_lval) \ 79 __asm__ __volatile__( \ 80 "move $12, %2\n" \ 81 "move $13, %1\n" \ 82 "ll $14, 0($13)\n" \ 83 "sc $12, 0($13)\n" \ 84 "move %0, $14\n" \ 85 : /*out*/ "=r"(_lval) \ 86 : /*in*/ "r"(&_addr), "r"(_lval) \ 87 : "$12", "$13", "$14", "memory", "cc" \ 88 ) 89 90 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \ 91 XCHG_M_R(_addr,_lval) 92 93 #elif defined(PLAT_ppc32_linux) || defined(PLAT_ppc64_linux) \ 94 || defined(PLAT_arm_linux) 95 # if defined(HAVE_BUILTIN_ATOMIC) 96 # define XCHG_M_R(_addr,_lval) \ 97 do { \ 98 int tmp; \ 99 while ((tmp = *(int*)(& _addr)), \ 100 ! __sync_bool_compare_and_swap((int*)&_addr, tmp, _lval)) \ 101 ; \ 102 _lval = tmp; \ 103 } while (0) 104 # else 105 # warning "XCHG_M_R() implementation is missing. Either" \ 106 "provide one or use a newer gcc version." 107 # define XCHG_M_R(_addr,_lval) \ 108 do { int tmp = *(int*)(& _addr); \ 109 *(int*)(& _addr) = (_lval); \ 110 _lval = tmp; \ 111 } while (0) 112 # endif 113 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \ 114 XCHG_M_R(_addr,_lval) 115 116 #else 117 # error "Unsupported architecture" 118 119 #endif 120 121 int x = 0; 122 123 void* child_fn ( void* arg ) 124 { 125 int v = 12345; 126 XCHG_M_R_with_redundant_LOCK(x, v); 127 assert(v == 0 || v == 6789); 128 return NULL; 129 } 130 131 int main ( void ) 132 { 133 int v = 6789; 134 pthread_t child; 135 136 if (pthread_create(&child, NULL, child_fn, NULL)) { 137 perror("pthread_create"); 138 exit(1); 139 } 140 141 XCHG_M_R(x, v); 142 assert(v == 0 || v == 12345); 143 144 if (pthread_join(child, NULL)) { 145 perror("pthread join"); 146 exit(1); 147 } 148 149 if (v == 0 || v == 12345) 150 printf("success\n"); 151 else 152 printf("failure\n"); 153 154 return v; 155 } 156