summaryrefslogtreecommitdiff
path: root/cpp/include/IceUtil/Atomic.h
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/include/IceUtil/Atomic.h')
-rw-r--r--cpp/include/IceUtil/Atomic.h178
1 files changed, 178 insertions, 0 deletions
diff --git a/cpp/include/IceUtil/Atomic.h b/cpp/include/IceUtil/Atomic.h
new file mode 100644
index 00000000000..23d2577b404
--- /dev/null
+++ b/cpp/include/IceUtil/Atomic.h
@@ -0,0 +1,178 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#ifndef ICE_UTIL_ATOMIC_H
+#define ICE_UTIL_ATOMIC_H
+
+#if ((defined(ICE_CPP11) && defined(_MSC_VER) && (_MSC_VER > 1600)) || \
+ (defined(ICE_CPP11) && !defined(_MSC_VER)))
+# define ICE_CPP11_HAS_ATOMIC
+#endif
+
+#if defined(ICE_CPP11_HAS_ATOMIC)
+# include <atomic>
+#elif defined(ICE_USE_MUTEX_SHARED)
+
+# include <IceUtil/Mutex.h>
+
+// Using the gcc builtins requires gcc 4.1 or better. For Linux, i386
+// doesn't work. Apple is supported for all architectures. Sun only
+// supports sparc (32 and 64 bit).
+
+#elif ((defined(__GNUC__) && (((__GNUC__* 100) + __GNUC_MINOR__) >= 401)) || __clang__) && \
+ ((defined(__sun) && (defined(__sparc) || defined(__sparcv9))) || \
+ defined(__APPLE__) || \
+ (defined(__linux) && \
+ (defined(__i486) || defined(__i586) || \
+ defined(__i686) || defined(__x86_64))))
+
+# define ICE_HAS_GCC_BUILTINS
+
+#elif defined(_WIN32)
+// Nothing to include
+#else
+// Use a simple mutex
+# include <IceUtil/Mutex.h>
+#endif
+
+
+namespace IceUtilInternal
+{
+
+#ifdef ICE_CPP11_HAS_ATOMIC
+typedef std::atomic<int> Atomic;
+#else
+
+#if defined(_WIN32)
+//
+// volatile here is required by InterlockedExchangeXXX
+// family functions.
+//
+typedef volatile unsigned int ATOMIC_T;
+#else
+typedef int ATOMIC_T;
+#endif
+
+
+//
+// This is temporary and very partial placeholder for std::atomic,
+// which is not yet widely available.
+//
+class Atomic : public IceUtil::noncopyable
+{
+public:
+
+ Atomic() :
+ _ref(0)
+ {
+ }
+
+ Atomic(int desired) :
+ _ref(desired)
+ {
+ }
+
+ inline int fetch_add(int value)
+ {
+#if defined(_WIN32)
+ return InterlockedExchangeAdd(&_ref, value);
+#elif defined(ICE_HAS_GCC_BUILTINS)
+ return __sync_fetch_and_add(&_ref, value);
+#else
+ IceUtil::Mutex::Lock sync(_mutex);
+ int tmp = _ref;
+ _ref += value;
+ return tmp;
+#endif
+ }
+
+ inline int fetch_sub(int value)
+ {
+#if defined(_WIN32)
+ return InterlockedExchangeSubtract(&_ref, value);
+#elif defined(ICE_HAS_GCC_BUILTINS)
+ return __sync_fetch_and_sub(&_ref, value);
+#else
+ IceUtil::Mutex::Lock sync(_mutex);
+ ATOMIC_T tmp = _ref;
+ _ref -= value;
+ return tmp;
+#endif
+ }
+
+ inline int load() const
+ {
+#if defined(_WIN32)
+ return InterlockedExchangeAdd(const_cast<ATOMIC_T*>(&_ref), 0);
+#elif defined(ICE_HAS_GCC_BUILTINS)
+ return __sync_fetch_and_add(const_cast<ATOMIC_T*>(&_ref), 0);
+#else
+ IceUtil::Mutex::Lock sync(_mutex);
+ return _ref;
+#endif
+ }
+
+ inline int exchange(int value)
+ {
+#if defined(_WIN32)
+ return InterlockedExchange(&_ref, value);
+#elif defined(ICE_HAS_GCC_BUILTINS)
+ __sync_synchronize();
+ return __sync_lock_test_and_set(&_ref, value);
+#else
+ IceUtil::Mutex::Lock sync(_mutex);
+ int tmp = _ref;
+ _ref = value;
+ return _ref;
+#endif
+ }
+
+ inline int operator++()
+ {
+ return fetch_add(1) + 1;
+ }
+
+ inline int operator--()
+ {
+ return fetch_sub(1) - 1;
+ }
+
+ inline int operator++(int)
+ {
+ return fetch_add(1);
+ }
+
+ inline int operator--(int)
+ {
+ return fetch_sub(1);
+ }
+
+ inline operator int()
+ {
+ return load();
+ }
+
+ inline operator int() const
+ {
+ return load();
+ }
+
+private:
+
+ ATOMIC_T _ref;
+#if !defined(_WIN32) && !defined(ICE_HAS_GCC_BUILTINS)
+ Mutex _mutex;
+#endif
+};
+
+#endif
+
+}
+
+#endif