summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rw-r--r--cpp/config/Make.rules.Linux5
-rw-r--r--cpp/include/IceUtil/Shared.h17
-rw-r--r--cpp/src/IceUtil/Shared.cpp13
3 files changed, 34 insertions, 1 deletions
diff --git a/cpp/config/Make.rules.Linux b/cpp/config/Make.rules.Linux
index 5071876805d..5ec54bc32d3 100644
--- a/cpp/config/Make.rules.Linux
+++ b/cpp/config/Make.rules.Linux
@@ -13,6 +13,7 @@
USE_SPARC_ASM = irrelevant
MACHINE = $(shell uname -m)
+SUSE_i586 = $(shell grep i586 /etc/SuSE-release 2>/dev/null)
#
# Default compiler is c++ (aka g++).
@@ -40,6 +41,10 @@ endif
ifeq ($(CXX),c++)
+ ifneq ($(SUSE_i586),)
+ CXXARCHFLAGS += -march=i586
+ endif
+
ifeq ($(MACHINE),sparc64)
#
# We are an ultra, at least, and so have the atomic instructions
diff --git a/cpp/include/IceUtil/Shared.h b/cpp/include/IceUtil/Shared.h
index a23a55fb3ae..64e4c51a74d 100644
--- a/cpp/include/IceUtil/Shared.h
+++ b/cpp/include/IceUtil/Shared.h
@@ -13,9 +13,24 @@
#include <IceUtil/Config.h>
#if 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 __GNUC__ >= 4 && __GNUC_MINOR__ >= 1 && \
+ ((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(__APPLE__) || defined(__linux) || defined(__FreeBSD__)) && (defined(__i386) || defined(__x86_64)) && !defined(__ICC)
+
# define ICE_HAS_ATOMIC_FUNCTIONS
#elif defined(_WIN32)
@@ -119,7 +134,7 @@ protected:
#if defined(_WIN32)
LONG _ref;
-#elif defined(ICE_HAS_ATOMIC_FUNCTIONS)
+#elif defined(ICE_HAS_ATOMIC_FUNCTIONS) || defined(ICE_HAS_GCC_BUILTINS)
volatile int _ref;
#else
int _ref;
diff --git a/cpp/src/IceUtil/Shared.cpp b/cpp/src/IceUtil/Shared.cpp
index 2c0205a4265..c25e8e74ee6 100644
--- a/cpp/src/IceUtil/Shared.cpp
+++ b/cpp/src/IceUtil/Shared.cpp
@@ -114,6 +114,9 @@ IceUtil::Shared::__incRef()
#if defined(_WIN32)
assert(InterlockedExchangeAdd(&_ref, 0) >= 0);
InterlockedIncrement(&_ref);
+#elif defined(ICE_HAS_GCC_BUILTINS)
+ int c = __sync_fetch_and_add(&_ref, 1);
+ assert(c >= 0);
#elif defined(ICE_HAS_ATOMIC_FUNCTIONS)
assert(IceUtilInternal::atomicExchangeAdd(&_ref, 0) >= 0);
IceUtilInternal::atomicInc(&_ref);
@@ -135,6 +138,14 @@ IceUtil::Shared::__decRef()
_noDelete = true;
delete this;
}
+#elif defined(ICE_HAS_GCC_BUILTINS)
+ int c = __sync_fetch_and_sub(&_ref, 1);
+ assert(c > 0);
+ if(c == 1 && !_noDelete)
+ {
+ _noDelete = true;
+ delete this;
+ }
#elif defined(ICE_HAS_ATOMIC_FUNCTIONS)
assert(IceUtilInternal::atomicExchangeAdd(&_ref, 0) > 0);
if(IceUtilInternal::atomicDecAndTest(&_ref) && !_noDelete)
@@ -164,6 +175,8 @@ IceUtil::Shared::__getRef() const
{
#if defined(_WIN32)
return InterlockedExchangeAdd(const_cast<LONG*>(&_ref), 0);
+#elif defined(ICE_HAS_GCC_BUILTINS)
+ return __sync_fetch_and_sub(const_cast<volatile int*>(&_ref), 0);
#elif defined(ICE_HAS_ATOMIC_FUNCTIONS)
return IceUtilInternal::atomicExchangeAdd(const_cast<volatile int*>(&_ref), 0);
#else