eathread_atomic_gcc.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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_GCC_H
  8. #define EATHREAD_GCC_EATHREAD_ATOMIC_GCC_H
  9. #include <EABase/eabase.h>
  10. #include <stddef.h>
  11. #include <eathread/internal/eathread_atomic_standalone.h>
  12. #define EA_THREAD_ATOMIC_IMPLEMENTED
  13. namespace EA
  14. {
  15. namespace Thread
  16. {
  17. /// class AtomicInt
  18. /// Actual implementation may vary per platform. May require certain alignments, sizes,
  19. /// and declaration specifications per platform.
  20. template <class T>
  21. class AtomicInt
  22. {
  23. public:
  24. typedef AtomicInt<T> ThisType;
  25. typedef T ValueType;
  26. /// AtomicInt
  27. /// Empty constructor. Intentionally leaves mValue in an unspecified state.
  28. /// This is done so that an AtomicInt acts like a standard built-in integer.
  29. AtomicInt()
  30. {}
  31. AtomicInt(ValueType n)
  32. { SetValue(n); }
  33. AtomicInt(const ThisType& x)
  34. : mValue(x.GetValue()) {}
  35. AtomicInt& operator=(const ThisType& x)
  36. { mValue = x.GetValue(); return *this; }
  37. ValueType GetValue() const
  38. { return mValue; }
  39. ValueType GetValueRaw() const
  40. { return mValue; }
  41. ValueType SetValue(ValueType n);
  42. bool SetValueConditional(ValueType n, ValueType condition);
  43. ValueType Increment();
  44. ValueType Decrement();
  45. ValueType Add(ValueType n);
  46. // operators
  47. inline operator const ValueType() const { return GetValue(); }
  48. inline ValueType operator =(ValueType n) { SetValue(n); return n; }
  49. inline ValueType operator+=(ValueType n) { return Add(n);}
  50. inline ValueType operator-=(ValueType n) { return Add(-n);}
  51. inline ValueType operator++() { return Increment();}
  52. inline ValueType operator++(int) { return Increment() - 1;}
  53. inline ValueType operator--() { return Decrement(); }
  54. inline ValueType operator--(int) { return Decrement() + 1;}
  55. protected:
  56. volatile ValueType mValue;
  57. };
  58. // Recent versions of GCC have atomic primitives built into the compiler and standard library.
  59. #if defined(EA_COMPILER_CLANG) || defined(__APPLE__) || (defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 403)) || defined(EA_COMPILER_RVCT) // GCC 4.3 or later. Depends on the GCC implementation.
  60. template <> inline
  61. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::GetValue() const
  62. { return __sync_add_and_fetch(const_cast<ValueType*>(&mValue), 0); }
  63. template <> inline
  64. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::GetValue() const
  65. { return __sync_add_and_fetch(const_cast<ValueType*>(&mValue), 0); }
  66. template <> inline
  67. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::SetValue(ValueType n)
  68. { __sync_synchronize(); return __sync_lock_test_and_set(&mValue, n); }
  69. template <> inline
  70. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::SetValue(ValueType n)
  71. { __sync_synchronize(); return __sync_lock_test_and_set(&mValue, n); }
  72. template <> inline
  73. bool AtomicInt<int32_t>::SetValueConditional(ValueType n, ValueType condition)
  74. { return (__sync_val_compare_and_swap(&mValue, condition, n) == condition); }
  75. template <> inline
  76. bool AtomicInt<uint32_t>::SetValueConditional(ValueType n, ValueType condition)
  77. { return (__sync_val_compare_and_swap(&mValue, condition, n) == condition); }
  78. template <> inline
  79. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Increment()
  80. { return __sync_add_and_fetch(&mValue, 1); }
  81. template <> inline
  82. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Increment()
  83. { return __sync_add_and_fetch(&mValue, 1); }
  84. template <> inline
  85. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Decrement()
  86. { return __sync_sub_and_fetch(&mValue, 1); }
  87. template <> inline
  88. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Decrement()
  89. { return __sync_sub_and_fetch(&mValue, 1); }
  90. template <> inline
  91. AtomicInt<int32_t>::ValueType AtomicInt<int32_t>::Add(ValueType n)
  92. { return __sync_add_and_fetch(&mValue, n); }
  93. template <> inline
  94. AtomicInt<uint32_t>::ValueType AtomicInt<uint32_t>::Add(ValueType n)
  95. { return __sync_add_and_fetch(&mValue, n); }
  96. template <> inline
  97. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::GetValue() const
  98. { return __sync_add_and_fetch(const_cast<ValueType*>(&mValue), 0); }
  99. template <> inline
  100. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::GetValue() const
  101. { return __sync_add_and_fetch(const_cast<ValueType*>(&mValue), 0); }
  102. template <> inline
  103. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::SetValue(ValueType n)
  104. { __sync_synchronize(); return __sync_lock_test_and_set(&mValue, n); }
  105. template <> inline
  106. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::SetValue(ValueType n)
  107. { __sync_synchronize(); return __sync_lock_test_and_set(&mValue, n); }
  108. template <> inline
  109. bool AtomicInt<int64_t>::SetValueConditional(ValueType n, ValueType condition)
  110. { return (__sync_val_compare_and_swap(&mValue, condition, n) == condition); }
  111. template <> inline
  112. bool AtomicInt<uint64_t>::SetValueConditional(ValueType n, ValueType condition)
  113. { return (__sync_val_compare_and_swap(&mValue, condition, n) == condition); }
  114. template <> inline
  115. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Increment()
  116. { return __sync_add_and_fetch(&mValue, 1); }
  117. template <> inline
  118. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Increment()
  119. { return __sync_add_and_fetch(&mValue, 1); }
  120. template <> inline
  121. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Decrement()
  122. { return __sync_sub_and_fetch(&mValue, 1); }
  123. template <> inline
  124. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Decrement()
  125. { return __sync_sub_and_fetch(&mValue, 1); }
  126. template <> inline
  127. AtomicInt<int64_t>::ValueType AtomicInt<int64_t>::Add(ValueType n)
  128. { return __sync_add_and_fetch(&mValue, n); }
  129. template <> inline
  130. AtomicInt<uint64_t>::ValueType AtomicInt<uint64_t>::Add(ValueType n)
  131. { return __sync_add_and_fetch(&mValue, n); }
  132. #endif
  133. } // namespace Thread
  134. } // namespace EA
  135. #endif // EATHREAD_GCC_EATHREAD_ATOMIC_GCC_H