1//===----------------------------------------------------------------------===//// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===//// 8 9// FIXME: This file is copied from libcxx/src/include/atomic_support.h. Instead 10// of duplicating the file in libc++abi we should require that the libc++ 11// sources are available when building libc++abi. 12 13#ifndef ATOMIC_SUPPORT_H 14#define ATOMIC_SUPPORT_H 15 16#include "__config" 17#include "memory" // for __libcpp_relaxed_load 18 19#if defined(__clang__) && __has_builtin(__atomic_load_n) \ 20 && __has_builtin(__atomic_store_n) \ 21 && __has_builtin(__atomic_add_fetch) \ 22 && __has_builtin(__atomic_exchange_n) \ 23 && __has_builtin(__atomic_compare_exchange_n) \ 24 && defined(__ATOMIC_RELAXED) \ 25 && defined(__ATOMIC_CONSUME) \ 26 && defined(__ATOMIC_ACQUIRE) \ 27 && defined(__ATOMIC_RELEASE) \ 28 && defined(__ATOMIC_ACQ_REL) \ 29 && defined(__ATOMIC_SEQ_CST) 30# define _LIBCXXABI_HAS_ATOMIC_BUILTINS 31#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407 32# define _LIBCXXABI_HAS_ATOMIC_BUILTINS 33#endif 34 35#if !defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS) 36# if defined(_LIBCPP_WARNING) 37 _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported") 38# else 39# warning Building libc++ without __atomic builtins is unsupported 40# endif 41#endif 42 43_LIBCPP_BEGIN_NAMESPACE_STD 44 45namespace { 46 47#if defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS) 48 49enum __libcpp_atomic_order { 50 _AO_Relaxed = __ATOMIC_RELAXED, 51 _AO_Consume = __ATOMIC_CONSUME, 52 _AO_Acquire = __ATOMIC_ACQUIRE, 53 _AO_Release = __ATOMIC_RELEASE, 54 _AO_Acq_Rel = __ATOMIC_ACQ_REL, 55 _AO_Seq = __ATOMIC_SEQ_CST 56}; 57 58template <class _ValueType, class _FromType> 59inline _LIBCPP_INLINE_VISIBILITY 60void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, 61 int __order = _AO_Seq) 62{ 63 __atomic_store_n(__dest, __val, __order); 64} 65 66template <class _ValueType, class _FromType> 67inline _LIBCPP_INLINE_VISIBILITY 68void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) 69{ 70 __atomic_store_n(__dest, __val, _AO_Relaxed); 71} 72 73template <class _ValueType> 74inline _LIBCPP_INLINE_VISIBILITY 75_ValueType __libcpp_atomic_load(_ValueType const* __val, 76 int __order = _AO_Seq) 77{ 78 return __atomic_load_n(__val, __order); 79} 80 81template <class _ValueType, class _AddType> 82inline _LIBCPP_INLINE_VISIBILITY 83_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, 84 int __order = _AO_Seq) 85{ 86 return __atomic_add_fetch(__val, __a, __order); 87} 88 89template <class _ValueType> 90inline _LIBCPP_INLINE_VISIBILITY 91_ValueType __libcpp_atomic_exchange(_ValueType* __target, 92 _ValueType __value, int __order = _AO_Seq) 93{ 94 return __atomic_exchange_n(__target, __value, __order); 95} 96 97template <class _ValueType> 98inline _LIBCPP_INLINE_VISIBILITY 99bool __libcpp_atomic_compare_exchange(_ValueType* __val, 100 _ValueType* __expected, _ValueType __after, 101 int __success_order = _AO_Seq, 102 int __fail_order = _AO_Seq) 103{ 104 return __atomic_compare_exchange_n(__val, __expected, __after, true, 105 __success_order, __fail_order); 106} 107 108#else // _LIBCPP_HAS_NO_THREADS 109 110enum __libcpp_atomic_order { 111 _AO_Relaxed, 112 _AO_Consume, 113 _AO_Acquire, 114 _AO_Release, 115 _AO_Acq_Rel, 116 _AO_Seq 117}; 118 119template <class _ValueType, class _FromType> 120inline _LIBCPP_INLINE_VISIBILITY 121void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, 122 int = 0) 123{ 124 *__dest = __val; 125} 126 127template <class _ValueType, class _FromType> 128inline _LIBCPP_INLINE_VISIBILITY 129void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) 130{ 131 *__dest = __val; 132} 133 134template <class _ValueType> 135inline _LIBCPP_INLINE_VISIBILITY 136_ValueType __libcpp_atomic_load(_ValueType const* __val, 137 int = 0) 138{ 139 return *__val; 140} 141 142template <class _ValueType, class _AddType> 143inline _LIBCPP_INLINE_VISIBILITY 144_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, 145 int = 0) 146{ 147 return *__val += __a; 148} 149 150template <class _ValueType> 151inline _LIBCPP_INLINE_VISIBILITY 152_ValueType __libcpp_atomic_exchange(_ValueType* __target, 153 _ValueType __value, int = _AO_Seq) 154{ 155 _ValueType old = *__target; 156 *__target = __value; 157 return old; 158} 159 160template <class _ValueType> 161inline _LIBCPP_INLINE_VISIBILITY 162bool __libcpp_atomic_compare_exchange(_ValueType* __val, 163 _ValueType* __expected, _ValueType __after, 164 int = 0, int = 0) 165{ 166 if (*__val == *__expected) { 167 *__val = __after; 168 return true; 169 } 170 *__expected = *__val; 171 return false; 172} 173 174#endif // _LIBCPP_HAS_NO_THREADS 175 176} // end namespace 177 178_LIBCPP_END_NAMESPACE_STD 179 180namespace { 181 182template <class IntType> 183class AtomicInt { 184public: 185 using MemoryOrder = std::__libcpp_atomic_order; 186 187 explicit AtomicInt(IntType *b) : b(b) {} 188 AtomicInt(AtomicInt const&) = delete; 189 AtomicInt& operator=(AtomicInt const&) = delete; 190 191 IntType load(MemoryOrder ord) { 192 return std::__libcpp_atomic_load(b, ord); 193 } 194 void store(IntType val, MemoryOrder ord) { 195 std::__libcpp_atomic_store(b, val, ord); 196 } 197 IntType exchange(IntType new_val, MemoryOrder ord) { 198 return std::__libcpp_atomic_exchange(b, new_val, ord); 199 } 200 bool compare_exchange(IntType *expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) { 201 return std::__libcpp_atomic_compare_exchange(b, expected, desired, ord_success, ord_failure); 202 } 203 204private: 205 IntType *b; 206}; 207 208} // end namespace 209 210#endif // ATOMIC_SUPPORT_H 211