diff options
author | Andrew W. Nosenko <andrew.w.nosenko@gmail.com> | 2012-04-27 17:05:32 +0300 |
---|---|---|
committer | Martin Sustrik <sustrik@250bpm.com> | 2012-04-29 07:30:42 +0200 |
commit | 8aafb03dee4520ea62cd0cc0c78a9b958ec5ae18 (patch) | |
tree | c3120eb3294510d7f1ddef683b1e3d0c6aaae06f /src/atomic_counter.hpp | |
parent | cdbaa67ff5fdb7cebab670e6f7906d9e81ae7f0a (diff) |
atomic: revisit the atomic operation checks and their usage
* configure.ac:
Check for working Solaris/NetBSD-style atomic.h independly on OS.
Add check for GCC-style __sync_*() builtins.
New defines: XS_ATOMIC_GCC_SYNC, XS_ATOMIC_SOLARIS.
Removed define: XS_FORCE_MUTEXES.
* src/atomic_counter.hpp:
(atomic_counter_t::add):
(atomic_counter_t::sub):
* src/atomic_ptr.hpp:
(atomic_ptr_t::xchg):
(atomic_ptr_t::cas):
Use result of these checks.
Preference order:
1. GCC-style __sync_*() builtins
2. Inline asm (x86, x86-64, armv7a)
3. Solaris/NetBSD-style atomic.h, Windows-specific API
4. Fallback to mutex-based implementation
Diffstat (limited to 'src/atomic_counter.hpp')
-rw-r--r-- | src/atomic_counter.hpp | 102 |
1 files changed, 43 insertions, 59 deletions
diff --git a/src/atomic_counter.hpp b/src/atomic_counter.hpp index bd89f72..32395d9 100644 --- a/src/atomic_counter.hpp +++ b/src/atomic_counter.hpp @@ -25,26 +25,16 @@ #include "stdint.hpp" #include "platform.hpp" -#if defined XS_FORCE_MUTEXES -#define XS_ATOMIC_COUNTER_MUTEX -#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__ -#define XS_ATOMIC_COUNTER_X86 -#elif defined __ARM_ARCH_7A__ && defined __GNUC__ -#define XS_ATOMIC_COUNTER_ARM -#elif defined XS_HAVE_WINDOWS -#define XS_ATOMIC_COUNTER_WINDOWS -#elif (defined XS_HAVE_SOLARIS || defined XS_HAVE_NETBSD) -#define XS_ATOMIC_COUNTER_ATOMIC_H +#if defined(XS_ATOMIC_GCC_SYNC) +#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) +#elif (defined(__GNUC__) && defined(__ARM_ARCH_7A__)) +#elif defined(XS_ATOMIC_SOLARIS) +# include <atomic.h> +#elif defined(XS_HAVE_WINDOWS) +# include "windows.hpp" #else -#define XS_ATOMIC_COUNTER_MUTEX -#endif - -#if defined XS_ATOMIC_COUNTER_MUTEX -#include "mutex.hpp" -#elif defined XS_ATOMIC_COUNTER_WINDOWS -#include "windows.hpp" -#elif defined XS_ATOMIC_COUNTER_ATOMIC_H -#include <atomic.h> +# define XS_ATOMIC_OVER_MUTEX 1 +# include "mutex.hpp" #endif namespace xs @@ -79,20 +69,17 @@ namespace xs { integer_t old_value; -#if defined XS_ATOMIC_COUNTER_WINDOWS - old_value = InterlockedExchangeAdd ((LONG*) &value, increment_); -#elif defined __GNUC__ && !defined XS_DISABLE_GCC_SYNC_BUILTINS +#if defined(XS_ATOMIC_GCC_SYNC) old_value = __sync_fetch_and_add (&value, increment_); -#elif defined XS_ATOMIC_COUNTER_ATOMIC_H - integer_t new_value = atomic_add_32_nv (&value, increment_); - old_value = new_value - increment_; -#elif defined XS_ATOMIC_COUNTER_X86 + +#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) __asm__ volatile ( "lock; xadd %0, %1 \n\t" : "=r" (old_value), "=m" (value) : "0" (increment_), "m" (value) : "cc", "memory"); -#elif defined XS_ATOMIC_COUNTER_ARM + +#elif (defined(__GNUC__) && defined(__ARM_ARCH_7A__)) integer_t flag, tmp; __asm__ volatile ( " dmb sy\n\t" @@ -105,13 +92,19 @@ namespace xs : "=&r"(old_value), "=&r"(flag), "=&r"(tmp), "+Qo"(value) : "Ir"(increment_), "r"(&value) : "cc"); -#elif defined XS_ATOMIC_COUNTER_MUTEX + +#elif defined(XS_ATOMIC_SOLARIS) + integer_t new_value = atomic_add_32_nv (&value, increment_); + old_value = new_value - increment_; + +#elif defined(XS_HAVE_WINDOWS) + old_value = InterlockedExchangeAdd ((LONG*) &value, increment_); + +#else sync.lock (); old_value = value; value += increment_; sync.unlock (); -#else -#error atomic_counter is not implemented for this platform #endif return old_value; } @@ -119,18 +112,11 @@ namespace xs // Atomic subtraction. Returns false if the counter drops to zero. inline bool sub (integer_t decrement) { -#if defined XS_ATOMIC_COUNTER_WINDOWS - LONG delta = - ((LONG) decrement); - integer_t old = InterlockedExchangeAdd ((LONG*) &value, delta); - return old - decrement != 0; -#elif defined __GNUC__ && !defined XS_DISABLE_GCC_SYNC_BUILTINS +#if defined(XS_ATOMIC_GCC_SYNC) integer_t new_value = __sync_sub_and_fetch (&value, decrement); return (new_value != 0); -#elif defined XS_ATOMIC_COUNTER_ATOMIC_H - int32_t delta = - ((int32_t) decrement); - integer_t nv = atomic_add_32_nv (&value, delta); - return nv != 0; -#elif defined XS_ATOMIC_COUNTER_X86 + +#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) integer_t oldval = -decrement; volatile integer_t *val = &value; __asm__ volatile ("lock; xaddl %0,%1" @@ -138,7 +124,8 @@ namespace xs : "0" (oldval), "m" (*val) : "cc", "memory"); return oldval != decrement; -#elif defined XS_ATOMIC_COUNTER_ARM + +#elif (defined(__GNUC__) && defined(__ARM_ARCH_7A__)) integer_t old_value, flag, tmp; __asm__ volatile ( " dmb sy\n\t" @@ -152,14 +139,23 @@ namespace xs : "Ir"(decrement), "r"(&value) : "cc"); return old_value - decrement != 0; -#elif defined XS_ATOMIC_COUNTER_MUTEX + +#elif defined(XS_ATOMIC_SOLARIS) + int32_t delta = - ((int32_t) decrement); + integer_t nv = atomic_add_32_nv (&value, delta); + return nv != 0; + +#elif defined(XS_HAVE_WINDOWS) + LONG delta = - ((LONG) decrement); + integer_t old = InterlockedExchangeAdd ((LONG*) &value, delta); + return old - decrement != 0; + +#else sync.lock (); value -= decrement; bool result = value ? true : false; sync.unlock (); return result; -#else -#error atomic_counter is not implemented for this platform #endif } @@ -171,7 +167,7 @@ namespace xs private: volatile integer_t value; -#if defined XS_ATOMIC_COUNTER_MUTEX +#if defined(XS_ATOMIC_OVER_MUTEX) mutex_t sync; #endif @@ -182,20 +178,8 @@ namespace xs } // Remove macros local to this file. -#if defined XS_ATOMIC_COUNTER_WINDOWS -#undef XS_ATOMIC_COUNTER_WINDOWS -#endif -#if defined XS_ATOMIC_COUNTER_ATOMIC_H -#undef XS_ATOMIC_COUNTER_ATOMIC_H -#endif -#if defined XS_ATOMIC_COUNTER_X86 -#undef XS_ATOMIC_COUNTER_X86 -#endif -#if defined XS_ATOMIC_COUNTER_ARM -#undef XS_ATOMIC_COUNTER_ARM -#endif -#if defined XS_ATOMIC_COUNTER_MUTEX -#undef XS_ATOMIC_COUNTER_MUTEX +#if defined(XS_ATOMIC_OVER_MUTEX) +# undef XS_ATOMIC_OVER_MUTEX #endif #endif |