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