The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

328 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCE_ATOMIC_JUCEHEADER__
  19. #define __JUCE_ATOMIC_JUCEHEADER__
  20. //==============================================================================
  21. /**
  22. Simple class to hold a primitive value and perform atomic operations on it.
  23. The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
  24. There are methods to perform most of the basic atomic operations.
  25. */
  26. template <typename Type>
  27. class Atomic
  28. {
  29. public:
  30. /** Creates a new value, initialised to zero. */
  31. inline Atomic() throw()
  32. : value (0)
  33. {
  34. }
  35. /** Creates a new value, with a given initial value. */
  36. inline Atomic (const Type initialValue) throw()
  37. : value (initialValue)
  38. {
  39. }
  40. /** Copies another value (atomically). */
  41. inline Atomic (const Atomic& other) throw()
  42. : value (other.get())
  43. {
  44. }
  45. /** Copies another value onto this one (atomically). */
  46. inline Atomic& operator= (const Atomic& other) throw()
  47. {
  48. set (other.get());
  49. }
  50. /** Destructor. */
  51. inline ~Atomic() throw()
  52. {
  53. // This class can only be used for types which are 32 or 64 bits in size.
  54. static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8);
  55. }
  56. /** Atomically reads and returns the current value. */
  57. Type get() const throw();
  58. /** Atomically sets the current value. */
  59. void set (Type newValue) throw();
  60. /** Atomically sets the current value, returning the value that was replaced. */
  61. Type exchange (Type value) throw();
  62. /** Atomically adds a number to this value, returning the new value. */
  63. Type operator+= (Type amountToAdd) throw();
  64. /** Atomically subtracts a number from this value, returning the new value. */
  65. Type operator-= (Type amountToSubtract) throw();
  66. /** Atomically increments this value, returning the new value. */
  67. Type operator++() throw();
  68. /** Atomically decrements this value, returning the new value. */
  69. Type operator--() throw();
  70. /** Atomically compares this value with a target value, and if it is equal, sets
  71. this to be equal to a new value.
  72. This operation is the atomic equivalent of doing this:
  73. @code
  74. bool compareAndSetBool (Type newValue, Type valueToCompare) throw();
  75. {
  76. if (get() == valueToCompare)
  77. {
  78. set (newValue);
  79. return true;
  80. }
  81. return false;
  82. }
  83. @endcode
  84. @returns true if the comparison was true and the value was replaced; false if
  85. the comparison failed and the value was left unchanged.
  86. @see compareAndSetValue
  87. */
  88. bool compareAndSetBool (Type newValue, Type valueToCompare) throw();
  89. /** Atomically compares this value with a target value, and if it is equal, sets
  90. this to be equal to a new value.
  91. This operation is the atomic equivalent of doing this:
  92. @code
  93. Type compareAndSetValue (Type newValue, Type valueToCompare) throw();
  94. {
  95. Type oldValue = get();
  96. if (oldValue == valueToCompare)
  97. set (newValue);
  98. return oldValue;
  99. }
  100. @endcode
  101. @returns the old value before it was changed.
  102. @see compareAndSetBool
  103. */
  104. Type compareAndSetValue (Type newValue, Type valueToCompare) throw();
  105. /** Performs a memory write barrier. */
  106. static void memoryBarrier() throw();
  107. //==============================================================================
  108. #if JUCE_MSVC
  109. __declspec (align (8))
  110. #else
  111. __attribute__ ((aligned (8)))
  112. #endif
  113. /** The raw value that this class operates on.
  114. This is exposed publically in case you need to manipulate it directly
  115. for performance reasons.
  116. */
  117. Type value;
  118. };
  119. //==============================================================================
  120. /*
  121. The following code allows the atomics to be performed as inline functions where possible...
  122. */
  123. #if (JUCE_IPHONE && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2 || ! defined (__IPHONE_3_2))) \
  124. || (JUCE_MAC && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)))
  125. #define JUCE_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier
  126. //==============================================================================
  127. #elif JUCE_GCC
  128. #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics
  129. //==============================================================================
  130. #else
  131. #define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics
  132. #if JUCE_USE_INTRINSICS
  133. #pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
  134. _InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
  135. #define juce_InterlockedExchange(a, b) _InterlockedExchange(a, b)
  136. #define juce_InterlockedIncrement(a) _InterlockedIncrement(a)
  137. #define juce_InterlockedDecrement(a) _InterlockedDecrement(a)
  138. #define juce_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
  139. #define juce_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
  140. #define juce_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
  141. #define juce_MemoryBarrier MemoryBarrier
  142. #else
  143. // (these are defined in juce_win32_Threads.cpp)
  144. long juce_InterlockedExchange (volatile long* a, long b) throw();
  145. long juce_InterlockedIncrement (volatile long* a) throw();
  146. long juce_InterlockedDecrement (volatile long* a) throw();
  147. long juce_InterlockedExchangeAdd (volatile long* a, long b) throw();
  148. long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw();
  149. __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) throw();
  150. static void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); }
  151. #endif
  152. #if JUCE_64BIT
  153. #pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
  154. #define juce_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
  155. #define juce_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
  156. #define juce_InterlockedIncrement64(a) _InterlockedIncrement64(a)
  157. #define juce_InterlockedDecrement64(a) _InterlockedDecrement64(a)
  158. #else
  159. // None of these atomics are available in a 32-bit Windows build!!
  160. static __int64 juce_InterlockedExchangeAdd64 (volatile __int64* a, __int64 b) throw() { jassertfalse; __int64 old = *a; *a += b; return old; }
  161. static __int64 juce_InterlockedExchange64 (volatile __int64* a, __int64 b) throw() { jassertfalse; __int64 old = *a; *a = b; return old; }
  162. static __int64 juce_InterlockedIncrement64 (volatile __int64* a) throw() { jassertfalse; return ++*a; }
  163. static __int64 juce_InterlockedDecrement64 (volatile __int64* a) throw() { jassertfalse; return --*a; }
  164. #endif
  165. #endif
  166. //==============================================================================
  167. template <typename Type>
  168. inline Type Atomic<Type>::get() const throw()
  169. {
  170. return const_cast <Atomic<Type>*> (this)->operator+= (0);
  171. }
  172. template <typename Type>
  173. inline void Atomic<Type>::set (const Type newValue) throw()
  174. {
  175. exchange (newValue);
  176. }
  177. template <typename Type>
  178. Type Atomic<Type>::exchange (const Type newValue) throw()
  179. {
  180. #if JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC
  181. Type currentVal = value;
  182. while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
  183. return currentVal;
  184. #elif JUCE_ATOMICS_WINDOWS
  185. return sizeof (Type) == 4 ? (Type) juce_InterlockedExchange ((volatile long*) &value, (long) newValue)
  186. : (Type) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) newValue);
  187. #endif
  188. }
  189. template <typename Type>
  190. inline Type Atomic<Type>::operator+= (const Type amountToAdd) throw()
  191. {
  192. #if JUCE_ATOMICS_MAC
  193. return sizeof (Type) == 4 ? (Type) OSAtomicAdd32 ((int32_t) amountToAdd, (int32_t*) &value)
  194. : (Type) OSAtomicAdd64 ((int64_t) amountToAdd, (int64_t*) &value);
  195. #elif JUCE_ATOMICS_WINDOWS
  196. return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
  197. : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
  198. #elif JUCE_ATOMICS_GCC
  199. return (Type) __sync_add_and_fetch (&value, amountToAdd);
  200. #endif
  201. }
  202. template <typename Type>
  203. inline Type Atomic<Type>::operator-= (const Type amountToSubtract) throw()
  204. {
  205. return operator+= (sizeof (Type) == 4 ? (Type) (-(int32) amountToSubtract)
  206. : (Type) (-(int64) amountToSubtract));
  207. }
  208. template <typename Type>
  209. inline Type Atomic<Type>::operator++() throw()
  210. {
  211. #if JUCE_ATOMICS_MAC
  212. return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32 ((int32_t*) &value)
  213. : (Type) OSAtomicIncrement64 ((int64_t*) &value);
  214. #elif JUCE_ATOMICS_WINDOWS
  215. return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value)
  216. : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value);
  217. #elif JUCE_ATOMICS_GCC
  218. return (Type) __sync_add_and_fetch (&value, 1);
  219. #endif
  220. }
  221. template <typename Type>
  222. inline Type Atomic<Type>::operator--() throw()
  223. {
  224. #if JUCE_ATOMICS_MAC
  225. return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32 ((int32_t*) &value)
  226. : (Type) OSAtomicDecrement64 ((int64_t*) &value);
  227. #elif JUCE_ATOMICS_WINDOWS
  228. return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value)
  229. : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value);
  230. #elif JUCE_ATOMICS_GCC
  231. return (Type) __sync_add_and_fetch (&value, -1);
  232. #endif
  233. }
  234. template <typename Type>
  235. inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) throw()
  236. {
  237. #if JUCE_ATOMICS_MAC
  238. return sizeof (Type) == 4 ? (Type) OSAtomicCompareAndSwap32Barrier ((int32_t) valueToCompare, (int32_t) newValue, (int32_t*) &value)
  239. : (Type) OSAtomicCompareAndSwap64Barrier ((int64_t) valueToCompare, (int64_t) newValue, (int64_t*) &value);
  240. #elif JUCE_ATOMICS_WINDOWS
  241. return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
  242. #elif JUCE_ATOMICS_GCC
  243. return __sync_bool_compare_and_swap (&value, valueToCompare, newValue);
  244. #endif
  245. }
  246. template <typename Type>
  247. inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) throw()
  248. {
  249. #if JUCE_ATOMICS_MAC
  250. for (;;) // Annoying workaround for OSX only having a bool CAS operation..
  251. {
  252. if (compareAndSetBool (newValue, valueToCompare))
  253. return valueToCompare;
  254. const Type result = value;
  255. if (result != valueToCompare)
  256. return result;
  257. }
  258. #elif JUCE_ATOMICS_WINDOWS
  259. return sizeof (Type) == 4 ? (Type) juce_InterlockedCompareExchange ((volatile long*) &value, (long) newValue, (long) valueToCompare)
  260. : (Type) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) newValue, (__int64) valueToCompare);
  261. #elif JUCE_ATOMICS_GCC
  262. return __sync_val_compare_and_swap (&value, valueToCompare, newValue);
  263. #endif
  264. }
  265. template <typename Type>
  266. inline void Atomic<Type>::memoryBarrier() throw()
  267. {
  268. #if JUCE_ATOMICS_MAC
  269. OSMemoryBarrier();
  270. #elif JUCE_ATOMICS_GCC
  271. __sync_synchronize();
  272. #elif JUCE_ATOMICS_WINDOWS
  273. juce_MemoryBarrier();
  274. #endif
  275. }
  276. #endif // __JUCE_ATOMIC_JUCEHEADER__