eathread_atomic_android_c11.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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_ATOMIC_ANDROID_C11_H
  8. #define EATHREAD_ATOMIC_ANDROID_C11_H
  9. #include <EABase/eabase.h>
  10. #include <stddef.h>
  11. #include <stdatomic.h>
  12. #include <eathread/internal/eathread_atomic_standalone.h>
  13. #define EA_THREAD_ATOMIC_IMPLEMENTED
  14. namespace EA
  15. {
  16. namespace Thread
  17. {
  18. /// class AtomicInt
  19. /// Actual implementation may vary per platform. May require certain alignments, sizes,
  20. /// and declaration specifications per platform.
  21. template <class T>
  22. class AtomicInt
  23. {
  24. public:
  25. typedef AtomicInt<T> ThisType;
  26. typedef T ValueType;
  27. typedef _Atomic(T) AtomicValueType;
  28. /// AtomicInt
  29. /// Empty constructor. Intentionally leaves mValue in an unspecified state.
  30. /// This is done so that an AtomicInt acts like a standard built-in integer.
  31. AtomicInt()
  32. {}
  33. AtomicInt(ValueType n)
  34. { SetValue(n); }
  35. AtomicInt(const ThisType& x)
  36. { SetValue(x.GetValue()); }
  37. AtomicInt& operator=(const ThisType& x)
  38. { SetValue(x.GetValue()); return *this; }
  39. ValueType GetValue() const
  40. { return atomic_load_explicit(const_cast<AtomicValueType*>(&mValue), memory_order_relaxed); }
  41. ValueType GetValueRaw() const
  42. { return atomic_load_explicit(const_cast<AtomicValueType*>(&mValue), memory_order_relaxed); }
  43. ValueType SetValue(ValueType n);
  44. bool SetValueConditional(ValueType n, ValueType condition);
  45. ValueType Increment();
  46. ValueType Decrement();
  47. ValueType Add(ValueType n);
  48. // operators
  49. inline operator const ValueType() const { return GetValue(); }
  50. inline ValueType operator =(ValueType n) { SetValue(n); return n; }
  51. inline ValueType operator+=(ValueType n) { return Add(n);}
  52. inline ValueType operator-=(ValueType n) { return Add(-n);}
  53. inline ValueType operator++() { return Increment();}
  54. inline ValueType operator++(int) { return Increment() - 1;}
  55. inline ValueType operator--() { return Decrement(); }
  56. inline ValueType operator--(int) { return Decrement() + 1;}
  57. protected:
  58. AtomicValueType mValue;
  59. };
  60. ///////////////////////////////////////////////////////////
  61. /// 32 bit
  62. ///
  63. template <> inline
  64. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::SetValue(ValueType n)
  65. { return atomic_exchange_explicit(&mValue, n, memory_order_relaxed); }
  66. template <> inline
  67. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::SetValue(ValueType n)
  68. { return atomic_exchange_explicit(&mValue, n, memory_order_relaxed); }
  69. template <> inline
  70. bool AtomicInt<int32_t>::SetValueConditional(ValueType n, ValueType condition)
  71. { return atomic_compare_exchange_strong_explicit(&mValue, &condition, n, memory_order_relaxed, memory_order_relaxed); }
  72. template <> inline
  73. bool AtomicInt<uint32_t>::SetValueConditional(ValueType n, ValueType condition)
  74. { return atomic_compare_exchange_strong_explicit(&mValue, &condition, n, memory_order_relaxed, memory_order_relaxed); }
  75. template <> inline
  76. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Increment()
  77. { return atomic_fetch_add_explicit(&mValue, 1, memory_order_relaxed) + 1; }
  78. template <> inline
  79. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Increment()
  80. { return atomic_fetch_add_explicit(&mValue, 1u, memory_order_relaxed) + 1u; }
  81. template <> inline
  82. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Decrement()
  83. { return atomic_fetch_sub_explicit(&mValue, 1, memory_order_relaxed) - 1; }
  84. template <> inline
  85. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Decrement()
  86. { return atomic_fetch_sub_explicit(&mValue, 1u, memory_order_relaxed) - 1u; }
  87. template <> inline
  88. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Add(ValueType n)
  89. { return atomic_fetch_add_explicit(&mValue, n, memory_order_relaxed) + n; }
  90. template <> inline
  91. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Add(ValueType n)
  92. { return atomic_fetch_add_explicit(&mValue, n, memory_order_relaxed) + n; }
  93. ///////////////////////////////////////////////////////////
  94. /// 64 bit
  95. ///
  96. template <> inline
  97. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::GetValue() const
  98. { return atomic_load_explicit(const_cast<AtomicValueType*>(&mValue), memory_order_relaxed); }
  99. template <> inline
  100. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::GetValue() const
  101. { return atomic_load_explicit(const_cast<AtomicValueType*>(&mValue), memory_order_relaxed); }
  102. template <> inline
  103. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::SetValue(ValueType n)
  104. { return atomic_exchange_explicit(&mValue, n, memory_order_relaxed); }
  105. template <> inline
  106. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::SetValue(ValueType n)
  107. { return atomic_exchange_explicit(&mValue, n, memory_order_relaxed); }
  108. template <> inline
  109. bool AtomicInt<int64_t>::SetValueConditional(ValueType n, ValueType condition)
  110. { return atomic_compare_exchange_strong_explicit(&mValue, &condition, n, memory_order_relaxed, memory_order_relaxed); }
  111. template <> inline
  112. bool AtomicInt<uint64_t>::SetValueConditional(ValueType n, ValueType condition)
  113. { return atomic_compare_exchange_strong_explicit(&mValue, &condition, n, memory_order_relaxed, memory_order_relaxed); }
  114. template <> inline
  115. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Add(ValueType n)
  116. { return atomic_fetch_add_explicit(&mValue, n, memory_order_relaxed) + n; }
  117. template <> inline
  118. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Add(ValueType n)
  119. { return atomic_fetch_add_explicit(&mValue, n, memory_order_relaxed) + n; }
  120. template <> inline
  121. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Increment()
  122. { return Add(1); }
  123. template <> inline
  124. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Increment()
  125. { return Add(1); }
  126. template <> inline
  127. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Decrement()
  128. { return Add(-1); }
  129. template <> inline
  130. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Decrement()
  131. { return Add(-1); }
  132. } // namespace Thread
  133. } // namespace EA
  134. ////////////////////////////////////////////////////////////////////////////////
  135. // Use of the C11 atomics API on Android is problematic because the platform
  136. // implements the atomics API via macro wrappers around their platform specific
  137. // functions. Unfortunately, macros affect header files outside of its
  138. // scoped namespace and will be applied to areas of the code in undesirable
  139. // ways. One instance of this is the C11 atomics colliding with the atomic
  140. // functions of C++11 std::shared_ptr.
  141. //
  142. // We attempt to prevent external impact of the stdatomics.h by undefining the
  143. // relevant functions.
  144. //
  145. // Note: If you #include <stdatomic.h> above an eathread header it will undefined macros.
  146. //
  147. // http://en.cppreference.com/w/cpp/memory/shared_ptr
  148. //
  149. // std::atomic_compare_exchange_strong(std::shared_ptr)
  150. // std::atomic_compare_exchange_strong_explicit(std::shared_ptr)
  151. // std::atomic_compare_exchange_weak(std::shared_ptr)
  152. // std::atomic_compare_exchange_weak_explicit(std::shared_ptr)
  153. // std::atomic_exchange(std::shared_ptr)
  154. // std::atomic_exchange_explicit(std::shared_ptr)
  155. // std::atomic_is_lock_free(std::shared_ptr)
  156. // std::atomic_load(std::shared_ptr)
  157. // std::atomic_load_explicit(std::shared_ptr)
  158. // std::atomic_store(std::shared_ptr)
  159. // std::atomic_store_explicit(std::shared_ptr)
  160. //
  161. #undef atomic_compare_exchange_strong
  162. #undef atomic_compare_exchange_strong_explicit
  163. #undef atomic_compare_exchange_weak
  164. #undef atomic_compare_exchange_weak_explicit
  165. #undef atomic_exchange
  166. #undef atomic_exchange_explicit
  167. #undef atomic_is_lock_free
  168. #undef atomic_load
  169. #undef atomic_load_explicit
  170. #undef atomic_store
  171. #undef atomic_store_explicit
  172. #endif // EATHREAD_ATOMIC_ANDROID_C11_H