summaryrefslogtreecommitdiff
path: root/cpp/src/IceUtil/Shared.cpp
diff options
context:
space:
mode:
authorMatthew Newhook <matthew@zeroc.com>2008-03-18 17:56:47 +0800
committerMatthew Newhook <matthew@zeroc.com>2008-03-18 17:56:47 +0800
commit49854a2b746653c73874bbd4b94eec5d99fa7151 (patch)
tree07845efff58287a9b54663b1b7bd22ad71e9c93c /cpp/src/IceUtil/Shared.cpp
parentMore fixes for bug 2822 (diff)
downloadice-49854a2b746653c73874bbd4b94eec5d99fa7151.tar.bz2
ice-49854a2b746653c73874bbd4b94eec5d99fa7151.tar.xz
ice-49854a2b746653c73874bbd4b94eec5d99fa7151.zip
http://bugzilla.zeroc.com/bugzilla/show_bug.cgi?id=2429
Squashed commit of the following: commit de2c29521182cb96394accffff2cc53589b048c2 Author: Matthew Newhook <matthew@zeroc.com> Date: Tue Mar 18 17:51:22 2008 +0800 Fix another .depend. commit 71031490cc200b5bdba6ffa8f81d04268e74e179 Author: Matthew Newhook <matthew@zeroc.com> Date: Tue Mar 18 17:46:24 2008 +0800 revert to master .depend. commit ba2b9e5eeea9af5b751d9e79a00751485141b4f3 Author: Matthew Newhook <matthew@zeroc.com> Date: Tue Mar 18 17:25:35 2008 +0800 Removed bogus change to Make.rules.Darwin. commit 528b433bf6e4179033588e19a4930e2cda18e225 Author: Matthew Newhook <matthew@zeroc.com> Date: Tue Mar 18 16:28:46 2008 +0800 Enable interlocked reference counting under intel mac commit 7353025feecaaef7ad64b14636c631c6e0f5ac67 Author: Matthew Newhook <matthew@centosvm4.matthew.zeroc.com> Date: Tue Mar 18 14:04:42 2008 +0800 fix bug with assertion. commit 1235239af0516e8948d876b0eaf1ba9a8dcbec2e Author: matthew newhook <matthew@june.matthew.zeroc.com> Date: Tue Mar 18 14:00:00 2008 +0800 Simplify shared implementation.
Diffstat (limited to 'cpp/src/IceUtil/Shared.cpp')
-rw-r--r--cpp/src/IceUtil/Shared.cpp94
1 files changed, 78 insertions, 16 deletions
diff --git a/cpp/src/IceUtil/Shared.cpp b/cpp/src/IceUtil/Shared.cpp
index f18b9385798..1121ab3c823 100644
--- a/cpp/src/IceUtil/Shared.cpp
+++ b/cpp/src/IceUtil/Shared.cpp
@@ -10,7 +10,79 @@
#include <IceUtil/Shared.h>
using namespace IceUtil;
-using namespace IceUtilInternal;
+
+#ifdef ICE_HAS_ATOMIC_FUNCTIONS
+
+namespace IceUtilInternal
+{
+
+//
+// Linux only. Unfortunately, asm/atomic.h builds non-SMP safe code
+// with non-SMP kernels. This means that executables compiled with a
+// non-SMP kernel would fail randomly due to concurrency errors with
+// reference counting on SMP hosts. Therefore the relevent pieces of
+// atomic.h are more-or-less duplicated.
+//
+
+/*
+ * atomicInc - increment ice_atomic variable
+ * @v: pointer of type AtomicCounter
+ *
+ * Atomically increments @v by 1. Note that the guaranteed useful
+ * range of an AtomicCounter is only 24 bits.
+ *
+ * Inlined because this operation is performance critical.
+ */
+static inline void atomicInc(volatile int* counter)
+{
+ __asm__ __volatile__(
+ "lock ; incl %0"
+ :"=m" (*counter)
+ :"m" (*counter));
+}
+
+/**
+ * atomicDecAndTest - decrement and test
+ * @v: pointer of type AtomicCounter
+ *
+ * Atomically decrements @v by 1 and returns true if the result is 0,
+ * or false for all other cases. Note that the guaranteed useful
+ * range of an AtomicCounter is only 24 bits.
+ *
+ * Inlined because this operation is performance critical.
+ */
+static inline int atomicDecAndTest(volatile int* counter)
+{
+ unsigned char c;
+ __asm__ __volatile__(
+ "lock ; decl %0; sete %1"
+ :"=m" (*counter), "=qm" (c)
+ :"m" (*counter) : "memory");
+ return c != 0;
+}
+
+/**
+ * atomicExchangeAdd - same as InterlockedExchangeAdd. This
+ * didn't come from atomic.h (the code was derived from similar code
+ * in /usr/include/asm/rwsem.h)
+ *
+ * Inlined because this operation is performance critical.
+ */
+static inline int atomicExchangeAdd(volatile int* counter, int i)
+{
+ int tmp = i;
+ __asm__ __volatile__(
+ "lock ; xadd %0,(%2)"
+ :"+r"(tmp), "=m"(*counter)
+ :"r"(counter), "m"(*counter)
+ : "memory");
+ return tmp + i;
+}
+
+}
+
+#endif
+
IceUtil::SimpleShared::SimpleShared() :
_ref(0),
@@ -25,25 +97,15 @@ IceUtil::SimpleShared::SimpleShared(const SimpleShared&) :
}
IceUtil::Shared::Shared() :
-#ifndef ICE_HAS_ATOMIC_FUNCTIONS
_ref(0),
-#endif
_noDelete(false)
{
-#ifdef ICE_HAS_ATOMIC_FUNCTIONS
- _ref.atomicSet(0);
-#endif
}
IceUtil::Shared::Shared(const Shared&) :
-#ifndef ICE_HAS_ATOMIC_FUNCTIONS
_ref(0),
-#endif
_noDelete(false)
{
-#ifdef ICE_HAS_ATOMIC_FUNCTIONS
- _ref.atomicSet(0);
-#endif
}
void
@@ -53,8 +115,8 @@ IceUtil::Shared::__incRef()
assert(InterlockedExchangeAdd(&_ref, 0) >= 0);
InterlockedIncrement(&_ref);
#elif defined(ICE_HAS_ATOMIC_FUNCTIONS)
- assert(_ref.atomicExchangeAdd(&_ref) >= 0);
- _ref.atomicInc();
+ assert(IceUtilInternal::atomicExchangeAdd(&_ref, 0) >= 0);
+ IceUtilInternal::atomicInc(&_ref);
#else
_mutex.lock();
assert(_ref >= 0);
@@ -74,8 +136,8 @@ IceUtil::Shared::__decRef()
delete this;
}
#elif defined(ICE_HAS_ATOMIC_FUNCTIONS)
- assert(_ref.atomicExchangeAdd(0) > 0);
- if(_ref.atomicDecAndTest() && !_noDelete)
+ assert(IceUtilInternal::atomicExchangeAdd(&_ref, 0) > 0);
+ if(IceUtilInternal::atomicDecAndTest(&_ref) && !_noDelete)
{
_noDelete = true;
delete this;
@@ -103,7 +165,7 @@ IceUtil::Shared::__getRef() const
#if defined(_WIN32)
return InterlockedExchangeAdd(const_cast<LONG*>(&_ref), 0);
#elif defined(ICE_HAS_ATOMIC_FUNCTIONS)
- return const_cast<IceUtilInternal::AtomicCounter*>(&_ref)->atomicExchangeAdd(0);
+ return IceUtilInternal::atomicExchangeAdd(const_cast<volatile int*>(&_ref), 0);
#else
_mutex.lock();
int ref = _ref;