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