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