eathread_atomic_android.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. #ifndef EATHREAD_GCC_EATHREAD_ATOMIC_ANDROID_H
  8. #define EATHREAD_GCC_EATHREAD_ATOMIC_ANDROID_H
  9. #include <EABase/eabase.h>
  10. #include <stddef.h>
  11. #include <sys/atomics.h>
  12. #include <eathread/internal/eathread_atomic_standalone.h>
  13. #define EA_THREAD_ATOMIC_IMPLEMENTED
  14. namespace EA
  15. {
  16. namespace Thread
  17. {
  18. /// android_fake_atomics_*
  19. ///
  20. int64_t android_fake_atomic_swap_64(int64_t value, volatile int64_t* addr);
  21. int android_fake_atomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue, volatile int64_t* addr);
  22. int64_t android_fake_atomic_read_64(volatile int64_t* addr);
  23. /// class AtomicInt
  24. /// Actual implementation may vary per platform. May require certain alignments, sizes,
  25. /// and declaration specifications per platform.
  26. template <class T>
  27. class AtomicInt
  28. {
  29. public:
  30. typedef AtomicInt<T> ThisType;
  31. typedef T ValueType;
  32. /// AtomicInt
  33. /// Empty constructor. Intentionally leaves mValue in an unspecified state.
  34. /// This is done so that an AtomicInt acts like a standard built-in integer.
  35. AtomicInt()
  36. {}
  37. AtomicInt(ValueType n)
  38. { SetValue(n); }
  39. AtomicInt(const ThisType& x)
  40. : mValue(x.GetValue()) {}
  41. AtomicInt& operator=(const ThisType& x)
  42. { mValue = x.GetValue(); return *this; }
  43. ValueType GetValue() const
  44. { return mValue; }
  45. ValueType GetValueRaw() const
  46. { return mValue; }
  47. ValueType SetValue(ValueType n);
  48. bool SetValueConditional(ValueType n, ValueType condition);
  49. ValueType Increment();
  50. ValueType Decrement();
  51. ValueType Add(ValueType n);
  52. // operators
  53. inline operator const ValueType() const { return GetValue(); }
  54. inline ValueType operator =(ValueType n) { SetValue(n); return n; }
  55. inline ValueType operator+=(ValueType n) { return Add(n);}
  56. inline ValueType operator-=(ValueType n) { return Add(-n);}
  57. inline ValueType operator++() { return Increment();}
  58. inline ValueType operator++(int) { return Increment() - 1;}
  59. inline ValueType operator--() { return Decrement(); }
  60. inline ValueType operator--(int) { return Decrement() + 1;}
  61. protected:
  62. volatile ValueType mValue;
  63. };
  64. template <> inline
  65. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::SetValue(ValueType n)
  66. { return __atomic_swap(n, &mValue); }
  67. template <> inline
  68. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::SetValue(ValueType n)
  69. { return __atomic_swap(n, (volatile int*)&mValue); }
  70. template <> inline
  71. bool AtomicInt<int32_t>::SetValueConditional(ValueType n, ValueType condition)
  72. { return (__atomic_cmpxchg(condition, n, &mValue) == 0); }
  73. template <> inline
  74. bool AtomicInt<uint32_t>::SetValueConditional(ValueType n, ValueType condition)
  75. { return (__atomic_cmpxchg(condition, n, (volatile int*)&mValue) == 0); }
  76. template <> inline
  77. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Increment()
  78. { return __atomic_inc(&mValue) + 1; }
  79. template <> inline
  80. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Increment()
  81. { return __atomic_inc((volatile int*)&mValue) + 1; }
  82. template <> inline
  83. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Decrement()
  84. { return __atomic_dec(&mValue) - 1; }
  85. template <> inline
  86. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Decrement()
  87. { return __atomic_dec((volatile int*)&mValue) - 1; }
  88. template <> inline
  89. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Add(ValueType n)
  90. {
  91. // http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Atomic-Builtins.html
  92. return __sync_add_and_fetch(&mValue, n);
  93. }
  94. template <> inline
  95. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Add(ValueType n)
  96. {
  97. // http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Atomic-Builtins.html
  98. return __sync_add_and_fetch(&mValue, n);
  99. }
  100. ///////////////////////////////////////////////////////////
  101. /// 64 bit, simulated
  102. ///
  103. template <> inline
  104. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::GetValue() const
  105. { return android_fake_atomic_read_64((volatile int64_t*)&mValue); }
  106. template <> inline
  107. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::GetValue() const
  108. { return android_fake_atomic_read_64((volatile int64_t*)&mValue); }
  109. template <> inline
  110. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::SetValue(ValueType n)
  111. {
  112. const ValueType nOldValue(mValue);
  113. android_fake_atomic_swap_64((int64_t)n, (volatile int64_t*)&mValue);
  114. return nOldValue;
  115. }
  116. template <> inline
  117. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::SetValue(ValueType n)
  118. {
  119. const ValueType nOldValue(mValue);
  120. android_fake_atomic_swap_64((int64_t)n, (volatile int64_t*)&mValue);
  121. return nOldValue;
  122. }
  123. template <> inline
  124. bool AtomicInt<int64_t>::SetValueConditional(ValueType n, ValueType condition)
  125. {
  126. return android_fake_atomic_cmpxchg_64(condition, n, (volatile int64_t*)&mValue) == 0;
  127. }
  128. template <> inline
  129. bool AtomicInt<uint64_t>::SetValueConditional(ValueType n, ValueType condition)
  130. {
  131. return android_fake_atomic_cmpxchg_64(condition, n, (volatile int64_t*)&mValue) == 0;
  132. }
  133. template <> inline
  134. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Add(ValueType n)
  135. {
  136. int64_t old;
  137. do {
  138. old = mValue;
  139. }
  140. while (android_fake_atomic_cmpxchg_64((int64_t)old, (int64_t)old+n, (volatile int64_t*)&mValue) != 0);
  141. return mValue;
  142. }
  143. template <> inline
  144. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Add(ValueType n)
  145. {
  146. uint64_t old;
  147. do {
  148. old = mValue;
  149. }
  150. while (android_fake_atomic_cmpxchg_64((int64_t)old, (int64_t)old+n, (volatile int64_t*)&mValue) != 0);
  151. return mValue;
  152. }
  153. template <> inline
  154. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Increment()
  155. { return Add(1); }
  156. template <> inline
  157. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Increment()
  158. { return Add(1); }
  159. template <> inline
  160. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Decrement()
  161. { return Add(-1); }
  162. template <> inline
  163. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Decrement()
  164. { return Add(-1); }
  165. } // namespace Thread
  166. } // namespace EA
  167. #endif // EATHREAD_GCC_EATHREAD_ATOMIC_ANDROID_H