b52aef3a8c
This is a substantial rewrite of the atomic wait/notify (and timed wait counterparts) implementation. The previous __platform_wait looped on EINTR however this behavior is not required by the standard. A new _GLIBCXX_HAVE_PLATFORM_WAIT macro now controls whether wait/notify are implemented using a platform specific primitive or with a platform agnostic mutex/condvar. This patch only supplies a definition for linux futexes. A future update could add support __ulock_wait/wake on Darwin, for instance. The members of __waiters were lifted to a new base class. The members are now arranged such that overall sizeof(__waiter_pool_base) fits in two cache lines (on platforms with at least 64 byte cache lines). The definition will also use destructive_interference_size for this if it is available. The __waiters type is now specific to untimed waits, and is renamed to __waiter_pool. Timed waits have a corresponding __timed_waiter_pool type. Much of the code has been moved from the previous __atomic_wait() free function to the __waiter_base template and a __waiter derived type is provided to implement the un-timed wait operations. A similar change has been made to the timed wait implementation. The __atomic_spin code has been extended to take a spin policy which is invoked after the initial busy wait loop. The default policy is to return from the spin. The timed wait code adds a timed backoff spinning policy. The code from <thread> which implements this_thread::sleep_for, sleep_until has been moved to a new <bits/std_thread_sleep.h> header which allows the thread sleep code to be consumed without pulling in the whole of <thread>. The entry points into the wait/notify code have been restructured to support either - * Testing the current value of the atomic stored at the given address and waiting on a notification. * Applying a predicate to determine if the wait was satisfied. The entry points were renamed to make it clear that the wait and wake operations operate on addresses. The first variant takes the expected value and a function which returns the current value that should be used in comparison operations, these operations are named with a _v suffix (e.g. 'value'). All atomic<_Tp> wait/notify operations use the first variant. Barriers, latches and semaphores use the predicate variant. This change also centralizes what it means to compare values for the purposes of atomic<T>::wait rather than scattering through individual predicates. This change also centralizes the repetitive code which adjusts for different user supplied clocks (this should be moved elsewhere and all such adjustments should use a common implementation). This change also removes the hashing of the pointer and uses the pointer value directly for indexing into the waiters table. libstdc++-v3/ChangeLog: * include/Makefile.am: Add new <bits/this_thread_sleep.h> header. * include/Makefile.in: Regenerate. * include/bits/this_thread_sleep.h: New file. * include/bits/atomic_base.h: Adjust all calls to __atomic_wait/__atomic_notify for new call signatures. * include/bits/atomic_timed_wait.h: Extensive rewrite. * include/bits/atomic_wait.h: Likewise. * include/bits/semaphore_base.h: Adjust all calls to __atomic_wait/__atomic_notify for new call signatures. * include/std/atomic: Likewise. * include/std/barrier: Likewise. * include/std/latch: Likewise. * include/std/semaphore: Likewise. * include/std/thread (this_thread::sleep_for) (this_thread::sleep_until): Move to new header. * testsuite/29_atomics/atomic/wait_notify/bool.cc: Simplify test. * testsuite/29_atomics/atomic/wait_notify/generic.cc: Likewise. * testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise. * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise. * testsuite/29_atomics/atomic_float/wait_notify.cc: Likewise. * testsuite/29_atomics/atomic_integral/wait_notify.cc: Likewise. * testsuite/29_atomics/atomic_ref/wait_notify.cc: Likewise.
1641 lines
46 KiB
C++
1641 lines
46 KiB
C++
// -*- C++ -*- header.
|
|
|
|
// Copyright (C) 2008-2021 Free Software Foundation, Inc.
|
|
//
|
|
// This file is part of the GNU ISO C++ Library. This library is free
|
|
// software; you can redistribute it and/or modify it under the
|
|
// terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 3, or (at your option)
|
|
// any later version.
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
// 3.1, as published by the Free Software Foundation.
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
/** @file include/atomic
|
|
* This is a Standard C++ Library header.
|
|
*/
|
|
|
|
// Based on "C++ Atomic Types and Operations" by Hans Boehm and Lawrence Crowl.
|
|
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html
|
|
|
|
#ifndef _GLIBCXX_ATOMIC
|
|
#define _GLIBCXX_ATOMIC 1
|
|
|
|
#pragma GCC system_header
|
|
|
|
#if __cplusplus < 201103L
|
|
# include <bits/c++0x_warning.h>
|
|
#else
|
|
|
|
#include <bits/atomic_base.h>
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
/**
|
|
* @addtogroup atomics
|
|
* @{
|
|
*/
|
|
|
|
#if __cplusplus >= 201703L
|
|
# define __cpp_lib_atomic_is_always_lock_free 201603
|
|
#endif
|
|
|
|
template<typename _Tp>
|
|
struct atomic;
|
|
|
|
/// atomic<bool>
|
|
// NB: No operators or fetch-operations for this type.
|
|
template<>
|
|
struct atomic<bool>
|
|
{
|
|
using value_type = bool;
|
|
|
|
private:
|
|
__atomic_base<bool> _M_base;
|
|
|
|
public:
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(bool __i) noexcept : _M_base(__i) { }
|
|
|
|
bool
|
|
operator=(bool __i) noexcept
|
|
{ return _M_base.operator=(__i); }
|
|
|
|
bool
|
|
operator=(bool __i) volatile noexcept
|
|
{ return _M_base.operator=(__i); }
|
|
|
|
operator bool() const noexcept
|
|
{ return _M_base.load(); }
|
|
|
|
operator bool() const volatile noexcept
|
|
{ return _M_base.load(); }
|
|
|
|
bool
|
|
is_lock_free() const noexcept { return _M_base.is_lock_free(); }
|
|
|
|
bool
|
|
is_lock_free() const volatile noexcept { return _M_base.is_lock_free(); }
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_BOOL_LOCK_FREE == 2;
|
|
#endif
|
|
|
|
void
|
|
store(bool __i, memory_order __m = memory_order_seq_cst) noexcept
|
|
{ _M_base.store(__i, __m); }
|
|
|
|
void
|
|
store(bool __i, memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ _M_base.store(__i, __m); }
|
|
|
|
bool
|
|
load(memory_order __m = memory_order_seq_cst) const noexcept
|
|
{ return _M_base.load(__m); }
|
|
|
|
bool
|
|
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
|
|
{ return _M_base.load(__m); }
|
|
|
|
bool
|
|
exchange(bool __i, memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_base.exchange(__i, __m); }
|
|
|
|
bool
|
|
exchange(bool __i,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_base.exchange(__i, __m); }
|
|
|
|
bool
|
|
compare_exchange_weak(bool& __i1, bool __i2, memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return _M_base.compare_exchange_weak(__i1, __i2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_weak(bool& __i1, bool __i2, memory_order __m1,
|
|
memory_order __m2) volatile noexcept
|
|
{ return _M_base.compare_exchange_weak(__i1, __i2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_weak(bool& __i1, bool __i2,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_base.compare_exchange_weak(__i1, __i2, __m); }
|
|
|
|
bool
|
|
compare_exchange_weak(bool& __i1, bool __i2,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_base.compare_exchange_weak(__i1, __i2, __m); }
|
|
|
|
bool
|
|
compare_exchange_strong(bool& __i1, bool __i2, memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return _M_base.compare_exchange_strong(__i1, __i2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_strong(bool& __i1, bool __i2, memory_order __m1,
|
|
memory_order __m2) volatile noexcept
|
|
{ return _M_base.compare_exchange_strong(__i1, __i2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_strong(bool& __i1, bool __i2,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
|
|
|
|
bool
|
|
compare_exchange_strong(bool& __i1, bool __i2,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
|
|
|
|
#if __cpp_lib_atomic_wait
|
|
void
|
|
wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
|
|
{ _M_base.wait(__old, __m); }
|
|
|
|
// TODO add const volatile overload
|
|
|
|
void
|
|
notify_one() const noexcept
|
|
{ _M_base.notify_one(); }
|
|
|
|
void
|
|
notify_all() const noexcept
|
|
{ _M_base.notify_all(); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
};
|
|
|
|
#if __cplusplus <= 201703L
|
|
# define _GLIBCXX20_INIT(I)
|
|
#else
|
|
# define _GLIBCXX20_INIT(I) = I
|
|
#endif
|
|
|
|
/**
|
|
* @brief Generic atomic type, primary class template.
|
|
*
|
|
* @tparam _Tp Type to be made atomic, must be trivially copyable.
|
|
*/
|
|
template<typename _Tp>
|
|
struct atomic
|
|
{
|
|
using value_type = _Tp;
|
|
|
|
private:
|
|
// Align 1/2/4/8/16-byte types to at least their size.
|
|
static constexpr int _S_min_alignment
|
|
= (sizeof(_Tp) & (sizeof(_Tp) - 1)) || sizeof(_Tp) > 16
|
|
? 0 : sizeof(_Tp);
|
|
|
|
static constexpr int _S_alignment
|
|
= _S_min_alignment > alignof(_Tp) ? _S_min_alignment : alignof(_Tp);
|
|
|
|
alignas(_S_alignment) _Tp _M_i _GLIBCXX20_INIT(_Tp());
|
|
|
|
static_assert(__is_trivially_copyable(_Tp),
|
|
"std::atomic requires a trivially copyable type");
|
|
|
|
static_assert(sizeof(_Tp) > 0,
|
|
"Incomplete or zero-sized types are not supported");
|
|
|
|
#if __cplusplus > 201703L
|
|
static_assert(is_copy_constructible_v<_Tp>);
|
|
static_assert(is_move_constructible_v<_Tp>);
|
|
static_assert(is_copy_assignable_v<_Tp>);
|
|
static_assert(is_move_assignable_v<_Tp>);
|
|
#endif
|
|
|
|
public:
|
|
atomic() = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(_Tp __i) noexcept : _M_i(__i) { }
|
|
|
|
operator _Tp() const noexcept
|
|
{ return load(); }
|
|
|
|
operator _Tp() const volatile noexcept
|
|
{ return load(); }
|
|
|
|
_Tp
|
|
operator=(_Tp __i) noexcept
|
|
{ store(__i); return __i; }
|
|
|
|
_Tp
|
|
operator=(_Tp __i) volatile noexcept
|
|
{ store(__i); return __i; }
|
|
|
|
bool
|
|
is_lock_free() const noexcept
|
|
{
|
|
// Produce a fake, minimally aligned pointer.
|
|
return __atomic_is_lock_free(sizeof(_M_i),
|
|
reinterpret_cast<void *>(-_S_alignment));
|
|
}
|
|
|
|
bool
|
|
is_lock_free() const volatile noexcept
|
|
{
|
|
// Produce a fake, minimally aligned pointer.
|
|
return __atomic_is_lock_free(sizeof(_M_i),
|
|
reinterpret_cast<void *>(-_S_alignment));
|
|
}
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free
|
|
= __atomic_always_lock_free(sizeof(_M_i), 0);
|
|
#endif
|
|
|
|
void
|
|
store(_Tp __i, memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
__atomic_store(std::__addressof(_M_i), std::__addressof(__i), int(__m));
|
|
}
|
|
|
|
void
|
|
store(_Tp __i, memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
__atomic_store(std::__addressof(_M_i), std::__addressof(__i), int(__m));
|
|
}
|
|
|
|
_Tp
|
|
load(memory_order __m = memory_order_seq_cst) const noexcept
|
|
{
|
|
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
|
|
_Tp* __ptr = reinterpret_cast<_Tp*>(__buf);
|
|
__atomic_load(std::__addressof(_M_i), __ptr, int(__m));
|
|
return *__ptr;
|
|
}
|
|
|
|
_Tp
|
|
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
|
|
{
|
|
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
|
|
_Tp* __ptr = reinterpret_cast<_Tp*>(__buf);
|
|
__atomic_load(std::__addressof(_M_i), __ptr, int(__m));
|
|
return *__ptr;
|
|
}
|
|
|
|
_Tp
|
|
exchange(_Tp __i, memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
|
|
_Tp* __ptr = reinterpret_cast<_Tp*>(__buf);
|
|
__atomic_exchange(std::__addressof(_M_i), std::__addressof(__i),
|
|
__ptr, int(__m));
|
|
return *__ptr;
|
|
}
|
|
|
|
_Tp
|
|
exchange(_Tp __i,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
|
|
_Tp* __ptr = reinterpret_cast<_Tp*>(__buf);
|
|
__atomic_exchange(std::__addressof(_M_i), std::__addressof(__i),
|
|
__ptr, int(__m));
|
|
return *__ptr;
|
|
}
|
|
|
|
bool
|
|
compare_exchange_weak(_Tp& __e, _Tp __i, memory_order __s,
|
|
memory_order __f) noexcept
|
|
{
|
|
return __atomic_compare_exchange(std::__addressof(_M_i),
|
|
std::__addressof(__e),
|
|
std::__addressof(__i),
|
|
true, int(__s), int(__f));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_weak(_Tp& __e, _Tp __i, memory_order __s,
|
|
memory_order __f) volatile noexcept
|
|
{
|
|
return __atomic_compare_exchange(std::__addressof(_M_i),
|
|
std::__addressof(__e),
|
|
std::__addressof(__i),
|
|
true, int(__s), int(__f));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_weak(_Tp& __e, _Tp __i,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return compare_exchange_weak(__e, __i, __m,
|
|
__cmpexch_failure_order(__m)); }
|
|
|
|
bool
|
|
compare_exchange_weak(_Tp& __e, _Tp __i,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return compare_exchange_weak(__e, __i, __m,
|
|
__cmpexch_failure_order(__m)); }
|
|
|
|
bool
|
|
compare_exchange_strong(_Tp& __e, _Tp __i, memory_order __s,
|
|
memory_order __f) noexcept
|
|
{
|
|
return __atomic_compare_exchange(std::__addressof(_M_i),
|
|
std::__addressof(__e),
|
|
std::__addressof(__i),
|
|
false, int(__s), int(__f));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_strong(_Tp& __e, _Tp __i, memory_order __s,
|
|
memory_order __f) volatile noexcept
|
|
{
|
|
return __atomic_compare_exchange(std::__addressof(_M_i),
|
|
std::__addressof(__e),
|
|
std::__addressof(__i),
|
|
false, int(__s), int(__f));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_strong(_Tp& __e, _Tp __i,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return compare_exchange_strong(__e, __i, __m,
|
|
__cmpexch_failure_order(__m)); }
|
|
|
|
bool
|
|
compare_exchange_strong(_Tp& __e, _Tp __i,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return compare_exchange_strong(__e, __i, __m,
|
|
__cmpexch_failure_order(__m)); }
|
|
|
|
#if __cpp_lib_atomic_wait
|
|
void
|
|
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
|
|
{
|
|
std::__atomic_wait_address_v(&_M_i, __old,
|
|
[__m, this] { return this->load(__m); });
|
|
}
|
|
|
|
// TODO add const volatile overload
|
|
|
|
void
|
|
notify_one() const noexcept
|
|
{ std::__atomic_notify_address(&_M_i, false); }
|
|
|
|
void
|
|
notify_all() const noexcept
|
|
{ std::__atomic_notify_address(&_M_i, true); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
|
|
};
|
|
#undef _GLIBCXX20_INIT
|
|
|
|
/// Partial specialization for pointer types.
|
|
template<typename _Tp>
|
|
struct atomic<_Tp*>
|
|
{
|
|
using value_type = _Tp*;
|
|
using difference_type = ptrdiff_t;
|
|
|
|
typedef _Tp* __pointer_type;
|
|
typedef __atomic_base<_Tp*> __base_type;
|
|
__base_type _M_b;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__pointer_type __p) noexcept : _M_b(__p) { }
|
|
|
|
operator __pointer_type() const noexcept
|
|
{ return __pointer_type(_M_b); }
|
|
|
|
operator __pointer_type() const volatile noexcept
|
|
{ return __pointer_type(_M_b); }
|
|
|
|
__pointer_type
|
|
operator=(__pointer_type __p) noexcept
|
|
{ return _M_b.operator=(__p); }
|
|
|
|
__pointer_type
|
|
operator=(__pointer_type __p) volatile noexcept
|
|
{ return _M_b.operator=(__p); }
|
|
|
|
__pointer_type
|
|
operator++(int) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b++;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++(int) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b++;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--(int) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b--;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--(int) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b--;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++() noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return ++_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator++() volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return ++_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--() noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return --_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator--() volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return --_M_b;
|
|
}
|
|
|
|
__pointer_type
|
|
operator+=(ptrdiff_t __d) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator+=(__d);
|
|
}
|
|
|
|
__pointer_type
|
|
operator+=(ptrdiff_t __d) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator+=(__d);
|
|
}
|
|
|
|
__pointer_type
|
|
operator-=(ptrdiff_t __d) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator-=(__d);
|
|
}
|
|
|
|
__pointer_type
|
|
operator-=(ptrdiff_t __d) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.operator-=(__d);
|
|
}
|
|
|
|
bool
|
|
is_lock_free() const noexcept
|
|
{ return _M_b.is_lock_free(); }
|
|
|
|
bool
|
|
is_lock_free() const volatile noexcept
|
|
{ return _M_b.is_lock_free(); }
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_POINTER_LOCK_FREE == 2;
|
|
#endif
|
|
|
|
void
|
|
store(__pointer_type __p,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_b.store(__p, __m); }
|
|
|
|
void
|
|
store(__pointer_type __p,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_b.store(__p, __m); }
|
|
|
|
__pointer_type
|
|
load(memory_order __m = memory_order_seq_cst) const noexcept
|
|
{ return _M_b.load(__m); }
|
|
|
|
__pointer_type
|
|
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
|
|
{ return _M_b.load(__m); }
|
|
|
|
__pointer_type
|
|
exchange(__pointer_type __p,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{ return _M_b.exchange(__p, __m); }
|
|
|
|
__pointer_type
|
|
exchange(__pointer_type __p,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{ return _M_b.exchange(__p, __m); }
|
|
|
|
bool
|
|
compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m1, memory_order __m2) noexcept
|
|
{ return _M_b.compare_exchange_strong(__p1, __p2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m1,
|
|
memory_order __m2) volatile noexcept
|
|
{ return _M_b.compare_exchange_strong(__p1, __p2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
return compare_exchange_weak(__p1, __p2, __m,
|
|
__cmpexch_failure_order(__m));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_weak(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
return compare_exchange_weak(__p1, __p2, __m,
|
|
__cmpexch_failure_order(__m));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m1, memory_order __m2) noexcept
|
|
{ return _M_b.compare_exchange_strong(__p1, __p2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m1,
|
|
memory_order __m2) volatile noexcept
|
|
{ return _M_b.compare_exchange_strong(__p1, __p2, __m1, __m2); }
|
|
|
|
bool
|
|
compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
return _M_b.compare_exchange_strong(__p1, __p2, __m,
|
|
__cmpexch_failure_order(__m));
|
|
}
|
|
|
|
bool
|
|
compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
return _M_b.compare_exchange_strong(__p1, __p2, __m,
|
|
__cmpexch_failure_order(__m));
|
|
}
|
|
|
|
#if __cpp_lib_atomic_wait
|
|
void
|
|
wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
|
|
{ _M_b.wait(__old, __m); }
|
|
|
|
// TODO add const volatile overload
|
|
|
|
void
|
|
notify_one() const noexcept
|
|
{ _M_b.notify_one(); }
|
|
|
|
void
|
|
notify_all() const noexcept
|
|
{ _M_b.notify_all(); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
__pointer_type
|
|
fetch_add(ptrdiff_t __d,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.fetch_add(__d, __m);
|
|
}
|
|
|
|
__pointer_type
|
|
fetch_add(ptrdiff_t __d,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.fetch_add(__d, __m);
|
|
}
|
|
|
|
__pointer_type
|
|
fetch_sub(ptrdiff_t __d,
|
|
memory_order __m = memory_order_seq_cst) noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.fetch_sub(__d, __m);
|
|
}
|
|
|
|
__pointer_type
|
|
fetch_sub(ptrdiff_t __d,
|
|
memory_order __m = memory_order_seq_cst) volatile noexcept
|
|
{
|
|
#if __cplusplus >= 201703L
|
|
static_assert( is_object<_Tp>::value, "pointer to object type" );
|
|
#endif
|
|
return _M_b.fetch_sub(__d, __m);
|
|
}
|
|
};
|
|
|
|
|
|
/// Explicit specialization for char.
|
|
template<>
|
|
struct atomic<char> : __atomic_base<char>
|
|
{
|
|
typedef char __integral_type;
|
|
typedef __atomic_base<char> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for signed char.
|
|
template<>
|
|
struct atomic<signed char> : __atomic_base<signed char>
|
|
{
|
|
typedef signed char __integral_type;
|
|
typedef __atomic_base<signed char> __base_type;
|
|
|
|
atomic() noexcept= default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned char.
|
|
template<>
|
|
struct atomic<unsigned char> : __atomic_base<unsigned char>
|
|
{
|
|
typedef unsigned char __integral_type;
|
|
typedef __atomic_base<unsigned char> __base_type;
|
|
|
|
atomic() noexcept= default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for short.
|
|
template<>
|
|
struct atomic<short> : __atomic_base<short>
|
|
{
|
|
typedef short __integral_type;
|
|
typedef __atomic_base<short> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_SHORT_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned short.
|
|
template<>
|
|
struct atomic<unsigned short> : __atomic_base<unsigned short>
|
|
{
|
|
typedef unsigned short __integral_type;
|
|
typedef __atomic_base<unsigned short> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_SHORT_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for int.
|
|
template<>
|
|
struct atomic<int> : __atomic_base<int>
|
|
{
|
|
typedef int __integral_type;
|
|
typedef __atomic_base<int> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned int.
|
|
template<>
|
|
struct atomic<unsigned int> : __atomic_base<unsigned int>
|
|
{
|
|
typedef unsigned int __integral_type;
|
|
typedef __atomic_base<unsigned int> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for long.
|
|
template<>
|
|
struct atomic<long> : __atomic_base<long>
|
|
{
|
|
typedef long __integral_type;
|
|
typedef __atomic_base<long> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_LONG_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned long.
|
|
template<>
|
|
struct atomic<unsigned long> : __atomic_base<unsigned long>
|
|
{
|
|
typedef unsigned long __integral_type;
|
|
typedef __atomic_base<unsigned long> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_LONG_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for long long.
|
|
template<>
|
|
struct atomic<long long> : __atomic_base<long long>
|
|
{
|
|
typedef long long __integral_type;
|
|
typedef __atomic_base<long long> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_LLONG_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for unsigned long long.
|
|
template<>
|
|
struct atomic<unsigned long long> : __atomic_base<unsigned long long>
|
|
{
|
|
typedef unsigned long long __integral_type;
|
|
typedef __atomic_base<unsigned long long> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_LLONG_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for wchar_t.
|
|
template<>
|
|
struct atomic<wchar_t> : __atomic_base<wchar_t>
|
|
{
|
|
typedef wchar_t __integral_type;
|
|
typedef __atomic_base<wchar_t> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_WCHAR_T_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
#ifdef _GLIBCXX_USE_CHAR8_T
|
|
/// Explicit specialization for char8_t.
|
|
template<>
|
|
struct atomic<char8_t> : __atomic_base<char8_t>
|
|
{
|
|
typedef char8_t __integral_type;
|
|
typedef __atomic_base<char8_t> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus > 201402L
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR8_T_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
/// Explicit specialization for char16_t.
|
|
template<>
|
|
struct atomic<char16_t> : __atomic_base<char16_t>
|
|
{
|
|
typedef char16_t __integral_type;
|
|
typedef __atomic_base<char16_t> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR16_T_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
/// Explicit specialization for char32_t.
|
|
template<>
|
|
struct atomic<char32_t> : __atomic_base<char32_t>
|
|
{
|
|
typedef char32_t __integral_type;
|
|
typedef __atomic_base<char32_t> __base_type;
|
|
|
|
atomic() noexcept = default;
|
|
~atomic() noexcept = default;
|
|
atomic(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
|
|
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
|
|
|
|
using __base_type::operator __integral_type;
|
|
using __base_type::operator=;
|
|
|
|
#if __cplusplus >= 201703L
|
|
static constexpr bool is_always_lock_free = ATOMIC_CHAR32_T_LOCK_FREE == 2;
|
|
#endif
|
|
};
|
|
|
|
|
|
/// atomic_bool
|
|
typedef atomic<bool> atomic_bool;
|
|
|
|
/// atomic_char
|
|
typedef atomic<char> atomic_char;
|
|
|
|
/// atomic_schar
|
|
typedef atomic<signed char> atomic_schar;
|
|
|
|
/// atomic_uchar
|
|
typedef atomic<unsigned char> atomic_uchar;
|
|
|
|
/// atomic_short
|
|
typedef atomic<short> atomic_short;
|
|
|
|
/// atomic_ushort
|
|
typedef atomic<unsigned short> atomic_ushort;
|
|
|
|
/// atomic_int
|
|
typedef atomic<int> atomic_int;
|
|
|
|
/// atomic_uint
|
|
typedef atomic<unsigned int> atomic_uint;
|
|
|
|
/// atomic_long
|
|
typedef atomic<long> atomic_long;
|
|
|
|
/// atomic_ulong
|
|
typedef atomic<unsigned long> atomic_ulong;
|
|
|
|
/// atomic_llong
|
|
typedef atomic<long long> atomic_llong;
|
|
|
|
/// atomic_ullong
|
|
typedef atomic<unsigned long long> atomic_ullong;
|
|
|
|
/// atomic_wchar_t
|
|
typedef atomic<wchar_t> atomic_wchar_t;
|
|
|
|
#ifdef _GLIBCXX_USE_CHAR8_T
|
|
/// atomic_char8_t
|
|
typedef atomic<char8_t> atomic_char8_t;
|
|
#endif
|
|
|
|
/// atomic_char16_t
|
|
typedef atomic<char16_t> atomic_char16_t;
|
|
|
|
/// atomic_char32_t
|
|
typedef atomic<char32_t> atomic_char32_t;
|
|
|
|
#ifdef _GLIBCXX_USE_C99_STDINT_TR1
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 2441. Exact-width atomic typedefs should be provided
|
|
|
|
/// atomic_int8_t
|
|
typedef atomic<int8_t> atomic_int8_t;
|
|
|
|
/// atomic_uint8_t
|
|
typedef atomic<uint8_t> atomic_uint8_t;
|
|
|
|
/// atomic_int16_t
|
|
typedef atomic<int16_t> atomic_int16_t;
|
|
|
|
/// atomic_uint16_t
|
|
typedef atomic<uint16_t> atomic_uint16_t;
|
|
|
|
/// atomic_int32_t
|
|
typedef atomic<int32_t> atomic_int32_t;
|
|
|
|
/// atomic_uint32_t
|
|
typedef atomic<uint32_t> atomic_uint32_t;
|
|
|
|
/// atomic_int64_t
|
|
typedef atomic<int64_t> atomic_int64_t;
|
|
|
|
/// atomic_uint64_t
|
|
typedef atomic<uint64_t> atomic_uint64_t;
|
|
|
|
|
|
/// atomic_int_least8_t
|
|
typedef atomic<int_least8_t> atomic_int_least8_t;
|
|
|
|
/// atomic_uint_least8_t
|
|
typedef atomic<uint_least8_t> atomic_uint_least8_t;
|
|
|
|
/// atomic_int_least16_t
|
|
typedef atomic<int_least16_t> atomic_int_least16_t;
|
|
|
|
/// atomic_uint_least16_t
|
|
typedef atomic<uint_least16_t> atomic_uint_least16_t;
|
|
|
|
/// atomic_int_least32_t
|
|
typedef atomic<int_least32_t> atomic_int_least32_t;
|
|
|
|
/// atomic_uint_least32_t
|
|
typedef atomic<uint_least32_t> atomic_uint_least32_t;
|
|
|
|
/// atomic_int_least64_t
|
|
typedef atomic<int_least64_t> atomic_int_least64_t;
|
|
|
|
/// atomic_uint_least64_t
|
|
typedef atomic<uint_least64_t> atomic_uint_least64_t;
|
|
|
|
|
|
/// atomic_int_fast8_t
|
|
typedef atomic<int_fast8_t> atomic_int_fast8_t;
|
|
|
|
/// atomic_uint_fast8_t
|
|
typedef atomic<uint_fast8_t> atomic_uint_fast8_t;
|
|
|
|
/// atomic_int_fast16_t
|
|
typedef atomic<int_fast16_t> atomic_int_fast16_t;
|
|
|
|
/// atomic_uint_fast16_t
|
|
typedef atomic<uint_fast16_t> atomic_uint_fast16_t;
|
|
|
|
/// atomic_int_fast32_t
|
|
typedef atomic<int_fast32_t> atomic_int_fast32_t;
|
|
|
|
/// atomic_uint_fast32_t
|
|
typedef atomic<uint_fast32_t> atomic_uint_fast32_t;
|
|
|
|
/// atomic_int_fast64_t
|
|
typedef atomic<int_fast64_t> atomic_int_fast64_t;
|
|
|
|
/// atomic_uint_fast64_t
|
|
typedef atomic<uint_fast64_t> atomic_uint_fast64_t;
|
|
#endif
|
|
|
|
|
|
/// atomic_intptr_t
|
|
typedef atomic<intptr_t> atomic_intptr_t;
|
|
|
|
/// atomic_uintptr_t
|
|
typedef atomic<uintptr_t> atomic_uintptr_t;
|
|
|
|
/// atomic_size_t
|
|
typedef atomic<size_t> atomic_size_t;
|
|
|
|
/// atomic_ptrdiff_t
|
|
typedef atomic<ptrdiff_t> atomic_ptrdiff_t;
|
|
|
|
#ifdef _GLIBCXX_USE_C99_STDINT_TR1
|
|
/// atomic_intmax_t
|
|
typedef atomic<intmax_t> atomic_intmax_t;
|
|
|
|
/// atomic_uintmax_t
|
|
typedef atomic<uintmax_t> atomic_uintmax_t;
|
|
#endif
|
|
|
|
// Function definitions, atomic_flag operations.
|
|
inline bool
|
|
atomic_flag_test_and_set_explicit(atomic_flag* __a,
|
|
memory_order __m) noexcept
|
|
{ return __a->test_and_set(__m); }
|
|
|
|
inline bool
|
|
atomic_flag_test_and_set_explicit(volatile atomic_flag* __a,
|
|
memory_order __m) noexcept
|
|
{ return __a->test_and_set(__m); }
|
|
|
|
inline void
|
|
atomic_flag_clear_explicit(atomic_flag* __a, memory_order __m) noexcept
|
|
{ __a->clear(__m); }
|
|
|
|
inline void
|
|
atomic_flag_clear_explicit(volatile atomic_flag* __a,
|
|
memory_order __m) noexcept
|
|
{ __a->clear(__m); }
|
|
|
|
inline bool
|
|
atomic_flag_test_and_set(atomic_flag* __a) noexcept
|
|
{ return atomic_flag_test_and_set_explicit(__a, memory_order_seq_cst); }
|
|
|
|
inline bool
|
|
atomic_flag_test_and_set(volatile atomic_flag* __a) noexcept
|
|
{ return atomic_flag_test_and_set_explicit(__a, memory_order_seq_cst); }
|
|
|
|
inline void
|
|
atomic_flag_clear(atomic_flag* __a) noexcept
|
|
{ atomic_flag_clear_explicit(__a, memory_order_seq_cst); }
|
|
|
|
inline void
|
|
atomic_flag_clear(volatile atomic_flag* __a) noexcept
|
|
{ atomic_flag_clear_explicit(__a, memory_order_seq_cst); }
|
|
|
|
|
|
template<typename _Tp>
|
|
using __atomic_val_t = typename atomic<_Tp>::value_type;
|
|
template<typename _Tp>
|
|
using __atomic_diff_t = typename atomic<_Tp>::difference_type;
|
|
|
|
// [atomics.nonmembers] Non-member functions.
|
|
// Function templates generally applicable to atomic types.
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_is_lock_free(const atomic<_ITp>* __a) noexcept
|
|
{ return __a->is_lock_free(); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_is_lock_free(const volatile atomic<_ITp>* __a) noexcept
|
|
{ return __a->is_lock_free(); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_init(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ __a->store(__i, memory_order_relaxed); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_init(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ __a->store(__i, memory_order_relaxed); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_store_explicit(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ __a->store(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_store_explicit(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ __a->store(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_load_explicit(const atomic<_ITp>* __a, memory_order __m) noexcept
|
|
{ return __a->load(__m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_load_explicit(const volatile atomic<_ITp>* __a,
|
|
memory_order __m) noexcept
|
|
{ return __a->load(__m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_exchange_explicit(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->exchange(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_exchange_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->exchange(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_weak_explicit(atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2,
|
|
memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return __a->compare_exchange_weak(*__i1, __i2, __m1, __m2); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_weak_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2,
|
|
memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return __a->compare_exchange_weak(*__i1, __i2, __m1, __m2); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_strong_explicit(atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2,
|
|
memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return __a->compare_exchange_strong(*__i1, __i2, __m1, __m2); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_strong_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2,
|
|
memory_order __m1,
|
|
memory_order __m2) noexcept
|
|
{ return __a->compare_exchange_strong(*__i1, __i2, __m1, __m2); }
|
|
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_store(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ atomic_store_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline void
|
|
atomic_store(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ atomic_store_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_load(const atomic<_ITp>* __a) noexcept
|
|
{ return atomic_load_explicit(__a, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_load(const volatile atomic<_ITp>* __a) noexcept
|
|
{ return atomic_load_explicit(__a, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_exchange(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_exchange_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_exchange(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_exchange_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_weak(atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2) noexcept
|
|
{
|
|
return atomic_compare_exchange_weak_explicit(__a, __i1, __i2,
|
|
memory_order_seq_cst,
|
|
memory_order_seq_cst);
|
|
}
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_weak(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2) noexcept
|
|
{
|
|
return atomic_compare_exchange_weak_explicit(__a, __i1, __i2,
|
|
memory_order_seq_cst,
|
|
memory_order_seq_cst);
|
|
}
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_strong(atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2) noexcept
|
|
{
|
|
return atomic_compare_exchange_strong_explicit(__a, __i1, __i2,
|
|
memory_order_seq_cst,
|
|
memory_order_seq_cst);
|
|
}
|
|
|
|
template<typename _ITp>
|
|
inline bool
|
|
atomic_compare_exchange_strong(volatile atomic<_ITp>* __a,
|
|
__atomic_val_t<_ITp>* __i1,
|
|
__atomic_val_t<_ITp> __i2) noexcept
|
|
{
|
|
return atomic_compare_exchange_strong_explicit(__a, __i1, __i2,
|
|
memory_order_seq_cst,
|
|
memory_order_seq_cst);
|
|
}
|
|
|
|
|
|
#if __cpp_lib_atomic_wait
|
|
template<typename _Tp>
|
|
inline void
|
|
atomic_wait(const atomic<_Tp>* __a,
|
|
typename std::atomic<_Tp>::value_type __old) noexcept
|
|
{ __a->wait(__old); }
|
|
|
|
template<typename _Tp>
|
|
inline void
|
|
atomic_wait_explicit(const atomic<_Tp>* __a,
|
|
typename std::atomic<_Tp>::value_type __old,
|
|
std::memory_order __m) noexcept
|
|
{ __a->wait(__old, __m); }
|
|
|
|
template<typename _Tp>
|
|
inline void
|
|
atomic_notify_one(atomic<_Tp>* __a) noexcept
|
|
{ __a->notify_one(); }
|
|
|
|
template<typename _Tp>
|
|
inline void
|
|
atomic_notify_all(atomic<_Tp>* __a) noexcept
|
|
{ __a->notify_all(); }
|
|
#endif // __cpp_lib_atomic_wait
|
|
|
|
// Function templates for atomic_integral and atomic_pointer operations only.
|
|
// Some operations (and, or, xor) are only available for atomic integrals,
|
|
// which is implemented by taking a parameter of type __atomic_base<_ITp>*.
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_add_explicit(atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_add(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_add_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_add(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_sub_explicit(atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_sub(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_sub_explicit(volatile atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_sub(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_and_explicit(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_and(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_and_explicit(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_and(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_or_explicit(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_or(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_or_explicit(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_or(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_xor_explicit(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_xor(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_xor_explicit(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i,
|
|
memory_order __m) noexcept
|
|
{ return __a->fetch_xor(__i, __m); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_add(atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_add_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_add(volatile atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_add_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_sub(atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_sub_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_sub(volatile atomic<_ITp>* __a,
|
|
__atomic_diff_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_sub_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_and(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_and_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_and(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_and_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_or(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_or_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_or(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_or_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_xor(__atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
template<typename _ITp>
|
|
inline _ITp
|
|
atomic_fetch_xor(volatile __atomic_base<_ITp>* __a,
|
|
__atomic_val_t<_ITp> __i) noexcept
|
|
{ return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
|
|
|
|
#if __cplusplus > 201703L
|
|
#define __cpp_lib_atomic_float 201711L
|
|
template<>
|
|
struct atomic<float> : __atomic_float<float>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(float __fp) noexcept : __atomic_float<float>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<float>::operator=;
|
|
};
|
|
|
|
template<>
|
|
struct atomic<double> : __atomic_float<double>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(double __fp) noexcept : __atomic_float<double>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<double>::operator=;
|
|
};
|
|
|
|
template<>
|
|
struct atomic<long double> : __atomic_float<long double>
|
|
{
|
|
atomic() noexcept = default;
|
|
|
|
constexpr
|
|
atomic(long double __fp) noexcept : __atomic_float<long double>(__fp)
|
|
{ }
|
|
|
|
atomic& operator=(const atomic&) volatile = delete;
|
|
atomic& operator=(const atomic&) = delete;
|
|
|
|
using __atomic_float<long double>::operator=;
|
|
};
|
|
|
|
#define __cpp_lib_atomic_ref 201806L
|
|
|
|
/// Class template to provide atomic operations on a non-atomic variable.
|
|
template<typename _Tp>
|
|
struct atomic_ref : __atomic_ref<_Tp>
|
|
{
|
|
explicit
|
|
atomic_ref(_Tp& __t) noexcept : __atomic_ref<_Tp>(__t)
|
|
{ }
|
|
|
|
atomic_ref& operator=(const atomic_ref&) = delete;
|
|
|
|
atomic_ref(const atomic_ref&) = default;
|
|
|
|
using __atomic_ref<_Tp>::operator=;
|
|
};
|
|
|
|
#endif // C++2a
|
|
|
|
/// @} group atomics
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace
|
|
|
|
#endif // C++11
|
|
|
|
#endif // _GLIBCXX_ATOMIC
|