summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew W. Nosenko <andrew.w.nosenko@gmail.com>2012-04-27 17:05:32 +0300
committerMartin Sustrik <sustrik@250bpm.com>2012-04-29 07:30:42 +0200
commit8aafb03dee4520ea62cd0cc0c78a9b958ec5ae18 (patch)
treec3120eb3294510d7f1ddef683b1e3d0c6aaae06f
parentcdbaa67ff5fdb7cebab670e6f7906d9e81ae7f0a (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
-rw-r--r--configure.ac78
-rw-r--r--src/atomic_counter.hpp102
-rw-r--r--src/atomic_ptr.hpp95
3 files changed, 129 insertions, 146 deletions
diff --git a/configure.ac b/configure.ac
index decbd6c..0d8b404 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,19 +106,6 @@ AS_CASE(["${host_os}"],
AC_DEFINE([XS_HAVE_SOLARIS], [1], [Have Solaris OS])
AC_CHECK_LIB([socket], [socket])
AC_CHECK_LIB([nsl], [gethostbyname])
- AC_MSG_CHECKING([whether atomic operations can be used])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
- [[#include <atomic.h>]],
- [[uint32_t value;
- atomic_cas_32 (&value, 0, 0);
- return 0;]])],
- [solaris_has_atomic=yes],
- [solaris_has_atomic=no])
- AC_MSG_RESULT([$solaris_has_atomic])
- # Solaris 8 does not have atomic operations exported to user space.
- AS_IF([test "x$solaris_has_atomic" = "xno"], [
- AC_DEFINE([XS_FORCE_MUTEXES], [1], [Force to use mutexes])
- ])
],
[*freebsd*], [
AC_DEFINE([XS_HAVE_FREEBSD], [1], [Have FreeBSD OS])
@@ -133,24 +120,6 @@ AS_CASE(["${host_os}"],
],
[*netbsd*], [
AC_DEFINE([XS_HAVE_NETBSD], [1], [Have NetBSD OS])
- # NetBSD 5.0 and newer provides atomic operations but we can
- # only use these on systems where PR #42842 has been fixed so
- # we must try and link a test program using C++.
- libxs_netbsd_has_atomic=no
- AC_MSG_CHECKING([whether atomic operations can be used])
- AC_LANG_PUSH([C++])
- AC_LINK_IFELSE([AC_LANG_PROGRAM(
- [[#include <atomic.h>]],
- [[uint32_t value;
- atomic_cas_32 (&value, 0, 0);
- return 0;]])],
- [libxs_netbsd_has_atomic=yes],
- [libxs_netbsd_has_atomic=no])
- AC_LANG_POP([C++])
- AC_MSG_RESULT([$libxs_netbsd_has_atomic])
- AS_IF([test "x$libxs_netbsd_has_atomic" = "xno"], [
- AC_DEFINE([XS_FORCE_MUTEXES], [1], [Force to use mutexes])
- ])
],
[openbsd*], [
AC_DEFINE([XS_HAVE_OPENBSD], [1], [Have OpenBSD OS])
@@ -241,6 +210,53 @@ AC_CHECK_HEADERS([ifaddrs.h],
[AC_DEFINE([XS_HAVE_IFADDRS], [1], [Have ifaddrs.h header.])])
###############################################################################
+# Check available atomic implementations
+#
+# We have following variants:
+# o gcc __sync_*() [XS_ATOMIC_GCC_SYNC]
+# o optional atomic.h with atomic_cas_32() on solaris and netbsd [XS_ATOMIC_SOLARIS]
+# o windows specific [XS_HAVE_WINDOWS]
+# o handwritten inline asm for x86 and arm [no specific define]
+# o fallback to mutexes (or force by hands) [no specific define]
+
+#
+# Check for Solaris and NetBSD style atomic.h
+#
+AC_LANG_PUSH([C++])
+AC_MSG_CHECKING([for Solaris/NetBSD-style atomic.h])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+ [[#include <atomic.h>]],
+ [[uint32_t value;
+ atomic_cas_32 (&value, 0, 0);
+ return 0;]])],
+ [solaris_style_atomic=yes],
+ [solaris_style_atomic=no])
+AC_MSG_RESULT([$solaris_style_atomic])
+AS_IF([test "x$solaris_style_atomic" = "xyes"], [
+ AC_DEFINE([XS_ATOMIC_SOLARIS], [1], [Solaris/NetBSD-style atomic.h with atomic_cas_32()])
+])
+AC_LANG_POP([C++])
+
+#
+# Check for GCC-style __sync_*() builtins
+#
+AC_LANG_PUSH([C++])
+AC_MSG_CHECKING([for GCC-style __sync_*() atomic builtins])
+AC_LINK_IFELSE([AC_LANG_PROGRAM(
+ [volatile void* p;],
+ [[ int r;
+ r = __sync_bool_compare_and_swap(&p, (void*) 0x12345, (void*) 0);
+ return r;]])],
+ [gcc_style_sync_atomic=yes],
+ [gcc_style_sync_atomic=no])
+AC_MSG_RESULT([$gcc_style_sync_atomic])
+AS_IF([test "x$gcc_style_sync_atomic" = "xyes"], [
+ AC_DEFINE([XS_ATOMIC_GCC_SYNC], [1], [GCC-style __sync_*() atomic builtins])
+])
+AC_LANG_POP([C++])
+
+
+###############################################################################
# Check polling system #
###############################################################################
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
diff --git a/src/atomic_ptr.hpp b/src/atomic_ptr.hpp
index 2e585b7..08418d3 100644
--- a/src/atomic_ptr.hpp
+++ b/src/atomic_ptr.hpp
@@ -26,26 +26,16 @@
#include "platform.hpp"
-#if defined XS_FORCE_MUTEXES
-#define XS_ATOMIC_PTR_MUTEX
-#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
-#define XS_ATOMIC_PTR_X86
-#elif defined __ARM_ARCH_7A__ && defined __GNUC__
-#define XS_ATOMIC_PTR_ARM
-#elif defined XS_HAVE_WINDOWS
-#define XS_ATOMIC_PTR_WINDOWS
-#elif (defined XS_HAVE_SOLARIS || defined XS_HAVE_NETBSD)
-#define XS_ATOMIC_PTR_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_PTR_MUTEX
-#endif
-
-#if defined XS_ATOMIC_PTR_MUTEX
-#include "mutex.hpp"
-#elif defined XS_ATOMIC_PTR_WINDOWS
-#include "windows.hpp"
-#elif defined XS_ATOMIC_PTR_ATOMIC_H
-#include <atomic.h>
+# define XS_ATOMIC_OVER_MUTEX 1
+# include "mutex.hpp"
#endif
namespace xs
@@ -80,9 +70,7 @@ namespace xs
// to the 'val' value. Old value is returned.
inline T *xchg (T *val_)
{
-#if defined XS_ATOMIC_PTR_WINDOWS
- return (T*) InterlockedExchangePointer ((PVOID*) &ptr, val_);
-#elif defined __GNUC__ && !defined XS_DISABLE_GCC_SYNC_BUILTINS
+#if defined(XS_ATOMIC_GCC_SYNC)
{
T* ov;
do
@@ -91,16 +79,16 @@ namespace xs
} while (!__sync_bool_compare_and_swap (&ptr, ov, val_));
return ov;
}
-#elif defined XS_ATOMIC_PTR_ATOMIC_H
- return (T*) atomic_swap_ptr (&ptr, val_);
-#elif defined XS_ATOMIC_PTR_X86
+
+#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
T *old;
__asm__ volatile (
"lock; xchg %0, %2"
: "=r" (old), "=m" (ptr)
: "m" (ptr), "0" (val_));
return old;
-#elif defined XS_ATOMIC_PTR_ARM
+
+#elif (defined(__GNUC__) && defined(__ARM_ARCH_7A__))
T* old;
unsigned int flag;
__asm__ volatile (
@@ -114,14 +102,19 @@ namespace xs
: "r"(&ptr), "r"(val_)
: "cc");
return old;
-#elif defined XS_ATOMIC_PTR_MUTEX
+
+#elif defined(XS_ATOMIC_SOLARIS)
+ return (T*) atomic_swap_ptr (&ptr, val_);
+
+#elif defined(XS_HAVE_WINDOWS)
+ return (T*) InterlockedExchangePointer ((PVOID*) &ptr, val_);
+
+#else
sync.lock ();
T *old = (T*) ptr;
ptr = val_;
sync.unlock ();
return old;
-#else
-#error atomic_ptr is not implemented for this platform
#endif
}
@@ -131,14 +124,10 @@ namespace xs
// is returned.
inline T *cas (T *cmp_, T *val_)
{
-#if defined XS_ATOMIC_PTR_WINDOWS
- return (T*) InterlockedCompareExchangePointer (
- (volatile PVOID*) &ptr, val_, cmp_);
-#elif defined __GNUC__ && !defined XS_DISABLE_GCC_SYNC_BUILTINS
+#if defined(XS_ATOMIC_GCC_SYNC)
return (T*) __sync_val_compare_and_swap (&ptr, cmp_, val_);
-#elif defined XS_ATOMIC_PTR_ATOMIC_H
- return (T*) atomic_cas_ptr (&ptr, cmp_, val_);
-#elif defined XS_ATOMIC_PTR_X86
+
+#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
T *old;
__asm__ volatile (
"lock; cmpxchg %2, %3"
@@ -146,7 +135,8 @@ namespace xs
: "r" (val_), "m" (ptr), "0" (cmp_)
: "cc");
return old;
-#elif defined XS_ATOMIC_PTR_ARM
+
+#elif (defined(__GNUC__) && defined(__ARM_ARCH_7A__))
T *old;
unsigned int flag;
__asm__ volatile (
@@ -162,22 +152,28 @@ namespace xs
: "r"(&ptr), "r"(cmp_), "r"(val_)
: "cc");
return old;
-#elif defined XS_ATOMIC_PTR_MUTEX
+
+#elif defined(XS_ATOMIC_SOLARIS)
+ return (T*) atomic_cas_ptr (&ptr, cmp_, val_);
+
+#elif defined(XS_HAVE_WINDOWS)
+ return (T*) InterlockedCompareExchangePointer (
+ (volatile PVOID*) &ptr, val_, cmp_);
+
+#else
sync.lock ();
T *old = (T*) ptr;
if (ptr == cmp_)
ptr = val_;
sync.unlock ();
return old;
-#else
-#error atomic_ptr is not implemented for this platform
#endif
}
private:
volatile T *ptr;
-#if defined XS_ATOMIC_PTR_MUTEX
+#if defined XS_ATOMIC_OVER_MUTEX
mutex_t sync;
#endif
@@ -188,21 +184,8 @@ namespace xs
}
// Remove macros local to this file.
-#if defined XS_ATOMIC_PTR_WINDOWS
-#undef XS_ATOMIC_PTR_WINDOWS
-#endif
-#if defined XS_ATOMIC_PTR_ATOMIC_H
-#undef XS_ATOMIC_PTR_ATOMIC_H
-#endif
-#if defined XS_ATOMIC_PTR_X86
-#undef XS_ATOMIC_PTR_X86
-#endif
-#if defined XS_ATOMIC_PTR_ARM
-#undef XS_ATOMIC_PTR_ARM
-#endif
-#if defined XS_ATOMIC_PTR_MUTEX
-#undef XS_ATOMIC_PTR_MUTEX
+#if defined(XS_ATOMIC_OVER_MUTEX)
+# undef XS_ATOMIC_OVER_MUTEX
#endif
#endif
-