123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- // Copyright (c) 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- // This file is an internal atomic implementation, use atomicops.h instead.
- //
- // This implementation uses C++11 atomics' member functions. The code base is
- // currently written assuming atomicity revolves around accesses instead of
- // C++11's memory locations. The burden is on the programmer to ensure that all
- // memory locations accessed atomically are never accessed non-atomically (tsan
- // should help with this).
- //
- // TODO(jfb) Modify the atomicops.h API and user code to declare atomic
- // locations as truly atomic. See the static_assert below.
- //
- // Of note in this implementation:
- // * All NoBarrier variants are implemented as relaxed.
- // * All Barrier variants are implemented as sequentially-consistent.
- // * Compare exchange's failure ordering is always the same as the success one
- // (except for release, which fails as relaxed): using a weaker ordering is
- // only valid under certain uses of compare exchange.
- // * Acquire store doesn't exist in the C11 memory model, it is instead
- // implemented as a relaxed store followed by a sequentially consistent
- // fence.
- // * Release load doesn't exist in the C11 memory model, it is instead
- // implemented as sequentially consistent fence followed by a relaxed load.
- // * Atomic increment is expected to return the post-incremented value, whereas
- // C11 fetch add returns the previous value. The implementation therefore
- // needs to increment twice (which the compiler should be able to detect and
- // optimize).
- #ifndef BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
- #define BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
- #include <atomic>
- #include "build/build_config.h"
- namespace base {
- namespace subtle {
- // This implementation is transitional and maintains the original API for
- // atomicops.h. This requires casting memory locations to the atomic types, and
- // assumes that the API and the C++11 implementation are layout-compatible,
- // which isn't true for all implementations or hardware platforms. The static
- // assertion should detect this issue, were it to fire then this header
- // shouldn't be used.
- //
- // TODO(jfb) If this header manages to stay committed then the API should be
- // modified, and all call sites updated.
- typedef volatile std::atomic<Atomic32>* AtomicLocation32;
- static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
- "incompatible 32-bit atomic layout");
- inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- ((AtomicLocation32)ptr)
- ->compare_exchange_strong(old_value,
- new_value,
- std::memory_order_relaxed,
- std::memory_order_relaxed);
- return old_value;
- }
- inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
- Atomic32 new_value) {
- return ((AtomicLocation32)ptr)
- ->exchange(new_value, std::memory_order_relaxed);
- }
- inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- return increment +
- ((AtomicLocation32)ptr)
- ->fetch_add(increment, std::memory_order_relaxed);
- }
- inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
- }
- inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- ((AtomicLocation32)ptr)
- ->compare_exchange_strong(old_value,
- new_value,
- std::memory_order_acquire,
- std::memory_order_acquire);
- return old_value;
- }
- inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- ((AtomicLocation32)ptr)
- ->compare_exchange_strong(old_value,
- new_value,
- std::memory_order_release,
- std::memory_order_relaxed);
- return old_value;
- }
- inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
- ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
- }
- inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
- ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
- std::atomic_thread_fence(std::memory_order_seq_cst);
- }
- inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
- ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
- }
- inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
- return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
- }
- inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
- return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
- }
- inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
- std::atomic_thread_fence(std::memory_order_seq_cst);
- return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
- }
- #if defined(ARCH_CPU_64_BITS)
- typedef volatile std::atomic<Atomic64>* AtomicLocation64;
- static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
- "incompatible 64-bit atomic layout");
- inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- ((AtomicLocation64)ptr)
- ->compare_exchange_strong(old_value,
- new_value,
- std::memory_order_relaxed,
- std::memory_order_relaxed);
- return old_value;
- }
- inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
- Atomic64 new_value) {
- return ((AtomicLocation64)ptr)
- ->exchange(new_value, std::memory_order_relaxed);
- }
- inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- return increment +
- ((AtomicLocation64)ptr)
- ->fetch_add(increment, std::memory_order_relaxed);
- }
- inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
- }
- inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- ((AtomicLocation64)ptr)
- ->compare_exchange_strong(old_value,
- new_value,
- std::memory_order_acquire,
- std::memory_order_acquire);
- return old_value;
- }
- inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- ((AtomicLocation64)ptr)
- ->compare_exchange_strong(old_value,
- new_value,
- std::memory_order_release,
- std::memory_order_relaxed);
- return old_value;
- }
- inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
- ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
- }
- inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
- ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
- std::atomic_thread_fence(std::memory_order_seq_cst);
- }
- inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
- ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
- }
- inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
- return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
- }
- inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
- return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
- }
- inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
- std::atomic_thread_fence(std::memory_order_seq_cst);
- return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
- }
- #endif // defined(ARCH_CPU_64_BITS)
- } // namespace subtle
- } // namespace base
- #endif // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
|