From 2415dd0d8557db7fddbb84f18b6965f309801e30 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Sat, 17 Apr 2010 17:01:16 +0100 Subject: [PATCH] Fix for mac compareAndSwap(). --- juce_amalgamated.h | 49 ++++++++++++++++++++++++++++-------------- src/core/juce_Atomic.h | 49 ++++++++++++++++++++++++++++-------------- 2 files changed, 66 insertions(+), 32 deletions(-) diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 7d2bf5fefa..be019e0c8c 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -3135,14 +3135,43 @@ private: Atomic& operator= (const Atomic&); }; -#if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone... +// If we've got gcc4.2 or later, we can use its atomic intrinsics... +#if JUCE_GCC && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) + + inline void Atomic::increment (int32& variable) { __sync_add_and_fetch (&variable, 1); } + inline int32 Atomic::incrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, 1); } + inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&variable, -1); } + inline int32 Atomic::decrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, -1); } + inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return __sync_val_compare_and_swap (&destination, oldValue, newValue); } + + inline void* Atomic::swapPointers (void* volatile* value1, void* value2) + { + void* currentVal = *value1; + while (! __sync_bool_compare_and_swap (value1, currentVal, value2)) { currentVal = *value1; } + return currentVal; + } + +#elif (JUCE_MAC || JUCE_IPHONE) // Older Mac builds using gcc4.0 or earlier... inline void Atomic::increment (int32& variable) { OSAtomicIncrement32 (static_cast (&variable)); } inline int32 Atomic::incrementAndReturn (int32& variable) { return OSAtomicIncrement32 (static_cast (&variable)); } inline void Atomic::decrement (int32& variable) { OSAtomicDecrement32 (static_cast (&variable)); } inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 (static_cast (&variable)); } + inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) - { return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, static_cast (&destination)); } + { + for (;;) // Annoying workaround for OSX only having a bool CAS operation.. + { + if (OSAtomicCompareAndSwap32Barrier (oldValue, newValue, static_cast (&destination))) + return oldValue; + + const uint32 result = destination; + if (result != oldValue) + return result; + } + } + inline void* Atomic::swapPointers (void* volatile* value1, void* value2) { void* currentVal = *value1; @@ -3155,7 +3184,7 @@ private: return currentVal; } -#elif JUCE_LINUX // Linux... +#elif JUCE_LINUX // Linux with compilers other than gcc4.2 or later... #if __INTEL_COMPILER inline void Atomic::increment (int32& variable) { _InterlockedIncrement (&variable); } @@ -3175,19 +3204,7 @@ private: } #else - inline void Atomic::increment (int32& variable) { __sync_add_and_fetch (&variable, 1); } - inline int32 Atomic::incrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, 1); } - inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&variable, -1); } - inline int32 Atomic::decrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, -1); } - inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) - { return __sync_val_compare_and_swap (&destination, oldValue, newValue); } - - inline void* Atomic::swapPointers (void* volatile* value1, void* value2) - { - void* currentVal = *value1; - while (! __sync_bool_compare_and_swap (value1, currentVal, value2)) { currentVal = *value1; } - return currentVal; - } + #error "Linux build requires gcc4.2 or later for atomic operations" #endif #elif JUCE_USE_INTRINSICS // Windows... diff --git a/src/core/juce_Atomic.h b/src/core/juce_Atomic.h index 1ddd81eb7d..dc02de3a5a 100644 --- a/src/core/juce_Atomic.h +++ b/src/core/juce_Atomic.h @@ -62,14 +62,43 @@ private: //============================================================================== -#if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone... +// If we've got gcc4.2 or later, we can use its atomic intrinsics... +#if JUCE_GCC && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) + + inline void Atomic::increment (int32& variable) { __sync_add_and_fetch (&variable, 1); } + inline int32 Atomic::incrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, 1); } + inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&variable, -1); } + inline int32 Atomic::decrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, -1); } + inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return __sync_val_compare_and_swap (&destination, oldValue, newValue); } + + inline void* Atomic::swapPointers (void* volatile* value1, void* value2) + { + void* currentVal = *value1; + while (! __sync_bool_compare_and_swap (value1, currentVal, value2)) { currentVal = *value1; } + return currentVal; + } + +#elif (JUCE_MAC || JUCE_IPHONE) // Older Mac builds using gcc4.0 or earlier... inline void Atomic::increment (int32& variable) { OSAtomicIncrement32 (static_cast (&variable)); } inline int32 Atomic::incrementAndReturn (int32& variable) { return OSAtomicIncrement32 (static_cast (&variable)); } inline void Atomic::decrement (int32& variable) { OSAtomicDecrement32 (static_cast (&variable)); } inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 (static_cast (&variable)); } + inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) - { return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, static_cast (&destination)); } + { + for (;;) // Annoying workaround for OSX only having a bool CAS operation.. + { + if (OSAtomicCompareAndSwap32Barrier (oldValue, newValue, static_cast (&destination))) + return oldValue; + + const uint32 result = destination; + if (result != oldValue) + return result; + } + } + inline void* Atomic::swapPointers (void* volatile* value1, void* value2) { void* currentVal = *value1; @@ -83,7 +112,7 @@ private: } //============================================================================== -#elif JUCE_LINUX // Linux... +#elif JUCE_LINUX // Linux with compilers other than gcc4.2 or later... #if __INTEL_COMPILER inline void Atomic::increment (int32& variable) { _InterlockedIncrement (&variable); } @@ -103,19 +132,7 @@ private: } #else - inline void Atomic::increment (int32& variable) { __sync_add_and_fetch (&variable, 1); } - inline int32 Atomic::incrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, 1); } - inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&variable, -1); } - inline int32 Atomic::decrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, -1); } - inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) - { return __sync_val_compare_and_swap (&destination, oldValue, newValue); } - - inline void* Atomic::swapPointers (void* volatile* value1, void* value2) - { - void* currentVal = *value1; - while (! __sync_bool_compare_and_swap (value1, currentVal, value2)) { currentVal = *value1; } - return currentVal; - } + #error "Linux build requires gcc4.2 or later for atomic operations" #endif //==============================================================================