eathread_atomic_apple.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #if defined(EA_PRAGMA_ONCE_SUPPORTED)
  5. #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
  6. #endif
  7. /////////////////////////////////////////////////////////////////////////////
  8. // Defines functionality for threadsafe primitive operations.
  9. /////////////////////////////////////////////////////////////////////////////
  10. #ifndef EATHREAD_APPLE_EATHREAD_ATOMIC_APPLE_H
  11. #define EATHREAD_APPLE_EATHREAD_ATOMIC_APPLE_H
  12. #include <EABase/eabase.h>
  13. #include <stddef.h>
  14. #include <libkern/OSAtomic.h>
  15. #include "eathread/internal/atomic.h"
  16. #include "eathread/internal/eathread_atomic_standalone.h"
  17. #define EA_THREAD_ATOMIC_IMPLEMENTED
  18. namespace EA
  19. {
  20. namespace Thread
  21. {
  22. /// class AtomicInt
  23. /// Actual implementation may vary per platform. May require certain alignments, sizes,
  24. /// and declaration specifications per platform.
  25. template <class T>
  26. class AtomicInt
  27. {
  28. public:
  29. typedef AtomicInt<T> ThisType;
  30. typedef T ValueType;
  31. /// AtomicInt
  32. /// Empty constructor. Intentionally leaves mValue in an unspecified state.
  33. /// This is done so that an AtomicInt acts like a standard built-in integer.
  34. AtomicInt()
  35. { }
  36. AtomicInt(ValueType n)
  37. { SetValue(n); }
  38. AtomicInt(const ThisType& x)
  39. : mValue(x.GetValue()) { }
  40. AtomicInt& operator=(const ThisType& x)
  41. { mValue = x.GetValue(); return *this; }
  42. ValueType GetValue() const
  43. { return mValue; }
  44. ValueType GetValueRaw() const
  45. { return mValue; }
  46. ValueType SetValue(ValueType n);
  47. bool SetValueConditional(ValueType n, ValueType condition);
  48. ValueType Increment();
  49. ValueType Decrement();
  50. ValueType Add(ValueType n);
  51. // operators
  52. inline operator const ValueType() const { return GetValue(); }
  53. inline ValueType operator =(ValueType n) { SetValue(n); return n; }
  54. inline ValueType operator+=(ValueType n) { return Add(n);}
  55. inline ValueType operator-=(ValueType n) { return Add(-n);}
  56. inline ValueType operator++() { return Increment();}
  57. inline ValueType operator++(int) { return Increment() - 1;}
  58. inline ValueType operator--() { return Decrement(); }
  59. inline ValueType operator--(int) { return Decrement() + 1;}
  60. protected:
  61. volatile ValueType mValue;
  62. };
  63. template <>
  64. class AtomicInt<uint64_t>
  65. {
  66. public:
  67. typedef AtomicInt<uint64_t> ThisType;
  68. typedef uint64_t ValueType;
  69. /// AtomicInt
  70. /// Empty constructor. Intentionally leaves mValue in an unspecified state.
  71. /// This is done so that an AtomicInt acts like a standard built-in integer.
  72. AtomicInt()
  73. {}
  74. AtomicInt(ValueType n)
  75. { SetValue(n); }
  76. AtomicInt(const ThisType& x)
  77. : mValue(x.GetValue()) {}
  78. AtomicInt& operator=(const ThisType& x)
  79. { mValue = x.GetValue(); return *this; }
  80. ValueType GetValue() const
  81. { return (uint64_t)AtomicGetValue64((volatile int64_t *)&mValue); }
  82. ValueType GetValueRaw() const
  83. { return mValue; }
  84. ValueType SetValue(ValueType n)
  85. { return (uint64_t)AtomicSetValue64((volatile int64_t *)&mValue, n); }
  86. bool SetValueConditional(ValueType n, ValueType condition)
  87. { return AtomicSetValueConditional64((volatile int64_t *)&mValue, n, condition); }
  88. ValueType Increment()
  89. { return (uint64_t)AtomicAdd64((volatile int64_t *)&mValue, 1); }
  90. ValueType Decrement()
  91. { return (uint64_t)AtomicAdd64((volatile int64_t *)&mValue, -1); }
  92. ValueType Add(ValueType n)
  93. { return (uint64_t)AtomicAdd64((volatile int64_t *)&mValue, n); }
  94. // operators
  95. inline operator const ValueType() const { return GetValue(); }
  96. inline ValueType operator =(ValueType n) { SetValue(n); return n; }
  97. inline ValueType operator+=(ValueType n) { return Add(n);}
  98. inline ValueType operator-=(ValueType n) { return Add(-n);}
  99. inline ValueType operator++() { return Increment();}
  100. inline ValueType operator++(int) { return Increment() - 1;}
  101. inline ValueType operator--() { return Decrement(); }
  102. inline ValueType operator--(int) { return Decrement() + 1;}
  103. protected:
  104. volatile ValueType mValue;
  105. }__attribute__((aligned(8)));
  106. template <>
  107. class AtomicInt<int64_t>
  108. {
  109. public:
  110. typedef AtomicInt<int64_t> ThisType;
  111. typedef int64_t ValueType;
  112. /// AtomicInt
  113. /// Empty constructor. Intentionally leaves mValue in an unspecified state.
  114. /// This is done so that an AtomicInt acts like a standard built-in integer.
  115. AtomicInt()
  116. {}
  117. AtomicInt(ValueType n)
  118. { SetValue(n); }
  119. AtomicInt(const ThisType& x)
  120. : mValue(x.GetValue()) {}
  121. AtomicInt& operator=(const ThisType& x)
  122. { mValue = x.GetValue(); return *this; }
  123. ValueType GetValue() const
  124. { return AtomicGetValue64((volatile int64_t *)&mValue); }
  125. ValueType GetValueRaw() const
  126. { return mValue; }
  127. ValueType SetValue(ValueType n)
  128. { return AtomicSetValue64((volatile int64_t *)&mValue, n); }
  129. bool SetValueConditional(ValueType n, ValueType condition)
  130. { return AtomicSetValueConditional64((volatile int64_t *)&mValue, n, condition); }
  131. ValueType Increment()
  132. { return AtomicAdd64((volatile int64_t *)&mValue, 1); }
  133. ValueType Decrement()
  134. { return AtomicAdd64((volatile int64_t *)&mValue, -1); }
  135. ValueType Add(ValueType n)
  136. { return AtomicAdd64((volatile int64_t *)&mValue, n); }
  137. // operators
  138. inline operator const ValueType() const { return GetValue(); }
  139. inline ValueType operator =(ValueType n) { SetValue(n); return n; }
  140. inline ValueType operator+=(ValueType n) { return Add(n);}
  141. inline ValueType operator-=(ValueType n) { return Add(-n);}
  142. inline ValueType operator++() { return Increment();}
  143. inline ValueType operator++(int) { return Increment() - 1;}
  144. inline ValueType operator--() { return Decrement(); }
  145. inline ValueType operator--(int) { return Decrement() + 1;}
  146. protected:
  147. volatile ValueType mValue;
  148. }__attribute__((aligned(8)));
  149. template <> inline
  150. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::GetValue() const
  151. { return OSAtomicAdd32(0, reinterpret_cast<volatile int32_t*>(const_cast<ValueType*>(&mValue))); }
  152. template <> inline
  153. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::GetValue() const
  154. { return OSAtomicAdd32(0, reinterpret_cast<volatile int32_t*>(const_cast<ValueType*>(&mValue))); }
  155. template <> inline
  156. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::SetValue(ValueType n)
  157. {
  158. int32_t old;
  159. do
  160. {
  161. old = mValue;
  162. }
  163. while ( ! OSAtomicCompareAndSwap32(old, n, reinterpret_cast<volatile int32_t*>(&mValue)));
  164. return old;
  165. }
  166. template <> inline
  167. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::SetValue(ValueType n)
  168. {
  169. uint32_t old;
  170. do
  171. {
  172. old = mValue;
  173. } while ( ! OSAtomicCompareAndSwap32(old, n, reinterpret_cast<volatile int32_t*>(&mValue)));
  174. return old;
  175. }
  176. template <> inline
  177. bool AtomicInt<int32_t>::SetValueConditional(ValueType n, ValueType condition)
  178. { return OSAtomicCompareAndSwap32(condition, n, reinterpret_cast<volatile int32_t*>(&mValue)); }
  179. template <> inline
  180. bool AtomicInt<uint32_t>::SetValueConditional(ValueType n, ValueType condition)
  181. { return OSAtomicCompareAndSwap32(condition, n, reinterpret_cast<volatile int32_t*>(&mValue)); }
  182. template <> inline
  183. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Increment()
  184. { return OSAtomicIncrement32(reinterpret_cast<volatile int32_t*>(&mValue)); }
  185. template <> inline
  186. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Increment()
  187. { return OSAtomicIncrement32(reinterpret_cast<volatile int32_t*>(&mValue)); }
  188. template <> inline
  189. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Decrement()
  190. { return OSAtomicDecrement32(reinterpret_cast<volatile int32_t*>(&mValue)); }
  191. template <> inline
  192. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Decrement()
  193. { return OSAtomicDecrement32(reinterpret_cast<volatile int32_t*>(&mValue)); }
  194. template <> inline
  195. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Add(ValueType n)
  196. { return OSAtomicAdd32(n, reinterpret_cast<volatile int32_t*>(&mValue)); }
  197. template <> inline
  198. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Add(ValueType n)
  199. { return OSAtomicAdd32(n, reinterpret_cast<volatile int32_t*>(&mValue)); }
  200. }
  201. }
  202. #endif