AtomicCounter.h

00001 /* This file is Copyright 2000-2008 Meyer Sound Laboratories Inc.  See the included LICENSE.txt file for details. */ 
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>  // for the QT_VERSION number
00010 # if (QT_VERSION < 0x040400)
00011 #  include <QAtomic>   // the old, undocumented Qt4 API
00012 #  define MUSCLE_USE_PRIVATE_QT4_ATOMIC_API
00013 # else
00014 #  include <QAtomicInt>  // the new, documented Qt4 API, available in Qt 4.4.0 and higher
00015 # endif
00016 #endif
00017 
00018 #if defined(MUSCLE_CUSTOM_ATOMIC_TYPE)
00019  extern void MuscleCustomAtomicInitialize(volatile MUSCLE_CUSTOM_ATOMIC_TYPE * c);  // should set (*c) to zero
00020  extern void MuscleCustomAtomicDestroy(   volatile MUSCLE_CUSTOM_ATOMIC_TYPE * c);  // Called when the AtomicCounter is going away
00021  extern void MuscleCustomAtomicIncrement( volatile MUSCLE_CUSTOM_ATOMIC_TYPE * c);  // should atomically increment (*c)
00022  extern bool MuscleCustomAtomicDecrement( volatile MUSCLE_CUSTOM_ATOMIC_TYPE * c);  // should atomically decrement (*c) and return true iff the result is zero
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     // empty
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;  // tmp will be set to the value after the increment
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          : // No outputs
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;   // tmp will be set to the value after the decrement
00155       asm volatile( 
00156          "1:     lwarx   %0,0,%1\n" 
00157          "       addic   %0,%0,-1\n"  // addic allows r0, addi doesn't 
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

Generated on Thu Jun 5 17:47:52 2008 for MUSCLE by  doxygen 1.5.1