1f7cb1657SDavid Chisnall 2f7cb1657SDavid Chisnall #ifndef __has_builtin 3f7cb1657SDavid Chisnall # define __has_builtin(x) 0 4f7cb1657SDavid Chisnall #endif 5f7cb1657SDavid Chisnall #ifndef __has_feature 6f7cb1657SDavid Chisnall # define __has_feature(x) 0 7f7cb1657SDavid Chisnall #endif 8bfffb66eSDimitry Andric #ifndef __has_extension 9bfffb66eSDimitry Andric # define __has_extension(x) 0 10bfffb66eSDimitry Andric #endif 11bfffb66eSDimitry Andric 12bfffb66eSDimitry Andric #if !__has_extension(c_atomic) 13bfffb66eSDimitry Andric # define _Atomic(T) T 14bfffb66eSDimitry Andric #endif 15d9e22925SDimitry Andric #if __has_builtin(__c11_atomic_exchange) 16bfffb66eSDimitry Andric # define ATOMIC_BUILTIN(name) __c11_atomic_##name 17f7cb1657SDavid Chisnall #else 18bfffb66eSDimitry Andric # define ATOMIC_BUILTIN(name) __atomic_##name##_n 19f7cb1657SDavid Chisnall #endif 20f7cb1657SDavid Chisnall 21bfffb66eSDimitry Andric namespace 22bfffb66eSDimitry Andric { 23bfffb66eSDimitry Andric /** 24bfffb66eSDimitry Andric * C++11 memory orders. We only need a subset of them. 25bfffb66eSDimitry Andric */ 26bfffb66eSDimitry Andric enum memory_order 27bfffb66eSDimitry Andric { 28bfffb66eSDimitry Andric /** 29bfffb66eSDimitry Andric * Acquire order. 30bfffb66eSDimitry Andric */ 31bfffb66eSDimitry Andric acquire = __ATOMIC_ACQUIRE, 3225482379SDimitry Andric 33bfffb66eSDimitry Andric /** 34bfffb66eSDimitry Andric * Release order. 35bfffb66eSDimitry Andric */ 36bfffb66eSDimitry Andric release = __ATOMIC_RELEASE, 37bfffb66eSDimitry Andric 38bfffb66eSDimitry Andric /** 39bfffb66eSDimitry Andric * Sequentially consistent memory ordering. 40bfffb66eSDimitry Andric */ 41bfffb66eSDimitry Andric seqcst = __ATOMIC_SEQ_CST 42bfffb66eSDimitry Andric }; 43bfffb66eSDimitry Andric 44bfffb66eSDimitry Andric /** 45bfffb66eSDimitry Andric * Atomic, implements a subset of `std::atomic`. 46bfffb66eSDimitry Andric */ 47bfffb66eSDimitry Andric template<typename T> 48bfffb66eSDimitry Andric class atomic 49bfffb66eSDimitry Andric { 50bfffb66eSDimitry Andric /** 51bfffb66eSDimitry Andric * The underlying value. Use C11 atomic qualification if available. 52bfffb66eSDimitry Andric */ 53bfffb66eSDimitry Andric _Atomic(T) val; 54bfffb66eSDimitry Andric 55bfffb66eSDimitry Andric public: 56bfffb66eSDimitry Andric /** 57bfffb66eSDimitry Andric * Constructor, takes a value. 58bfffb66eSDimitry Andric */ atomic(T init)59bfffb66eSDimitry Andric atomic(T init) : val(init) {} 60bfffb66eSDimitry Andric 61bfffb66eSDimitry Andric /** 62bfffb66eSDimitry Andric * Atomically load with the specified memory order. 63bfffb66eSDimitry Andric */ 64bfffb66eSDimitry Andric T load(memory_order order = memory_order::seqcst) 65bfffb66eSDimitry Andric { 66bfffb66eSDimitry Andric return ATOMIC_BUILTIN(load)(&val, order); 67bfffb66eSDimitry Andric } 68bfffb66eSDimitry Andric 69bfffb66eSDimitry Andric /** 70bfffb66eSDimitry Andric * Atomically store with the specified memory order. 71bfffb66eSDimitry Andric */ 72bfffb66eSDimitry Andric void store(T v, memory_order order = memory_order::seqcst) 73bfffb66eSDimitry Andric { 74bfffb66eSDimitry Andric return ATOMIC_BUILTIN(store)(&val, v, order); 75bfffb66eSDimitry Andric } 76bfffb66eSDimitry Andric 77bfffb66eSDimitry Andric /** 78bfffb66eSDimitry Andric * Atomically exchange with the specified memory order. 79bfffb66eSDimitry Andric */ 80bfffb66eSDimitry Andric T exchange(T v, memory_order order = memory_order::seqcst) 81bfffb66eSDimitry Andric { 82bfffb66eSDimitry Andric return ATOMIC_BUILTIN(exchange)(&val, v, order); 83bfffb66eSDimitry Andric } 84bfffb66eSDimitry Andric 85bfffb66eSDimitry Andric /** 86bfffb66eSDimitry Andric * Atomically exchange with the specified memory order. 87bfffb66eSDimitry Andric */ 88bfffb66eSDimitry Andric bool compare_exchange(T & expected, 89bfffb66eSDimitry Andric T desired, 90bfffb66eSDimitry Andric memory_order order = memory_order::seqcst) 91bfffb66eSDimitry Andric { 92bfffb66eSDimitry Andric #if __has_builtin(__c11_atomic_compare_exchange_strong) 93bfffb66eSDimitry Andric return __c11_atomic_compare_exchange_strong( 94bfffb66eSDimitry Andric &val, &expected, desired, order, order); 95bfffb66eSDimitry Andric #else 96bfffb66eSDimitry Andric return __atomic_compare_exchange_n( 97bfffb66eSDimitry Andric &val, &expected, desired, true, order, order); 98bfffb66eSDimitry Andric #endif 99bfffb66eSDimitry Andric } 100bfffb66eSDimitry Andric }; 101bfffb66eSDimitry Andric } // namespace 102bfffb66eSDimitry Andric #undef ATOMIC_BUILTIN 103