/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include namespace folly { // relaxed_atomic // // Like atomic, but without the std::memory_order parameters on any member // functions. All operations use std::memory_order_relaxed, rather than the // std::memory_order_seq_cst, which is the default memory order in std::atomic. // // Useful for values which may be loaded and stored concurrently, such as // counters, but which do not guard any associated data. template struct relaxed_atomic; namespace detail { template struct relaxed_atomic_base : protected std::atomic { private: using atomic = std::atomic; public: using value_type = T; using atomic::atomic; T operator=(T desired) noexcept { store(desired); return desired; } T operator=(T desired) volatile noexcept { store(desired); return desired; } bool is_lock_free() const noexcept { return atomic::is_lock_free(); } bool is_lock_free() const volatile noexcept { return atomic::is_lock_free(); } void store(T desired) noexcept { atomic::store(desired, std::memory_order_relaxed); } void store(T desired) volatile noexcept { atomic::store(desired, std::memory_order_relaxed); } T load() const noexcept { return atomic::load(std::memory_order_relaxed); } T load() const volatile noexcept { return atomic::load(std::memory_order_relaxed); } operator T() const noexcept { return load(); } operator T() const volatile noexcept { return load(); } T exchange(T desired) noexcept { return atomic::exchange(desired, std::memory_order_relaxed); } T exchange(T desired) volatile noexcept { return atomic::exchange(desired, std::memory_order_relaxed); } bool compare_exchange_weak(T& expected, T desired) noexcept { return atomic::compare_exchange_weak( expected, desired, std::memory_order_relaxed); } bool compare_exchange_weak(T& expected, T desired) volatile noexcept { return atomic::compare_exchange_weak( expected, desired, std::memory_order_relaxed); } bool compare_exchange_strong(T& expected, T desired) noexcept { return atomic::compare_exchange_strong( expected, desired, std::memory_order_relaxed); } bool compare_exchange_strong(T& expected, T desired) volatile noexcept { return atomic::compare_exchange_strong( expected, desired, std::memory_order_relaxed); } }; template struct relaxed_atomic_integral_base : private relaxed_atomic_base { private: using atomic = std::atomic; using base = relaxed_atomic_base; public: using typename base::value_type; using base::relaxed_atomic_base; using base::operator=; using base::operator T; using base::compare_exchange_strong; using base::compare_exchange_weak; using base::exchange; using base::is_lock_free; using base::load; using base::store; T fetch_add(T arg) noexcept { return atomic::fetch_add(arg, std::memory_order_relaxed); } T fetch_add(T arg) volatile noexcept { return atomic::fetch_add(arg, std::memory_order_relaxed); } T fetch_sub(T arg) noexcept { return atomic::fetch_sub(arg, std::memory_order_relaxed); } T fetch_sub(T arg) volatile noexcept { return atomic::fetch_sub(arg, std::memory_order_relaxed); } T fetch_and(T arg) noexcept { return atomic::fetch_and(arg, std::memory_order_relaxed); } T fetch_and(T arg) volatile noexcept { return atomic::fetch_and(arg, std::memory_order_relaxed); } T fetch_or(T arg) noexcept { return atomic::fetch_or(arg, std::memory_order_relaxed); } T fetch_or(T arg) volatile noexcept { return atomic::fetch_or(arg, std::memory_order_relaxed); } T fetch_xor(T arg) noexcept { return atomic::fetch_xor(arg, std::memory_order_relaxed); } T fetch_xor(T arg) volatile noexcept { return atomic::fetch_xor(arg, std::memory_order_relaxed); } T operator++() noexcept { return fetch_add(1) + 1; } T operator++() volatile noexcept { return fetch_add(1) + 1; } T operator++(int) noexcept { return fetch_add(1); } T operator++(int) volatile noexcept { return fetch_add(1); } T operator--() noexcept { return fetch_sub(1) - 1; } T operator--() volatile noexcept { return fetch_sub(1) - 1; } T operator--(int) noexcept { return fetch_sub(1); } T operator--(int) volatile noexcept { return fetch_sub(1); } T operator+=(T arg) noexcept { return fetch_add(arg) + arg; } T operator+=(T arg) volatile noexcept { return fetch_add(arg) + arg; } T operator-=(T arg) noexcept { return fetch_sub(arg) - arg; } T operator-=(T arg) volatile noexcept { return fetch_sub(arg) - arg; } T operator&=(T arg) noexcept { return fetch_and(arg) & arg; } T operator&=(T arg) volatile noexcept { return fetch_and(arg) & arg; } T operator|=(T arg) noexcept { return fetch_or(arg) | arg; } T operator|=(T arg) volatile noexcept { return fetch_or(arg) | arg; } T operator^=(T arg) noexcept { return fetch_xor(arg) ^ arg; } T operator^=(T arg) volatile noexcept { return fetch_xor(arg) ^ arg; } }; } // namespace detail template <> struct relaxed_atomic : detail::relaxed_atomic_base { private: using base = detail::relaxed_atomic_base; public: using typename base::value_type; using base::relaxed_atomic_base; using base::operator=; using base::operator bool; }; using relaxed_atomic_bool = relaxed_atomic; template struct relaxed_atomic : detail::relaxed_atomic_base { private: using base = detail::relaxed_atomic_base; public: using typename base::value_type; using base::relaxed_atomic_base; using base::operator=; using base::operator T; }; template struct relaxed_atomic : detail::relaxed_atomic_base { private: using atomic = std::atomic; using base = detail::relaxed_atomic_base; public: using typename base::value_type; using detail::relaxed_atomic_base::relaxed_atomic_base; using base::operator=; using base::operator T*; T* fetch_add(std::ptrdiff_t arg) noexcept { return atomic::fetch_add(arg, std::memory_order_relaxed); } T* fetch_add(std::ptrdiff_t arg) volatile noexcept { return atomic::fetch_add(arg, std::memory_order_relaxed); } T* fetch_sub(std::ptrdiff_t arg) noexcept { return atomic::fetch_sub(arg, std::memory_order_relaxed); } T* fetch_sub(std::ptrdiff_t arg) volatile noexcept { return atomic::fetch_sub(arg, std::memory_order_relaxed); } T* operator++() noexcept { return fetch_add(1) + 1; } T* operator++() volatile noexcept { return fetch_add(1) + 1; } T* operator++(int) noexcept { return fetch_add(1); } T* operator++(int) volatile noexcept { return fetch_add(1); } T* operator--() noexcept { return fetch_sub(1) - 1; } T* operator--() volatile noexcept { return fetch_sub(1) - 1; } T* operator--(int) noexcept { return fetch_sub(1); } T* operator--(int) volatile noexcept { return fetch_sub(1); } T* operator+=(std::ptrdiff_t arg) noexcept { return fetch_add(arg) + arg; } T* operator+=(std::ptrdiff_t arg) volatile noexcept { return fetch_add(arg) + arg; } T* operator-=(std::ptrdiff_t arg) noexcept { return fetch_sub(arg) - arg; } T* operator-=(std::ptrdiff_t arg) volatile noexcept { return fetch_sub(arg) - arg; } }; #if __cpp_deduction_guides >= 201611 template relaxed_atomic(T) -> relaxed_atomic; #endif #define FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(type) \ template <> \ struct relaxed_atomic : detail::relaxed_atomic_integral_base { \ private: \ using base = detail::relaxed_atomic_integral_base; \ \ public: \ using base::relaxed_atomic_integral_base; \ using base::operator=; \ using base::operator type; \ }; FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(char) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(signed char) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(unsigned char) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(signed short) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(unsigned short) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(signed int) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(unsigned int) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(signed long) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(unsigned long) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(signed long long) FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION(unsigned long long) #undef FOLLY_RELAXED_ATOMIC_DEFINE_INTEGRAL_SPECIALIZATION using relaxed_atomic_char = relaxed_atomic; using relaxed_atomic_schar = relaxed_atomic; using relaxed_atomic_uchar = relaxed_atomic; using relaxed_atomic_short = relaxed_atomic; using relaxed_atomic_ushort = relaxed_atomic; using relaxed_atomic_int = relaxed_atomic; using relaxed_atomic_uint = relaxed_atomic; using relaxed_atomic_long = relaxed_atomic; using relaxed_atomic_ulong = relaxed_atomic; using relaxed_atomic_llong = relaxed_atomic; using relaxed_atomic_ullong = relaxed_atomic; using relaxed_atomic_char16_t = relaxed_atomic; using relaxed_atomic_char32_t = relaxed_atomic; using relaxed_atomic_wchar_t = relaxed_atomic; using relaxed_atomic_int8_t = relaxed_atomic; using relaxed_atomic_uint8_t = relaxed_atomic; using relaxed_atomic_int16_t = relaxed_atomic; using relaxed_atomic_uint16_t = relaxed_atomic; using relaxed_atomic_int32_t = relaxed_atomic; using relaxed_atomic_uint32_t = relaxed_atomic; using relaxed_atomic_int64_t = relaxed_atomic; using relaxed_atomic_uint64_t = relaxed_atomic; using relaxed_atomic_int_least8_t = relaxed_atomic; using relaxed_atomic_uint_least8_t = relaxed_atomic; using relaxed_atomic_int_least16_t = relaxed_atomic; using relaxed_atomic_uint_least16_t = relaxed_atomic; using relaxed_atomic_int_least32_t = relaxed_atomic; using relaxed_atomic_uint_least32_t = relaxed_atomic; using relaxed_atomic_int_least64_t = relaxed_atomic; using relaxed_atomic_uint_least64_t = relaxed_atomic; using relaxed_atomic_int_fast8_t = relaxed_atomic; using relaxed_atomic_uint_fast8_t = relaxed_atomic; using relaxed_atomic_int_fast16_t = relaxed_atomic; using relaxed_atomic_uint_fast16_t = relaxed_atomic; using relaxed_atomic_int_fast32_t = relaxed_atomic; using relaxed_atomic_uint_fast32_t = relaxed_atomic; using relaxed_atomic_int_fast64_t = relaxed_atomic; using relaxed_atomic_uint_fast64_t = relaxed_atomic; using relaxed_atomic_intptr_t = relaxed_atomic; using relaxed_atomic_uintptr_t = relaxed_atomic; using relaxed_atomic_size_t = relaxed_atomic; using relaxed_atomic_ptrdiff_t = relaxed_atomic; using relaxed_atomic_intmax_t = relaxed_atomic; using relaxed_atomic_uintmax_t = relaxed_atomic; } // namespace folly