00001
00002
00003 #ifndef MuscleAtomicCounter_h
00004 #define MuscleAtomicCounter_h
00005
00006 #include "support/MuscleSupport.h"
00007
00008 #if defined(QT_CORE_LIB)
00009 # include <QtCore>
00010 # if (QT_VERSION < 0x040400)
00011 # include <QAtomic>
00012 # define MUSCLE_USE_PRIVATE_QT4_ATOMIC_API
00013 # else
00014 # include <QAtomicInt>
00015 # endif
00016 #endif
00017
00018 #if defined(MUSCLE_CUSTOM_ATOMIC_TYPE)
00019 extern void MuscleCustomAtomicInitialize(volatile MUSCLE_CUSTOM_ATOMIC_TYPE * c);
00020 extern void MuscleCustomAtomicDestroy( volatile MUSCLE_CUSTOM_ATOMIC_TYPE * c);
00021 extern void MuscleCustomAtomicIncrement( volatile MUSCLE_CUSTOM_ATOMIC_TYPE * c);
00022 extern bool MuscleCustomAtomicDecrement( volatile MUSCLE_CUSTOM_ATOMIC_TYPE * c);
00023 #else
00024 # ifndef MUSCLE_SINGLE_THREAD_ONLY
00025 # if defined(__ATHEOS__)
00026 # include <atheos/atomic.h>
00027 # elif defined(__BEOS__)
00028 # include <kernel/OS.h>
00029 # elif defined(WIN32)
00030 # include <windows.h>
00031 # elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY) || defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
00032
00033 # elif defined(QT_VERSION) && (QT_VERSION >= 0x40000)
00034 # define MUSCLE_USE_QT_FOR_ATOMIC_OPERATIONS
00035 # elif defined(MUSCLE_USE_PTHREADS) || defined(QT_THREAD_SUPPORT)
00036 # define MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS 1
00037 BEGIN_NAMESPACE(muscle);
00038 extern int32 DoMutexAtomicIncrement(volatile int32 * count, int32 delta);
00039 END_NAMESPACE(muscle);
00040 # endif
00041 # endif
00042 #endif
00043
00044 BEGIN_NAMESPACE(muscle);
00045
00052 class AtomicCounter
00053 {
00054 public:
00056 AtomicCounter()
00057 #ifndef MUSCLE_CUSTOM_ATOMIC_TYPE
00058 : _count(0)
00059 #endif
00060 {
00061 #if defined(MUSCLE_CUSTOM_ATOMIC_TYPE)
00062 MuscleCustomAtomicInitialize(&_count);
00063 #endif
00064 }
00065
00067 ~AtomicCounter()
00068 {
00069 #if defined(MUSCLE_CUSTOM_ATOMIC_TYPE)
00070 MuscleCustomAtomicDestroy(&_count);
00071 #endif
00072 }
00073
00075 inline void AtomicIncrement()
00076 {
00077 #if defined(MUSCLE_CUSTOM_ATOMIC_TYPE)
00078 (void) MuscleCustomAtomicIncrement(&_count);
00079 #elif defined(MUSCLE_SINGLE_THREAD_ONLY)
00080 ++_count;
00081 #elif defined(WIN32)
00082 # if defined(_MSC_VER) && defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
00083 volatile int * p = &_count;
00084 __asm {
00085 mov eax, p;
00086 lock inc DWORD PTR [eax];
00087 };
00088 # else
00089 (void) InterlockedIncrement(&_count);
00090 # endif
00091 #elif defined(__ATHEOS__)
00092 (void) atomic_add(&_count,1);
00093 #elif defined(__BEOS__)
00094 (void) atomic_add(&_count,1);
00095 #elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY)
00096 volatile int * p = &_count;
00097 int tmp;
00098 asm volatile(
00099 "1: lwarx %0,0,%1\n"
00100 " addic %0,%0,1\n"
00101 " stwcx. %0,0,%1\n"
00102 " bne- 1b"
00103 : "=&r" (tmp)
00104 : "r" (p)
00105 : "cc", "memory");
00106 #elif defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
00107 volatile int * p = &_count;
00108 asm volatile(
00109 "lock; incl (%0)"
00110 :
00111 : "q" (p)
00112 : "cc", "memory");
00113 #elif defined(MUSCLE_USE_QT_FOR_ATOMIC_OPERATIONS)
00114 # ifdef MUSCLE_USE_PRIVATE_QT4_ATOMIC_API
00115 (void) q_atomic_increment(&_count);
00116 # else
00117 (void) _count.ref();
00118 # endif
00119 #elif defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
00120 (void) DoMutexAtomicIncrement(&_count, 1);
00121 #else
00122 # error "No atomic increment supplied for this OS! Add it here in AtomicCount.h, or put -DMUSCLE_SINGLE_THREAD_ONLY in your Makefile if you won't be using multithreading, or define MUSCLE_CUSTOM_ATOMIC_TYPE and supply your own atomic functions in your source code."
00123 #endif
00124 }
00125
00129 inline bool AtomicDecrement()
00130 {
00131 #if defined(MUSCLE_CUSTOM_ATOMIC_TYPE)
00132 return MuscleCustomAtomicDecrement(&_count);
00133 #elif defined(MUSCLE_SINGLE_THREAD_ONLY)
00134 return (--_count == 0);
00135 #elif defined(WIN32)
00136 # if defined(_MSC_VER) && defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
00137 bool isZero;
00138 volatile int * p = &_count;
00139 __asm {
00140 mov eax, p;
00141 lock dec DWORD PTR [eax];
00142 sete isZero;
00143 };
00144 return isZero;
00145 # else
00146 return (InterlockedDecrement(&_count) == 0);
00147 # endif
00148 #elif defined(__ATHEOS__)
00149 return (atomic_add(&_count,-1)==1);
00150 #elif defined(__BEOS__)
00151 return (atomic_add(&_count,-1)==1);
00152 #elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY)
00153 volatile int * p = &_count;
00154 int tmp;
00155 asm volatile(
00156 "1: lwarx %0,0,%1\n"
00157 " addic %0,%0,-1\n"
00158 " stwcx. %0,0,%1\n"
00159 " bne- 1b"
00160 : "=&r" (tmp)
00161 : "r" (p)
00162 : "cc", "memory");
00163 return(tmp == 0);
00164 #elif defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
00165 bool isZero;
00166 volatile int * p = &_count;
00167 asm volatile(
00168 "lock; decl (%1)\n"
00169 "sete %0"
00170 : "=q" (isZero)
00171 : "q" (p)
00172 : "cc", "memory"
00173 );
00174 return isZero;
00175 #elif defined(MUSCLE_USE_QT_FOR_ATOMIC_OPERATIONS)
00176 # ifdef MUSCLE_USE_PRIVATE_QT4_ATOMIC_API
00177 return (q_atomic_decrement(&_count) == 0);
00178 # else
00179 return (_count.deref() == false);
00180 # endif
00181 #elif defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
00182 return (DoMutexAtomicIncrement(&_count, -1) == 0);
00183 #else
00184 # error "No atomic decrement supplied for this OS! Add your own here in AtomicCounter.h, or put -DMUSCLE_SINGLE_THREAD_ONLY in your Makefile if you won't be using multithreading, or define MUSCLE_CUSTOM_ATOMIC_TYPE and supply your own atomic functions in your source code."
00185 #endif
00186 }
00187
00193 int32 GetCount() const {return (int32) _count;}
00194
00200 void SetCount(int32 c) {_count = c;}
00201
00202 private:
00203 #if defined(MUSCLE_CUSTOM_ATOMIC_TYPE)
00204 MUSCLE_CUSTOM_ATOMIC_TYPE _count;
00205 #elif defined(MUSCLE_SINGLE_THREAD_ONLY)
00206 int32 _count;
00207 #elif defined(__ATHEOS__)
00208 atomic_t _count;
00209 #elif defined(WIN32)
00210 # if defined(_MSC_VER) && defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
00211 volatile int _count;
00212 # else
00213 long _count;
00214 # endif
00215 #elif defined(__BEOS__)
00216 # if defined(B_BEOS_VERSION_5)
00217 vint32 _count;
00218 # else
00219 int32 _count;
00220 # endif
00221 #elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY) || defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
00222 volatile int _count;
00223 #elif defined(MUSCLE_USE_QT_FOR_ATOMIC_OPERATIONS)
00224 # ifdef MUSCLE_USE_PRIVATE_QT4_ATOMIC_API
00225 volatile int _count;
00226 # else
00227 QAtomicInt _count;
00228 # endif
00229 #else
00230 volatile int32 _count;
00231 #endif
00232 };
00233
00234 END_NAMESPACE(muscle);
00235
00236 #endif