"Fossies" - the Fresh Open Source Software Archive

Member "muscle/system/AtomicCounter.h" (8 Jun 2019, 7825 Bytes) of package /linux/privat/muscle7.30.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AtomicCounter.h" see the Fossies "Dox" file reference documentation.

    1 /* This file is Copyright 2000-2013 Meyer Sound Laboratories Inc.  See the included LICENSE.txt file for details. */ 
    2 
    3 #ifndef MuscleAtomicCounter_h 
    4 #define MuscleAtomicCounter_h 
    5 
    6 #include "support/MuscleSupport.h"
    7 
    8 #ifdef MUSCLE_SINGLE_THREAD_ONLY
    9   // empty
   10 #elif !defined(MUSCLE_AVOID_CPLUSPLUS11)
   11 # include <atomic>
   12 #elif defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
   13   // empty
   14 #elif defined(__ATHEOS__)
   15 # include <atheos/atomic.h>
   16 #elif defined(__BEOS__) || defined(__HAIKU__)
   17 # include <kernel/OS.h>
   18 #elif defined(WIN32)
   19   // empty
   20 #elif defined(__APPLE__)
   21 # include <libkern/OSAtomic.h>
   22 #elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY) || defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
   23   // empty
   24 #elif defined(MUSCLE_USE_PTHREADS) || defined(ANDROID) 
   25 # define MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS
   26 #endif
   27 
   28 #if defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
   29 # include "system/Mutex.h"
   30 # ifndef MUSCLE_MUTEX_POOL_SIZE
   31 #  define MUSCLE_MUTEX_POOL_SIZE 256
   32 # endif
   33 #endif
   34 
   35 namespace muscle {
   36 
   37 #if defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
   38 extern Mutex * _muscleAtomicMutexes;
   39 static inline int32 DoMutexAtomicIncrement(volatile int32 * count, int32 delta)
   40 {
   41    int32 ret;
   42    if (_muscleAtomicMutexes)
   43    {
   44       MutexGuard mg(_muscleAtomicMutexes[(((uint32)((uintptr)count))/sizeof(int32))%MUSCLE_MUTEX_POOL_SIZE]);  // double-cast for AMD64
   45       ret = *count = (*count + delta);
   46    }
   47    else
   48    {
   49       // if _muscleAtomicMutexes isn't allocated, then we're in process-setup or process-shutdown, so there are no multiple threads at the moment, so we can just do this
   50       ret = *count = (*count + delta);
   51    }
   52    return ret;
   53 }
   54 #endif
   55 
   56 /** This is a teensy little class that works as a cross-platform atomic counter variable. 
   57   * It's been ifdef'd all to hell, so that it tries to always use the most efficient API
   58   * possible based on the host CPU and OS.  If compiled with -DMUSCLE_SINGLE_THREAD_ONLY,
   59   * it degenerates to a regular old counter variable, which is very lightweight and portable,
   60   * but of course will only work properly in single-threaded environments.
   61   */
   62 class AtomicCounter MUSCLE_FINAL_CLASS
   63 {
   64 public:
   65    /** Default constructor.  The count value is initialized to zero. */
   66    AtomicCounter() : _count(0)
   67    {
   68       // empty
   69    }
   70 
   71    /** Destructor */
   72    ~AtomicCounter()
   73    {
   74       // empty
   75    }
   76 
   77    /** Atomically increments our counter by one.
   78      * Returns true iff the count's new value is 1; returns false
   79      *              if the count's new value is any other value.
   80      */
   81    inline bool AtomicIncrement() 
   82    {
   83 #if defined(MUSCLE_SINGLE_THREAD_ONLY) || !defined(MUSCLE_AVOID_CPLUSPLUS11)
   84       return (++_count == 1);
   85 #elif defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
   86       return (DoMutexAtomicIncrement(&_count, 1) == 1);
   87 #elif defined(WIN32) 
   88       return (InterlockedIncrement(&_count) == 1);
   89 #elif defined(__APPLE__) 
   90       return (OSAtomicIncrement32Barrier(&_count) == 1);
   91 #elif defined(__ATHEOS__) || defined(__BEOS__) || defined(__HAIKU__)
   92       return (atomic_add(&_count,1) == 0);  // atomic_add() returns the previous value
   93 #elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY)
   94       volatile int * p = &_count;
   95       int tmp;  // tmp will be set to the value after the increment
   96       asm volatile( 
   97          "1:     lwarx   %0,0,%1\n" 
   98          "       addic   %0,%0,1\n" 
   99          "       stwcx.  %0,0,%1\n" 
  100          "       bne-    1b" 
  101          : "=&r" (tmp) 
  102          : "r" (p) 
  103          : "cc", "memory");
  104       return (tmp == 1);
  105 #elif defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
  106       int value = 1;  // the increment-by value
  107       asm volatile(
  108          "lock; xaddl %%eax, %2;"
  109          :"=a" (value)                 // Output
  110          : "a" (value), "m" (_count)  // Input
  111          :"memory");
  112       return (value==0);  // at this point value contains the counter's pre-increment value
  113 #else
  114 # error "No atomic increment supplied for this OS!  Add it here in AtomicCount.h, remove -DMUSCLE_AVOID_CPLUSPLUS11 from your compiler-defines to use std::atomic, or put -DMUSCLE_SINGLE_THREAD_ONLY in your compiler-defines if you will not be using multithreading." 
  115 #endif 
  116    }
  117 
  118    /** Atomically decrements our counter by one.
  119      * @returns true iff the new value of our count is 0;
  120      *               returns false if it is any other value
  121      */
  122    inline bool AtomicDecrement() 
  123    {
  124 #if defined(MUSCLE_SINGLE_THREAD_ONLY) || !defined(MUSCLE_AVOID_CPLUSPLUS11)
  125       return (--_count == 0);
  126 #elif defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
  127       return (DoMutexAtomicIncrement(&_count, -1) == 0);
  128 #elif defined(WIN32) 
  129       return (InterlockedDecrement(&_count) == 0);
  130 #elif defined(__APPLE__)
  131       return (OSAtomicDecrement32Barrier(&_count) == 0);
  132 #elif defined(__ATHEOS__) 
  133       return (atomic_add(&_count,-1)==1);
  134 #elif defined(__BEOS__) || defined(__HAIKU__)
  135       return (atomic_add(&_count,-1)==1);
  136 #elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY)
  137       volatile int * p = &_count;
  138       int tmp;   // tmp will be set to the value after the decrement
  139       asm volatile( 
  140          "1:     lwarx   %0,0,%1\n" 
  141          "       addic   %0,%0,-1\n"  // addic allows r0, addi doesn't 
  142          "       stwcx.  %0,0,%1\n" 
  143          "       bne-    1b" 
  144          : "=&r" (tmp) 
  145          : "r" (p) 
  146          : "cc", "memory"); 
  147       return(tmp == 0); 
  148 #elif defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
  149       bool isZero;
  150       volatile int * p = &_count;
  151       asm volatile(
  152          "lock; decl (%1)\n"
  153          "sete %0"
  154          : "=q" (isZero)
  155          : "q" (p)
  156          : "cc", "memory"
  157          );
  158       return isZero;
  159 #else
  160 # error "No atomic decrement supplied for this OS!  Add it here in AtomicCount.h, or remove -DMUSCLE_AVOID_CPLUSPLUS11 in your compiler-defines to use std::atomic, or put -DMUSCLE_SINGLE_THREAD_ONLY in your compiler-defines if you will not be using multithreading." 
  161 #endif 
  162    }
  163 
  164    /** Returns the current value of this counter.
  165      * Be careful when using this function in multithreaded
  166      * environments, it can easily lead to race conditions
  167      * if you don't know what you are doing!
  168      */
  169    int32 GetCount() const {return (int32) _count;}
  170 
  171    /** Sets the current value of this counter.
  172      * Be careful when using this function in multithreaded
  173      * environments, it can easily lead to race conditions
  174      * if you don't know what you are doing!
  175      * @param c the new count-value to set
  176      */
  177    void SetCount(int32 c) {_count = c;}
  178 
  179 #if !defined(MUSCLE_AVOID_CPLUSPLUS11) && !defined(MUSCLE_SINGLE_THREAD_ONLY)
  180    /** Copy constructor, defined explicitly for the C++11-based implementation,
  181      * since std::atomic<int32> won't compile using the implicit copy constructor.
  182      * @param rhs the AtomicCounter to make this one equivalent to
  183      */
  184    AtomicCounter(const AtomicCounter & rhs) {_count.store(rhs._count.load());}
  185 
  186    /** Assignment operator, defined explicitly for C++11-based implementation
  187      * since std::atomic<int32> won't compile using the implicit copy constructor.
  188      * @param rhs the AtomicCounter to make this one equivalent to
  189      */
  190    AtomicCounter & operator=(const AtomicCounter & rhs) {_count.store(rhs._count.load()); return *this;}
  191 #endif
  192 
  193 private:
  194 #if defined(MUSCLE_SINGLE_THREAD_ONLY) || defined(__HAIKU__)
  195    int32 _count;
  196 #elif !defined(MUSCLE_AVOID_CPLUSPLUS11)
  197    std::atomic<int32> _count;
  198 #elif defined(__ATHEOS__)
  199    atomic_t _count;
  200 #elif defined(WIN32)
  201    long _count;
  202 #elif defined(__APPLE__)
  203    volatile int32_t _count;
  204 #elif defined(__BEOS__)
  205 # if defined(B_BEOS_VERSION_5)
  206    vint32 _count;
  207 # else
  208    int32 _count;
  209 # endif
  210 #elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY) || defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
  211    volatile int _count;
  212 #else
  213    volatile int32 _count;
  214 #endif
  215 };
  216 
  217 } // end namespace muscle
  218 
  219 #endif