/////////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. /////////////////////////////////////////////////////////////////////////////// #if defined(EA_PRAGMA_ONCE_SUPPORTED) #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. #endif #ifndef EATHREAD_GCC_EATHREAD_ATOMIC_GCC_H #define EATHREAD_GCC_EATHREAD_ATOMIC_GCC_H #include #include #include #define EA_THREAD_ATOMIC_IMPLEMENTED namespace EA { namespace Thread { /// class AtomicInt /// Actual implementation may vary per platform. May require certain alignments, sizes, /// and declaration specifications per platform. template class AtomicInt { public: typedef AtomicInt ThisType; typedef T ValueType; /// AtomicInt /// Empty constructor. Intentionally leaves mValue in an unspecified state. /// This is done so that an AtomicInt acts like a standard built-in integer. AtomicInt() {} AtomicInt(ValueType n) { SetValue(n); } AtomicInt(const ThisType& x) : mValue(x.GetValue()) {} AtomicInt& operator=(const ThisType& x) { mValue = x.GetValue(); return *this; } ValueType GetValue() const { return mValue; } ValueType GetValueRaw() const { return mValue; } ValueType SetValue(ValueType n); bool SetValueConditional(ValueType n, ValueType condition); ValueType Increment(); ValueType Decrement(); ValueType Add(ValueType n); // operators inline operator const ValueType() const { return GetValue(); } inline ValueType operator =(ValueType n) { SetValue(n); return n; } inline ValueType operator+=(ValueType n) { return Add(n);} inline ValueType operator-=(ValueType n) { return Add(-n);} inline ValueType operator++() { return Increment();} inline ValueType operator++(int) { return Increment() - 1;} inline ValueType operator--() { return Decrement(); } inline ValueType operator--(int) { return Decrement() + 1;} protected: volatile ValueType mValue; }; // Recent versions of GCC have atomic primitives built into the compiler and standard library. #if defined(EA_COMPILER_CLANG) \ || defined(EA_PLATFORM_APPLE) \ || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) \ || defined(EA_COMPILER_RVCT) // GCC 4.3 or later. Depends on the GCC implementation. template <> inline AtomicInt::ValueType AtomicInt::GetValue() const { return __sync_add_and_fetch(const_cast(&mValue), 0); } template <> inline AtomicInt::ValueType AtomicInt::GetValue() const { return __sync_add_and_fetch(const_cast(&mValue), 0); } template <> inline AtomicInt::ValueType AtomicInt::SetValue(ValueType n) { __sync_synchronize(); return __sync_lock_test_and_set(&mValue, n); } template <> inline AtomicInt::ValueType AtomicInt::SetValue(ValueType n) { __sync_synchronize(); return __sync_lock_test_and_set(&mValue, n); } template <> inline bool AtomicInt::SetValueConditional(ValueType n, ValueType condition) { return (__sync_val_compare_and_swap(&mValue, condition, n) == condition); } template <> inline bool AtomicInt::SetValueConditional(ValueType n, ValueType condition) { return (__sync_val_compare_and_swap(&mValue, condition, n) == condition); } template <> inline AtomicInt::ValueType AtomicInt::Increment() { return __sync_add_and_fetch(&mValue, 1); } template <> inline AtomicInt::ValueType AtomicInt::Increment() { return __sync_add_and_fetch(&mValue, 1); } template <> inline AtomicInt::ValueType AtomicInt::Decrement() { return __sync_sub_and_fetch(&mValue, 1); } template <> inline AtomicInt::ValueType AtomicInt::Decrement() { return __sync_sub_and_fetch(&mValue, 1); } template <> inline AtomicInt::ValueType AtomicInt::Add(ValueType n) { return __sync_add_and_fetch(&mValue, n); } template <> inline AtomicInt::ValueType AtomicInt::Add(ValueType n) { return __sync_add_and_fetch(&mValue, n); } template <> inline AtomicInt::ValueType AtomicInt::GetValue() const { return __sync_add_and_fetch(const_cast(&mValue), 0); } template <> inline AtomicInt::ValueType AtomicInt::GetValue() const { return __sync_add_and_fetch(const_cast(&mValue), 0); } template <> inline AtomicInt::ValueType AtomicInt::SetValue(ValueType n) { __sync_synchronize(); return __sync_lock_test_and_set(&mValue, n); } template <> inline AtomicInt::ValueType AtomicInt::SetValue(ValueType n) { __sync_synchronize(); return __sync_lock_test_and_set(&mValue, n); } template <> inline bool AtomicInt::SetValueConditional(ValueType n, ValueType condition) { return (__sync_val_compare_and_swap(&mValue, condition, n) == condition); } template <> inline bool AtomicInt::SetValueConditional(ValueType n, ValueType condition) { return (__sync_val_compare_and_swap(&mValue, condition, n) == condition); } template <> inline AtomicInt::ValueType AtomicInt::Increment() { return __sync_add_and_fetch(&mValue, 1); } template <> inline AtomicInt::ValueType AtomicInt::Increment() { return __sync_add_and_fetch(&mValue, 1); } template <> inline AtomicInt::ValueType AtomicInt::Decrement() { return __sync_sub_and_fetch(&mValue, 1); } template <> inline AtomicInt::ValueType AtomicInt::Decrement() { return __sync_sub_and_fetch(&mValue, 1); } template <> inline AtomicInt::ValueType AtomicInt::Add(ValueType n) { return __sync_add_and_fetch(&mValue, n); } template <> inline AtomicInt::ValueType AtomicInt::Add(ValueType n) { return __sync_add_and_fetch(&mValue, n); } #endif } // namespace Thread } // namespace EA #endif // EATHREAD_GCC_EATHREAD_ATOMIC_GCC_H