summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/atomic/gcc_builtins.h5
-rw-r--r--include/atomic/nolock.h17
-rw-r--r--include/atomic/x86-gcc.h41
-rw-r--r--include/my_atomic.h4
-rw-r--r--unittest/mysys/my_atomic-t.c19
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);