// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_BASE_ATOMIC_UTILS_H_ #define V8_BASE_ATOMIC_UTILS_H_ #include #include #include "src/base/atomicops.h" #include "src/base/macros.h" namespace v8 { namespace base { // Deprecated. Use std::atomic for new code. // Flag using T atomically. Also accepts void* as T. template class AtomicValue { public: AtomicValue() : value_(0) {} explicit AtomicValue(T initial) : value_(cast_helper::to_storage_type(initial)) {} V8_INLINE T Value() const { return cast_helper::to_return_type(base::Acquire_Load(&value_)); } V8_INLINE void SetValue(T new_value) { base::Release_Store(&value_, cast_helper::to_storage_type(new_value)); } private: STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); template struct cast_helper { static base::AtomicWord to_storage_type(S value) { return static_cast(value); } static S to_return_type(base::AtomicWord value) { return static_cast(value); } }; template struct cast_helper { static base::AtomicWord to_storage_type(S* value) { return reinterpret_cast(value); } static S* to_return_type(base::AtomicWord value) { return reinterpret_cast(value); } }; base::AtomicWord value_; }; // Provides atomic operations for a values stored at some address. template class AsAtomicImpl { public: using AtomicStorageType = TAtomicStorageType; template static T Acquire_Load(T* addr) { STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); return cast_helper::to_return_type( base::Acquire_Load(to_storage_addr(addr))); } template static T Relaxed_Load(T* addr) { STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); return cast_helper::to_return_type( base::Relaxed_Load(to_storage_addr(addr))); } template static void Release_Store(T* addr, typename std::remove_reference::type new_value) { STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); base::Release_Store(to_storage_addr(addr), cast_helper::to_storage_type(new_value)); } template static void Relaxed_Store(T* addr, typename std::remove_reference::type new_value) { STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); base::Relaxed_Store(to_storage_addr(addr), cast_helper::to_storage_type(new_value)); } template static T Release_CompareAndSwap( T* addr, typename std::remove_reference::type old_value, typename std::remove_reference::type new_value) { STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); return cast_helper::to_return_type(base::Release_CompareAndSwap( to_storage_addr(addr), cast_helper::to_storage_type(old_value), cast_helper::to_storage_type(new_value))); } // Atomically sets bits selected by the mask to the given value. // Returns false if the bits are already set as needed. template static bool SetBits(T* addr, T bits, T mask) { STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); DCHECK_EQ(bits & ~mask, static_cast(0)); T old_value; T new_value; do { old_value = Relaxed_Load(addr); if ((old_value & mask) == bits) return false; new_value = (old_value & ~mask) | bits; } while (Release_CompareAndSwap(addr, old_value, new_value) != old_value); return true; } private: template struct cast_helper { static AtomicStorageType to_storage_type(U value) { return static_cast(value); } static U to_return_type(AtomicStorageType value) { return static_cast(value); } }; template struct cast_helper { static AtomicStorageType to_storage_type(U* value) { return reinterpret_cast(value); } static U* to_return_type(AtomicStorageType value) { return reinterpret_cast(value); } }; template static AtomicStorageType* to_storage_addr(T* value) { return reinterpret_cast(value); } template static const AtomicStorageType* to_storage_addr(const T* value) { return reinterpret_cast(value); } }; using AsAtomic8 = AsAtomicImpl; using AsAtomic32 = AsAtomicImpl; using AsAtomicWord = AsAtomicImpl; // This is similar to AsAtomicWord but it explicitly deletes functionality // provided atomic access to bit representation of stored values. template class AsAtomicPointerImpl : public AsAtomicImpl { public: template static bool SetBits(T* addr, T bits, T mask) = delete; }; using AsAtomicPointer = AsAtomicPointerImpl; template ::value>::type> inline void CheckedIncrement(std::atomic* number, T amount) { const T old = number->fetch_add(amount); DCHECK_GE(old + amount, old); USE(old); } template ::value>::type> inline void CheckedDecrement(std::atomic* number, T amount) { const T old = number->fetch_sub(amount); DCHECK_GE(old, amount); USE(old); } } // namespace base } // namespace v8 #endif // V8_BASE_ATOMIC_UTILS_H_