diff options
-rw-r--r-- | include/atomic/gcc_builtins.h | 5 | ||||
-rw-r--r-- | include/atomic/nolock.h | 17 | ||||
-rw-r--r-- | include/atomic/x86-gcc.h | 41 | ||||
-rw-r--r-- | include/my_atomic.h | 4 | ||||
-rw-r--r-- | unittest/mysys/my_atomic-t.c | 19 |
5 files changed, 50 insertions, 36 deletions
diff --git a/include/atomic/gcc_builtins.h b/include/atomic/gcc_builtins.h index 100ff80cacd..d03d28f572e 100644 --- a/include/atomic/gcc_builtins.h +++ b/include/atomic/gcc_builtins.h @@ -22,8 +22,9 @@ v= __sync_lock_test_and_set(a, v); #define make_atomic_cas_body(S) \ int ## S sav; \ - sav= __sync_val_compare_and_swap(a, *cmp, set); \ - if (!(ret= (sav == *cmp))) *cmp= sav; + int ## S cmp_val= *cmp; \ + sav= __sync_val_compare_and_swap(a, cmp_val, set);\ + if (!(ret= (sav == cmp_val))) *cmp= sav #ifdef MY_ATOMIC_MODE_DUMMY #define make_atomic_load_body(S) ret= *a diff --git a/include/atomic/nolock.h b/include/atomic/nolock.h index 5a0c41d9078..4c871473b60 100644 --- a/include/atomic/nolock.h +++ b/include/atomic/nolock.h @@ -29,21 +29,22 @@ We choose implementation as follows: ------------------------------------ On Windows using Visual C++ the native implementation should be - preferrable. When using gcc we prefer the native x86 implementation, - we prefer the Solaris implementation before the gcc because of - stability preference, we choose gcc implementation if nothing else - works on gcc. If neither Visual C++ or gcc we still choose the - Solaris implementation on Solaris (mainly for SunStudio compiles. + preferrable. When using gcc we prefer the Solaris implementation + before the gcc because of stability preference, we choose gcc + builtins if available, otherwise we choose the somewhat broken + native x86 implementation. If neither Visual C++ or gcc we still + choose the Solaris implementation on Solaris (mainly for SunStudio + compilers). */ # if defined(_MSV_VER) # include "generic-msvc.h" # elif __GNUC__ -# if defined(__i386__) || defined(__x86_64__) -# include "x86-gcc.h" -# elif defined(HAVE_SOLARIS_ATOMIC) +# if defined(HAVE_SOLARIS_ATOMIC) # include "solaris.h" # elif defined(HAVE_GCC_ATOMIC_BUILTINS) # include "gcc_builtins.h" +# elif defined(__i386__) || defined(__x86_64__) +# include "x86-gcc.h" # endif # elif defined(HAVE_SOLARIS_ATOMIC) # include "solaris.h" diff --git a/include/atomic/x86-gcc.h b/include/atomic/x86-gcc.h index 61b94a48568..8baa84e110e 100644 --- a/include/atomic/x86-gcc.h +++ b/include/atomic/x86-gcc.h @@ -53,18 +53,29 @@ #endif #define make_atomic_add_body32 \ - asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a)) + asm volatile (LOCK_prefix "; xadd %0, %1;" \ + : "+r" (v), "=m" (*a) \ + : "m" (*a) \ + : "memory") #define make_atomic_cas_body32 \ + __typeof__(*cmp) sav; \ asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \ - : "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set)) + : "=m" (*a), "=a" (sav), "=q" (ret) \ + : "r" (set), "m" (*a), "a" (*cmp) \ + : "memory"); \ + if (!ret) \ + *cmp= sav #ifdef __x86_64__ #define make_atomic_add_body64 make_atomic_add_body32 #define make_atomic_cas_body64 make_atomic_cas_body32 -#define make_atomic_fas_body(S) \ - asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (*a)) +#define make_atomic_fas_body(S) \ + asm volatile ("xchg %0, %1;" \ + : "+r" (v), "=m" (*a) \ + : "m" (*a) \ + : "memory") /* Actually 32-bit reads/writes are always atomic on x86 @@ -73,9 +84,14 @@ #define make_atomic_load_body(S) \ ret=0; \ asm volatile (LOCK_prefix "; cmpxchg %2, %0" \ - : "+m" (*a), "+a" (ret): "r" (ret)) + : "=m" (*a), "=a" (ret) \ + : "r" (ret), "m" (*a) \ + : "memory") #define make_atomic_store_body(S) \ - asm volatile ("; xchg %0, %1;" : "+m" (*a), "+r" (v)) + asm volatile ("; xchg %0, %1;" \ + : "=m" (*a), "+r" (v) \ + : "m" (*a) \ + : "memory") #else /* @@ -104,12 +120,13 @@ platforms the much simpler make_atomic_cas_body32 will work fine. */ -#define make_atomic_cas_body64 \ - int32 ebx=(set & 0xFFFFFFFF), ecx=(set >> 32); \ - asm volatile ("push %%ebx; movl %3, %%ebx;" \ - LOCK_prefix "; cmpxchg8b %0; setz %2; pop %%ebx"\ - : "+m" (*a), "+A" (*cmp), "=c" (ret) \ - :"m" (ebx), "c" (ecx)) +#define make_atomic_cas_body64 \ + int32 ebx=(set & 0xFFFFFFFF), ecx=(set >> 32); \ + asm volatile ("push %%ebx; movl %3, %%ebx;" \ + LOCK_prefix "; cmpxchg8b %0; setz %2; pop %%ebx" \ + : "=m" (*a), "+A" (*cmp), "=c" (ret) \ + : "m" (ebx), "c" (ecx), "m" (*a) \ + : "memory", "esp") #endif /* diff --git a/include/my_atomic.h b/include/my_atomic.h index 8ba3e201730..a2f454ac319 100644 --- a/include/my_atomic.h +++ b/include/my_atomic.h @@ -20,6 +20,7 @@ This header defines five atomic operations: my_atomic_add#(&var, what) + 'Fetch and Add' add 'what' to *var, and return the old value of *var my_atomic_fas#(&var, what) @@ -27,9 +28,10 @@ store 'what' in *var, and return the old value of *var my_atomic_cas#(&var, &old, new) - 'Compare And Swap' + An odd variation of 'Compare And Set/Swap' if *var is equal to *old, then store 'new' in *var, and return TRUE otherwise store *var in *old, and return FALSE + Usually, &old should not be accessed if the operation is successful. my_atomic_load#(&var) return *var diff --git a/unittest/mysys/my_atomic-t.c b/unittest/mysys/my_atomic-t.c index 9853d3cf964..95799be7bb1 100644 --- a/unittest/mysys/my_atomic-t.c +++ b/unittest/mysys/my_atomic-t.c @@ -15,13 +15,6 @@ #include "thr_template.c" -/* at least gcc 3.4.5 and 3.4.6 (but not 3.2.3) on RHEL */ -#if __GNUC__ == 3 && __GNUC_MINOR__ == 4 -#define GCC_BUG_WORKAROUND volatile -#else -#define GCC_BUG_WORKAROUND -#endif - volatile uint32 b32; volatile int32 c32; my_atomic_rwlock_t rwl; @@ -29,8 +22,8 @@ my_atomic_rwlock_t rwl; /* add and sub a random number in a loop. Must get 0 at the end */ pthread_handler_t test_atomic_add(void *arg) { - int m= (*(int *)arg)/2; - GCC_BUG_WORKAROUND int32 x; + int m= (*(int *)arg)/2; + int32 x; for (x= ((int)(intptr)(&m)); m ; m--) { x= (x*m+0x87654321) & INT_MAX32; @@ -52,8 +45,8 @@ volatile int64 a64; /* add and sub a random number in a loop. Must get 0 at the end */ pthread_handler_t test_atomic_add64(void *arg) { - int m= (*(int *)arg)/2; - GCC_BUG_WORKAROUND int64 x; + int m= (*(int *)arg)/2; + int64 x; for (x= ((int64)(intptr)(&m)); m ; m--) { x= (x*m+0xfdecba987654321LL) & INT_MAX64; @@ -128,8 +121,8 @@ pthread_handler_t test_atomic_fas(void *arg) */ pthread_handler_t test_atomic_cas(void *arg) { - int m= (*(int *)arg)/2, ok= 0; - GCC_BUG_WORKAROUND int32 x, y; + int m= (*(int *)arg)/2, ok= 0; + int32 x, y; for (x= ((int)(intptr)(&m)); m ; m--) { my_atomic_rwlock_wrlock(&rwl); |