diff --git a/modules/juce_core/memory/juce_Atomic.h b/modules/juce_core/memory/juce_Atomic.h index 78f6faf6ef..90d874274e 100644 --- a/modules/juce_core/memory/juce_Atomic.h +++ b/modules/juce_core/memory/juce_Atomic.h @@ -144,10 +144,16 @@ namespace juce #else - #ifndef DOXYGEN - template class AtomicBase; + #if JUCE_MSVC + JUCE_COMPILER_WARNING ("You must use a version of MSVC which supports std::atomic") #endif + #if JUCE_IOS || JUCE_ANDROID // (64-bit ops will compile but not link) + #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 + #endif + + template class AtomicBase; + //============================================================================== /** Simple class to hold a primitive value and perform atomic operations on it. @@ -252,227 +258,163 @@ namespace juce static inline void memoryBarrier() noexcept { AtomicBase::memoryBarrier(); } }; - #ifndef DOXYGEN - - //============================================================================== - // Internal implementation follows - //============================================================================== - template - class AtomicBase - { - public: - typedef typename AtomicHelpers::DiffTypeHelper::Type DiffType; - - inline AtomicBase() noexcept : value (0) {} - inline explicit AtomicBase (const Type v) noexcept : value (v) {} - inline AtomicBase (const AtomicBase& other) noexcept : value (other.get()) {} - Type get() const noexcept; - inline AtomicBase& operator= (const AtomicBase& other) noexcept { exchange (other.get()); return *this; } - inline AtomicBase& operator= (const Type newValue) noexcept { exchange (newValue); return *this; } - void set (Type newValue) noexcept { exchange (newValue); } - Type exchange (Type) noexcept; - bool compareAndSetBool (Type, Type) noexcept; - Type compareAndSetValue (Type, Type) noexcept; - static void memoryBarrier() noexcept; - - //============================================================================== - #if JUCE_64BIT - JUCE_ALIGN (8) - #else - JUCE_ALIGN (4) - #endif - - /** The raw value that this class operates on. - This is exposed publicly in case you need to manipulate it directly - for performance reasons. - */ - volatile Type value; - - protected: - template - static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; } - - static inline Type castFrom32Bit (int32 value) noexcept { return castTo (value); } - static inline Type castFrom64Bit (int64 value) noexcept { return castTo (value); } - static inline int32 castTo32Bit (Type value) noexcept { return castTo (value); } - static inline int64 castTo64Bit (Type value) noexcept { return castTo (value); } - - Type operator++ (int); // better to just use pre-increment with atomics.. - Type operator-- (int); - - /** This templated negate function will negate pointers as well as integers */ - template - inline ValueType negateValue (ValueType n) noexcept - { - return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n - : (sizeof (ValueType) == 2 ? (ValueType) -(short) n - : (sizeof (ValueType) == 4 ? (ValueType) -(int) n - : ((ValueType) -(int64) n))); - } - - /** This templated negate function will negate pointers as well as integers */ - template - inline PointerType* negateValue (PointerType* n) noexcept - { - return reinterpret_cast (-reinterpret_cast (n)); - } - }; - - //============================================================================== - // Specialisation for void* which does not include the pointer arithmetic - template <> - class Atomic : public AtomicBase - { - public: - inline Atomic() noexcept {} - inline explicit Atomic (void* const initialValue) noexcept : AtomicBase (initialValue) {} - inline Atomic (const Atomic& other) noexcept : AtomicBase (other) {} - inline void* get() const noexcept { return AtomicBase::get(); } - inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase::operator= (other); return *this; } - inline Atomic& operator= (void* const newValue) noexcept { AtomicBase::operator= (newValue); return *this; } - inline void set (void* newValue) noexcept { exchange (newValue); } - inline void* exchange (void* v) noexcept { return AtomicBase::exchange (v); } - inline bool compareAndSetBool (void* newValue, void* valueToCompare) noexcept { return AtomicBase::compareAndSetBool (newValue, valueToCompare); } - inline void* compareAndSetValue (void* newValue, void* valueToCompare) noexcept { return AtomicBase::compareAndSetValue (newValue, valueToCompare); } - static inline void memoryBarrier() noexcept { AtomicBase::memoryBarrier(); } - }; - - //============================================================================== - /* - The following code is in the header so that the atomics can be inlined where possible... - */ - #if JUCE_MAC && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)) - #define JUCE_ATOMICS_MAC_LEGACY 1 // Older OSX builds using gcc4.1 or earlier - #elif JUCE_GCC || JUCE_CLANG - #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics - #if JUCE_IOS || JUCE_ANDROID // (64-bit ops will compile but not link on these mobile OSes) - #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 - #endif - #endif - - template - struct AtomicIncrementDecrement - { - static inline Type inc (AtomicBase& a) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((volatile int32_t*) &a.value) - : (Type) OSAtomicIncrement64Barrier ((volatile int64_t*) &a.value); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (& (a.value), (Type) 1) - : (Type) __sync_add_and_fetch ((int64_t*) & (a.value), 1); - #endif - } - - static inline Type dec (AtomicBase& a) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((volatile int32_t*) &a.value) - : (Type) OSAtomicDecrement64Barrier ((volatile int64_t*) &a.value); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (& (a.value), (Type) -1) - : (Type) __sync_add_and_fetch ((int64_t*) & (a.value), -1); - #endif - } - }; - - template - struct AtomicIncrementDecrement - { - static inline Type* inc (Atomic& a) noexcept { return a.operator+= (1); } - static inline Type* dec (Atomic& a) noexcept { return a.operator-= (1); } - }; - - //============================================================================== - template - inline Type AtomicBase::get() const noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (volatile int32_t*) &value)) - : castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (volatile int64_t*) &value)); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) - : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); - #endif - } - - template - inline Type AtomicBase::exchange (const Type newValue) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY || JUCE_ATOMICS_GCC - Type currentVal = value; - while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; } - return currentVal; - #endif - } - - template - inline Type Atomic::operator+= (const DiffType amountToAdd) noexcept - { - Type amount = (Type() + amountToAdd); - - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amount), (volatile int32_t*) &AtomicBase::value) - : (Type) OSAtomicAdd64Barrier ((int64_t) amount, (volatile int64_t*) &AtomicBase::value); - #elif JUCE_ATOMICS_GCC - return (Type) __sync_add_and_fetch (& (AtomicBase::value), amount); - #endif - } - - template - inline Type Atomic::operator-= (const DiffType amountToSubtract) noexcept - { - return operator+= (AtomicBase::negateValue (amountToSubtract)); - } - - template - inline Type Atomic::operator++() noexcept { return AtomicIncrementDecrement::inc (*this); } - - template - inline Type Atomic::operator--() noexcept { return AtomicIncrementDecrement::dec (*this); } - - template - inline bool AtomicBase::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (volatile int32_t*) &value) - : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (volatile int64_t*) &value); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) - : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); - #endif - } - - template - inline Type AtomicBase::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - for (;;) // Annoying workaround for only having a bool CAS operation.. - { - if (compareAndSetBool (newValue, valueToCompare)) - return valueToCompare; - - const Type result = value; - if (result != valueToCompare) - return result; - } - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) - : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); + //============================================================================== + // Internal implementation follows + //============================================================================== + template + class AtomicBase + { + public: + typedef typename AtomicHelpers::DiffTypeHelper::Type DiffType; + + inline AtomicBase() noexcept : value (0) {} + inline explicit AtomicBase (const Type v) noexcept : value (v) {} + inline AtomicBase (const AtomicBase& other) noexcept : value (other.get()) {} + Type get() const noexcept; + inline AtomicBase& operator= (const AtomicBase& other) noexcept { exchange (other.get()); return *this; } + inline AtomicBase& operator= (const Type newValue) noexcept { exchange (newValue); return *this; } + void set (Type newValue) noexcept { exchange (newValue); } + Type exchange (Type) noexcept; + bool compareAndSetBool (Type, Type) noexcept; + Type compareAndSetValue (Type, Type) noexcept; + static void memoryBarrier() noexcept; + + //============================================================================== + #if JUCE_64BIT + JUCE_ALIGN (8) + #else + JUCE_ALIGN (4) #endif - } - - template - inline void AtomicBase::memoryBarrier() noexcept - { - #if JUCE_ATOMICS_MAC_LEGACY - OSMemoryBarrier(); - #elif JUCE_ATOMICS_GCC - __sync_synchronize(); - #endif - } - #endif + /** The raw value that this class operates on. + This is exposed publicly in case you need to manipulate it directly + for performance reasons. + */ + volatile Type value; + + protected: + template + static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; } + + static inline Type castFrom32Bit (int32 value) noexcept { return castTo (value); } + static inline Type castFrom64Bit (int64 value) noexcept { return castTo (value); } + static inline int32 castTo32Bit (Type value) noexcept { return castTo (value); } + static inline int64 castTo64Bit (Type value) noexcept { return castTo (value); } + + Type operator++ (int); // better to just use pre-increment with atomics.. + Type operator-- (int); + + /** This templated negate function will negate pointers as well as integers */ + template + inline ValueType negateValue (ValueType n) noexcept + { + return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n + : (sizeof (ValueType) == 2 ? (ValueType) -(short) n + : (sizeof (ValueType) == 4 ? (ValueType) -(int) n + : ((ValueType) -(int64) n))); + } + + /** This templated negate function will negate pointers as well as integers */ + template + inline PointerType* negateValue (PointerType* n) noexcept + { + return reinterpret_cast (-reinterpret_cast (n)); + } + }; + + //============================================================================== + // Specialisation for void* which does not include the pointer arithmetic + template <> + class Atomic : public AtomicBase + { + public: + inline Atomic() noexcept {} + inline explicit Atomic (void* const initialValue) noexcept : AtomicBase (initialValue) {} + inline Atomic (const Atomic& other) noexcept : AtomicBase (other) {} + inline void* get() const noexcept { return AtomicBase::get(); } + inline Atomic& operator= (const Atomic& other) noexcept { AtomicBase::operator= (other); return *this; } + inline Atomic& operator= (void* const newValue) noexcept { AtomicBase::operator= (newValue); return *this; } + inline void set (void* newValue) noexcept { exchange (newValue); } + inline void* exchange (void* v) noexcept { return AtomicBase::exchange (v); } + inline bool compareAndSetBool (void* newValue, void* valueToCompare) noexcept { return AtomicBase::compareAndSetBool (newValue, valueToCompare); } + inline void* compareAndSetValue (void* newValue, void* valueToCompare) noexcept { return AtomicBase::compareAndSetValue (newValue, valueToCompare); } + static inline void memoryBarrier() noexcept { AtomicBase::memoryBarrier(); } + }; + + template + struct AtomicIncrementDecrement + { + static inline Type inc (AtomicBase& a) noexcept + { + return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (& (a.value), (Type) 1) + : (Type) __sync_add_and_fetch ((int64_t*) & (a.value), 1); + } + + static inline Type dec (AtomicBase& a) noexcept + { + return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (& (a.value), (Type) -1) + : (Type) __sync_add_and_fetch ((int64_t*) & (a.value), -1); + } + }; + + template + struct AtomicIncrementDecrement + { + static inline Type* inc (Atomic& a) noexcept { return a.operator+= (1); } + static inline Type* dec (Atomic& a) noexcept { return a.operator-= (1); } + }; + + //============================================================================== + template + inline Type AtomicBase::get() const noexcept + { + return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) + : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); + } + + template + inline Type AtomicBase::exchange (const Type newValue) noexcept + { + Type currentVal = value; + while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; } + return currentVal; + } + + template + inline Type Atomic::operator+= (const DiffType amountToAdd) noexcept + { + Type amount = (Type() + amountToAdd); + return (Type) __sync_add_and_fetch (& (AtomicBase::value), amount); + } + + template + inline Type Atomic::operator-= (const DiffType amountToSubtract) noexcept + { + return operator+= (AtomicBase::negateValue (amountToSubtract)); + } + + template + inline Type Atomic::operator++() noexcept { return AtomicIncrementDecrement::inc (*this); } + + template + inline Type Atomic::operator--() noexcept { return AtomicIncrementDecrement::dec (*this); } + + template + inline bool AtomicBase::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept + { + return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) + : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); + } + + template + inline Type AtomicBase::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept + { + return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) + : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); + } + + template + inline void AtomicBase::memoryBarrier() noexcept { __sync_synchronize(); } #endif