From 80cfbfd0de8375a63564c0b28763dce4e255cd7d Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 7 Jun 2020 02:11:18 +0300 Subject: [PATCH] Added implementation of inter-process atomics. The inter-process atomics have ipc_ prefixes: ipc_atomic, ipc_atomic_ref and ipc_atomic_flag. These types are similar to their unprefixed counterparts with the following distinctions: - The operations are provided with an added precondition that is_lock_free() returns true. - All operations, including waiting/notifying operations, are address-free, so the types are suitable for inter-process communication. - The new has_native_wait_notify() operation and always_has_native_wait_notify static constant allow to test if the target platform has native support for address-free waiting/notifying operations. If it does not, a generic implementation is used based on a busy wait. - The new set of capability macros added. The macros are named BOOST_ATOMIC_HAS_NATIVE__IPC_WAIT_NOTIFY and indicate whether address-free waiting/notifying operations are supported natively for a given type. Additionally, to unify interface and implementation of different components, the has_native_wait_notify() operation and always_has_native_wait_notify static constant were added to non-IPC atomic types as well. Added BOOST_ATOMIC_HAS_NATIVE__WAIT_NOTIFY capability macros to indicate native support for inter-thread waiting/notifying operations. Also, added is_lock_free() and is_always_lock_free to atomic_flag. This commit adds implementation, docs and tests. --- doc/atomic.qbk | 78 +++- include/boost/atomic.hpp | 3 + include/boost/atomic/atomic.hpp | 4 +- include/boost/atomic/atomic_flag.hpp | 74 +--- include/boost/atomic/atomic_ref.hpp | 4 +- include/boost/atomic/capabilities.hpp | 1 + .../boost/atomic/detail/atomic_flag_impl.hpp | 126 ++++++ include/boost/atomic/detail/atomic_impl.hpp | 84 ++-- .../boost/atomic/detail/atomic_ref_impl.hpp | 77 ++-- .../atomic/detail/extra_fp_ops_emulated.hpp | 10 +- .../atomic/detail/extra_ops_emulated.hpp | 45 ++- .../boost/atomic/detail/fp_ops_emulated.hpp | 5 +- include/boost/atomic/detail/once_flag.hpp | 2 +- .../boost/atomic/detail/operations_fwd.hpp | 4 +- include/boost/atomic/detail/ops_emulated.hpp | 21 +- include/boost/atomic/detail/ops_gcc_alpha.hpp | 50 +-- include/boost/atomic/detail/ops_gcc_arm.hpp | 60 +-- .../boost/atomic/detail/ops_gcc_atomic.hpp | 105 ++--- include/boost/atomic/detail/ops_gcc_ppc.hpp | 60 +-- include/boost/atomic/detail/ops_gcc_sparc.hpp | 30 +- include/boost/atomic/detail/ops_gcc_sync.hpp | 53 +-- include/boost/atomic/detail/ops_gcc_x86.hpp | 67 ++-- .../boost/atomic/detail/ops_gcc_x86_dcas.hpp | 6 +- include/boost/atomic/detail/ops_linux_arm.hpp | 21 +- include/boost/atomic/detail/ops_msvc_arm.hpp | 35 +- include/boost/atomic/detail/ops_msvc_x86.hpp | 81 ++-- include/boost/atomic/detail/ops_windows.hpp | 23 +- .../boost/atomic/detail/wait_capabilities.hpp | 363 ++++++++++++++++++ .../detail/wait_caps_dragonfly_umtx.hpp | 30 ++ .../atomic/detail/wait_caps_freebsd_umtx.hpp | 40 ++ .../boost/atomic/detail/wait_caps_futex.hpp | 31 ++ .../boost/atomic/detail/wait_caps_windows.hpp | 55 +++ .../atomic/detail/wait_operations_fwd.hpp | 7 +- .../atomic/detail/wait_ops_dragonfly_umtx.hpp | 11 +- .../boost/atomic/detail/wait_ops_emulated.hpp | 19 +- .../atomic/detail/wait_ops_freebsd_umtx.hpp | 15 +- .../boost/atomic/detail/wait_ops_futex.hpp | 46 ++- .../boost/atomic/detail/wait_ops_generic.hpp | 67 +++- .../boost/atomic/detail/wait_ops_windows.hpp | 20 +- include/boost/atomic/ipc_atomic.hpp | 92 +++++ include/boost/atomic/ipc_atomic_flag.hpp | 37 ++ include/boost/atomic/ipc_atomic_ref.hpp | 92 +++++ src/lock_pool.cpp | 4 +- test/Jamfile.v2 | 4 + test/api_test_helpers.hpp | 57 ++- test/atomic_api.cpp | 2 +- test/atomic_wrapper.hpp | 30 +- test/ipc_atomic_api.cpp | 67 ++++ test/ipc_atomic_ref_api.cpp | 62 +++ test/ipc_wait_api.cpp | 39 ++ test/ipc_wait_ref_api.cpp | 34 ++ test/ipc_wait_test_helpers.hpp | 309 +++++++++++++++ test/wait_api.cpp | 4 +- test/wait_fuzz.cpp | 3 +- test/wait_ref_api.cpp | 3 +- test/wait_test_helpers.hpp | 3 +- 56 files changed, 2173 insertions(+), 502 deletions(-) create mode 100644 include/boost/atomic/detail/atomic_flag_impl.hpp create mode 100644 include/boost/atomic/detail/wait_capabilities.hpp create mode 100644 include/boost/atomic/detail/wait_caps_dragonfly_umtx.hpp create mode 100644 include/boost/atomic/detail/wait_caps_freebsd_umtx.hpp create mode 100644 include/boost/atomic/detail/wait_caps_futex.hpp create mode 100644 include/boost/atomic/detail/wait_caps_windows.hpp create mode 100644 include/boost/atomic/ipc_atomic.hpp create mode 100644 include/boost/atomic/ipc_atomic_flag.hpp create mode 100644 include/boost/atomic/ipc_atomic_ref.hpp create mode 100644 test/ipc_atomic_api.cpp create mode 100644 test/ipc_atomic_ref_api.cpp create mode 100644 test/ipc_wait_api.cpp create mode 100644 test/ipc_wait_ref_api.cpp create mode 100644 test/ipc_wait_test_helpers.hpp diff --git a/doc/atomic.qbk b/doc/atomic.qbk index ee3a3b6..50685be 100644 --- a/doc/atomic.qbk +++ b/doc/atomic.qbk @@ -98,7 +98,7 @@ As a consequence a program such as: x = 1; y = 1; - thread2 + thread2: if (y == 1) { assert(x == 1); } @@ -241,6 +241,13 @@ This provides the same ordering guarantees as previously, but elides a (possibly expensive) memory ordering operation in the case C is executed. +[note Atomic fences are only indended to constraint ordering of +regular and atomic loads and stores for the purpose of thread +synchronization. `atomic_thread_fence` is not intended to be used +to order some architecture-specific memory accesses, such as +non-temporal loads and stores on x86 or write combining memory +accesses. Use specialized instructions for these purposes.] + [endsect] [section:release_consume ['happens-before] through [^release] and [^consume]] @@ -481,6 +488,14 @@ following operations: [`atomic_flag()`] [Initialize to the clear state. See the discussion below.] ] + [ + [`bool is_lock_free()`] + [Checks if the atomic flag is lock-free; the returned value is consistent with the `is_always_lock_free` static constant, see below.] + ] + [ + [`bool has_native_wait_notify()`] + [Indicates if the target platform natively supports waiting and notifying operations for this object. Returns `true` if `always_has_native_wait_notify` is `true`.] + ] [ [`bool test(memory_order order)`] [Returns `true` if the flag is in the set state and `false` otherwise.] @@ -505,6 +520,14 @@ following operations: [`void notify_all()`] [Unblocks all threads blocked in waiting operations on this atomic object.] ] + [ + [`static constexpr bool is_always_lock_free`] + [This static boolean constant indicates if any atomic flag is lock-free] + ] + [ + [`static constexpr bool always_has_native_wait_notify`] + [Indicates if the target platform always natively supports waiting and notifying operations.] + ] ] `order` always has `memory_order_seq_cst` as default parameter. @@ -587,6 +610,10 @@ All atomic objects support the following operations and properties: [`bool is_lock_free()`] [Checks if the atomic object is lock-free; the returned value is consistent with the `is_always_lock_free` static constant, see below.] ] + [ + [`bool has_native_wait_notify()`] + [Indicates if the target platform natively supports waiting and notifying operations for this object. Returns `true` if `always_has_native_wait_notify` is `true`.] + ] [ [`T& value()`] [Returns a reference to the value stored in the atomic object.] @@ -645,6 +672,10 @@ All atomic objects support the following operations and properties: [`static constexpr bool is_always_lock_free`] [This static boolean constant indicates if any atomic object of this type is lock-free] ] + [ + [`static constexpr bool always_has_native_wait_notify`] + [Indicates if the target platform always natively supports waiting and notifying operations.] + ] ] `order` always has `memory_order_seq_cst` as default parameter. @@ -982,7 +1013,7 @@ constraint which always defaults to `memory_order_seq_cst`. [section:interface_atomic_convenience_typedefs [^boost::atomic<['T]>] convenience typedefs] -For convenience, several shorthand typedefs of [^boost::atomic<['T]>] are provided: +For convenience, the following shorthand typedefs of [^boost::atomic<['T]>] are provided: [c++] @@ -1001,6 +1032,7 @@ For convenience, several shorthand typedefs of [^boost::atomic<['T]>] are provid typedef atomic< void* > atomic_address; typedef atomic< bool > atomic_bool; typedef atomic< wchar_t > atomic_wchar_t; + typedef atomic< char8_t > atomic_char8_t; typedef atomic< char16_t > atomic_char16_t; typedef atomic< char32_t > atomic_char32_t; @@ -1038,7 +1070,7 @@ For convenience, several shorthand typedefs of [^boost::atomic<['T]>] are provid typedef atomic< intptr_t > atomic_intptr_t; typedef atomic< uintptr_t > atomic_uintptr_t; -The typedefs are provided only if the corresponding type is available. +The typedefs are provided only if the corresponding value type is available. [endsect] @@ -1204,16 +1236,42 @@ Notifying operations have the following forms: The `notify_one` operation unblocks at least one thread blocked in the waiting operation on the same atomic object, and `notify_all` unblocks all such threads. Notifying operations do not enforce memory ordering and should normally be preceeded with a store operation or a fence with the appropriate memory ordering constraint. -Waiting and notifying operations require special support from the operating system, which may not be universally available. Even for atomic objects that support lock-free operations (as indicated by the `is_always_lock_free` property or the corresponding [link atomic.interface.feature_macros macro]), the waiting and notifying operations may involve locking and require linking with [*Boost.Atomic] compiled library. +Waiting and notifying operations require special support from the operating system, which may not be universally available. Whether the operating system natively supports these operations is indicated by the `always_has_native_wait_notify` static constant and `has_native_wait_notify()` member function of a given atomic type. + +Even for atomic objects that support lock-free operations (as indicated by the `is_always_lock_free` property or the corresponding [link atomic.interface.feature_macros macro]), the waiting and notifying operations may involve locking and require linking with [*Boost.Atomic] compiled library. Waiting and notifying operations are not address-free, meaning that the implementation may use process-local state and process-local addresses of the atomic objects to implement the operations. In particular, this means these operations cannot be used for communication between processes (when the atomic object is located in shared memory) or when the atomic object is mapped at different memory addresses in the same process. [endsect] +[section:interface_ipc Atomic types for inter-process communication] + + #include + #include + #include + +[*Boost.Atomic] provides a dedicated set of types for inter-process communication: `boost::ipc_atomic_flag`, [^boost::ipc_atomic<['T]>] and [^boost::ipc_atomic_ref<['T]>]. Collectively, these types are called inter-process communication atomic types or IPC atomic types, and their counterparts without the `ipc_` prefix - non-IPC atomic types. + +Each of the IPC atomic types have the same requirements on their value types and provide the same set of operations and properties as its non-IPC counterpart. All operations have the same signature, requirements and effects, with the following amendments: + +* All operations, except constructors, destructors, `is_lock_free()` and `has_native_wait_notify()` have an additional precondition that `is_lock_free()` returns `true` for this atomic object. (Implementation note: The current implementation detects availability of atomic instructions at compile time, and the code that does not fulfull this requirement will fail to compile.) +* The `has_native_wait_notify()` method and `always_has_native_wait_notify` static constant indicate whether the operating system has native support for inter-process waiting and notifying operations. This may be different from non-IPC atomic types as the OS may have different capabilities for inter-thread and inter-process communication. +* All operations on objects of IPC atomic types are address-free, which allows to place such objects (in case of [^boost::ipc_atomic_ref<['T]>] - objects referenced by `ipc_atomic_ref`) in memory regions shared between processes or mapped at different addresses in the same process. + +[note Operations on lock-free non-IPC atomic objects, except [link atomic.interface.interface_wait_notify_ops waiting and notifying operations], are also address-free, so `boost::atomic_flag`, [^boost::atomic<['T]>] and [^boost::atomic_ref<['T]>] could also be used for inter-process communication. However, the user must ensure that the given atomic object indeed supports lock-free operations. Failing to do this could result in a misbehaving program. IPC atomic types enforce this requirement and add support for address-free waiting and notifying operations.] + +It should be noted that some operations on IPC atomic types may be more expensive than the non-IPC ones. This primarily concerns waiting and notifying operations, as the operating system may have to perform conversion of the process-mapped addresses of atomic objects to physical addresses. Also, when native support for inter-process waiting and notifying operations is not present (as indicated by `has_native_wait_notify()`), waiting operations are emulated with a busy loop, which can affect performance and power consumption of the system. Native support for waiting and notifying operations can also be detected using [link atomic.interface.feature_macros capability macros]. + +Users must not create and use IPC and non-IPC atomic references on the same referenced object at the same time. IPC and non-IPC atomic references are not required to communicate with each other. For example, a waiting operation on a non-IPC atomic reference may not be interrupted by a notifying operation on an IPC atomic reference referencing the same object. + +[endsect] + [section:interface_fences Fences] #include +[link atomic.thread_coordination.fences Fences] are implemented with the following operations: + [table [[Syntax] [Description]] [ @@ -1222,10 +1280,15 @@ Waiting and notifying operations are not address-free, meaning that the implemen ] [ [`void atomic_signal_fence(memory_order order)`] - [Issue fence for coordination with signal handler (only in same thread).] + [Issue fence for coordination with a signal handler (only in the same thread).] ] ] +Note that `atomic_signal_fence` does not implement thread synchronization +and only acts as a barrier to prevent code reordering by the compiler (but not by CPU). +The `order` argument here specifies the direction, in which the fence prevents the +compiler to reorder code. + [endsect] [section:feature_macros Feature testing macros] @@ -1357,6 +1420,8 @@ For floating-point types the following macros are similarly defined: These macros are not defined when support for floating point types is disabled by user. +For any of the [^BOOST_ATOMIC_['X]_LOCK_FREE] macro described above, two additional macros named [^BOOST_ATOMIC_HAS_NATIVE_['X]_WAIT_NOTIFY] and [^BOOST_ATOMIC_HAS_NATIVE_['X]_IPC_WAIT_NOTIFY] are defined. The former indicates whether [link atomic.interface.interface_wait_notify_ops waiting and notifying operations] are supported natively for non-IPC atomic types of a given type, and the latter does the same for [link atomic.interface.interface_ipc IPC atomic types]. The macros take values of `0`, `1` or `2`, where `0` indicates that native operations are not available, `1` means the operations may be available (which is determined at run time) and `2` means always available. Note that the lock-free and native waiting/notifying operations macros for a given type may have different values. + [endsect] [endsect] @@ -1499,6 +1564,9 @@ implementation behaves as expected: and then wake up one or all of them for a number of times. This test is intended as a smoke test in case if the implementation has long-term instabilities or races (primarily, in the lock pool implementation). +* [*ipc_atomic_api.cpp], [*ipc_atomic_ref_api.cpp], [*ipc_wait_api.cpp] + and [*ipc_wait_ref_api.cpp] are similar to the tests without the [*ipc_] + prefix, but test IPC atomic types. [endsect] diff --git a/include/boost/atomic.hpp b/include/boost/atomic.hpp index 1fd80d3..be239b3 100644 --- a/include/boost/atomic.hpp +++ b/include/boost/atomic.hpp @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include #ifdef BOOST_HAS_PRAGMA_ONCE diff --git a/include/boost/atomic/atomic.hpp b/include/boost/atomic/atomic.hpp index 7ab2a4f..4683f85 100644 --- a/include/boost/atomic/atomic.hpp +++ b/include/boost/atomic/atomic.hpp @@ -42,10 +42,10 @@ namespace atomics { //! Atomic object template< typename T > class atomic : - public atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type > + public atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type, false > { private: - typedef atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type > base_type; + typedef atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type, false > base_type; typedef typename base_type::value_arg_type value_arg_type; public: diff --git a/include/boost/atomic/atomic_flag.hpp b/include/boost/atomic/atomic_flag.hpp index 8cd984f..b91bfd9 100644 --- a/include/boost/atomic/atomic_flag.hpp +++ b/include/boost/atomic/atomic_flag.hpp @@ -5,7 +5,7 @@ * * Copyright (c) 2011 Helge Bahmann * Copyright (c) 2013 Tim Blechmann - * Copyright (c) 2014 Andrey Semashev + * Copyright (c) 2014, 2020 Andrey Semashev */ /*! * \file atomic/atomic_flag.hpp @@ -16,87 +16,19 @@ #ifndef BOOST_ATOMIC_ATOMIC_FLAG_HPP_INCLUDED_ #define BOOST_ATOMIC_ATOMIC_FLAG_HPP_INCLUDED_ -#include -#include #include #include -#include -#include -#include +#include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once #endif -/* - * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, - * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. - */ - namespace boost { namespace atomics { -#if defined(BOOST_ATOMIC_DETAIL_NO_CXX11_CONSTEXPR_UNION_INIT) || defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) -#define BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT -#else -#define BOOST_ATOMIC_FLAG_INIT {} -#endif - //! Atomic flag -struct atomic_flag -{ - // Prefer 4-byte storage as most platforms support waiting/notifying operations without a lock pool for 32-bit integers - typedef atomics::detail::operations< 4u, false > operations; - typedef atomics::detail::wait_operations< operations > wait_operations; - typedef operations::storage_type storage_type; - - BOOST_ATOMIC_DETAIL_ALIGNED_VAR(operations::storage_alignment, storage_type, m_storage); - - BOOST_FORCEINLINE BOOST_ATOMIC_DETAIL_CONSTEXPR_UNION_INIT atomic_flag() BOOST_NOEXCEPT : m_storage(0u) - { - } - - BOOST_FORCEINLINE bool test(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT - { - BOOST_ASSERT(order != memory_order_release); - BOOST_ASSERT(order != memory_order_acq_rel); - return !!operations::load(m_storage, order); - } - - BOOST_FORCEINLINE bool test_and_set(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT - { - return operations::test_and_set(m_storage, order); - } - - BOOST_FORCEINLINE void clear(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT - { - BOOST_ASSERT(order != memory_order_consume); - BOOST_ASSERT(order != memory_order_acquire); - BOOST_ASSERT(order != memory_order_acq_rel); - operations::clear(m_storage, order); - } - - BOOST_FORCEINLINE bool wait(bool old_val, memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT - { - BOOST_ASSERT(order != memory_order_release); - BOOST_ASSERT(order != memory_order_acq_rel); - - return !!wait_operations::wait(m_storage, static_cast< storage_type >(old_val), order); - } - - BOOST_FORCEINLINE void notify_one() volatile BOOST_NOEXCEPT - { - wait_operations::notify_one(m_storage); - } - - BOOST_FORCEINLINE void notify_all() volatile BOOST_NOEXCEPT - { - wait_operations::notify_all(m_storage); - } - - BOOST_DELETED_FUNCTION(atomic_flag(atomic_flag const&)) - BOOST_DELETED_FUNCTION(atomic_flag& operator= (atomic_flag const&)) -}; +typedef atomics::detail::atomic_flag_impl< false > atomic_flag; } // namespace atomics diff --git a/include/boost/atomic/atomic_ref.hpp b/include/boost/atomic/atomic_ref.hpp index 11accb3..7adbf6d 100644 --- a/include/boost/atomic/atomic_ref.hpp +++ b/include/boost/atomic/atomic_ref.hpp @@ -40,10 +40,10 @@ namespace atomics { //! Atomic reference to external object template< typename T > class atomic_ref : - public atomics::detail::base_atomic_ref< T, typename atomics::detail::classify< T >::type > + public atomics::detail::base_atomic_ref< T, typename atomics::detail::classify< T >::type, false > { private: - typedef atomics::detail::base_atomic_ref< T, typename atomics::detail::classify< T >::type > base_type; + typedef atomics::detail::base_atomic_ref< T, typename atomics::detail::classify< T >::type, false > base_type; typedef typename base_type::value_arg_type value_arg_type; public: diff --git a/include/boost/atomic/capabilities.hpp b/include/boost/atomic/capabilities.hpp index 653adfc..a17bde4 100644 --- a/include/boost/atomic/capabilities.hpp +++ b/include/boost/atomic/capabilities.hpp @@ -16,5 +16,6 @@ #include #include +#include #endif // BOOST_ATOMIC_CAPABILITIES_HPP_INCLUDED_ diff --git a/include/boost/atomic/detail/atomic_flag_impl.hpp b/include/boost/atomic/detail/atomic_flag_impl.hpp new file mode 100644 index 0000000..0374bfd --- /dev/null +++ b/include/boost/atomic/detail/atomic_flag_impl.hpp @@ -0,0 +1,126 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014, 2020 Andrey Semashev + */ +/*! + * \file atomic/detail/atomic_flag_impl.hpp + * + * This header contains implementation of \c atomic_flag. + */ + +#ifndef BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_IMPL_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_IMPL_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* + * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, + * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. + */ + +namespace boost { +namespace atomics { +namespace detail { + +#if defined(BOOST_ATOMIC_DETAIL_NO_CXX11_CONSTEXPR_UNION_INIT) || defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) +#define BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT +#else +#define BOOST_ATOMIC_FLAG_INIT {} +#endif + +//! Atomic flag implementation +template< bool IsInterprocess > +struct atomic_flag_impl +{ + // Prefer 4-byte storage as most platforms support waiting/notifying operations without a lock pool for 32-bit integers + typedef atomics::detail::operations< 4u, false, IsInterprocess > operations; + typedef atomics::detail::wait_operations< operations > wait_operations; + typedef typename operations::storage_type storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = operations::is_always_lock_free; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = wait_operations::always_has_native_wait_notify; + + BOOST_ATOMIC_DETAIL_ALIGNED_VAR_TPL(operations::storage_alignment, storage_type, m_storage); + + BOOST_FORCEINLINE BOOST_ATOMIC_DETAIL_CONSTEXPR_UNION_INIT atomic_flag_impl() BOOST_NOEXCEPT : m_storage(0u) + { + } + + BOOST_FORCEINLINE bool is_lock_free() const volatile BOOST_NOEXCEPT + { + return is_always_lock_free; + } + + BOOST_FORCEINLINE bool has_native_wait_notify() const volatile BOOST_NOEXCEPT + { + return wait_operations::has_native_wait_notify(m_storage); + } + + BOOST_FORCEINLINE bool test(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + return !!operations::load(m_storage, order); + } + + BOOST_FORCEINLINE bool test_and_set(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return operations::test_and_set(m_storage, order); + } + + BOOST_FORCEINLINE void clear(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + operations::clear(m_storage, order); + } + + BOOST_FORCEINLINE bool wait(bool old_val, memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return !!wait_operations::wait(m_storage, static_cast< storage_type >(old_val), order); + } + + BOOST_FORCEINLINE void notify_one() volatile BOOST_NOEXCEPT + { + wait_operations::notify_one(m_storage); + } + + BOOST_FORCEINLINE void notify_all() volatile BOOST_NOEXCEPT + { + wait_operations::notify_all(m_storage); + } + + BOOST_DELETED_FUNCTION(atomic_flag_impl(atomic_flag_impl const&)) + BOOST_DELETED_FUNCTION(atomic_flag_impl& operator= (atomic_flag_impl const&)) +}; + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) +template< bool IsInterprocess > +BOOST_CONSTEXPR_OR_CONST bool atomic_flag_impl< IsInterprocess >::is_always_lock_free; +template< bool IsInterprocess > +BOOST_CONSTEXPR_OR_CONST bool atomic_flag_impl< IsInterprocess >::always_has_native_wait_notify; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_IMPL_HPP_INCLUDED_ diff --git a/include/boost/atomic/detail/atomic_impl.hpp b/include/boost/atomic/detail/atomic_impl.hpp index 6ac963c..aa542d0 100644 --- a/include/boost/atomic/detail/atomic_impl.hpp +++ b/include/boost/atomic/detail/atomic_impl.hpp @@ -59,14 +59,14 @@ namespace boost { namespace atomics { namespace detail { -template< typename T, bool IsSigned > +template< typename T, bool Signed, bool Interprocess > class base_atomic_common { public: typedef T value_type; protected: - typedef atomics::detail::operations< storage_size_of< value_type >::value, IsSigned > operations; + typedef atomics::detail::operations< storage_size_of< value_type >::value, Signed, Interprocess > operations; typedef atomics::detail::wait_operations< operations > wait_operations; typedef typename atomics::detail::conditional< sizeof(value_type) <= sizeof(void*), value_type, value_type const& >::type value_arg_type; typedef typename operations::storage_type storage_type; @@ -76,6 +76,7 @@ protected: public: static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = operations::is_always_lock_free; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = wait_operations::always_has_native_wait_notify; protected: BOOST_ATOMIC_DETAIL_ALIGNED_VAR_TPL(storage_alignment, storage_type, m_storage); @@ -105,6 +106,11 @@ public: return is_always_lock_free; } + BOOST_FORCEINLINE bool has_native_wait_notify() const volatile BOOST_NOEXCEPT + { + return wait_operations::has_native_wait_notify(this->storage()); + } + BOOST_FORCEINLINE void notify_one() volatile BOOST_NOEXCEPT { wait_operations::notify_one(this->storage()); @@ -117,20 +123,22 @@ public: }; #if defined(BOOST_NO_CXX17_INLINE_VARIABLES) -template< typename T, bool IsSigned > -BOOST_CONSTEXPR_OR_CONST bool base_atomic_common< T, IsSigned >::is_always_lock_free; +template< typename T, bool Signed, bool Interprocess > +BOOST_CONSTEXPR_OR_CONST bool base_atomic_common< T, Signed, Interprocess >::is_always_lock_free; +template< typename T, bool Signed, bool Interprocess > +BOOST_CONSTEXPR_OR_CONST bool base_atomic_common< T, Signed, Interprocess >::always_has_native_wait_notify; #endif -template< typename T, bool IsTriviallyDefaultConstructible = atomics::detail::is_trivially_default_constructible< T >::value > +template< typename T, bool Interprocess, bool IsTriviallyDefaultConstructible = atomics::detail::is_trivially_default_constructible< T >::value > class base_atomic_generic; -template< typename T > -class base_atomic_generic< T, true > : - public base_atomic_common< T, false > +template< typename T, bool Interprocess > +class base_atomic_generic< T, Interprocess, true > : + public base_atomic_common< T, false, Interprocess > { private: - typedef base_atomic_common< T, false > base_type; + typedef base_atomic_common< T, false, Interprocess > base_type; protected: typedef typename base_type::storage_type storage_type; @@ -143,12 +151,12 @@ public: } }; -template< typename T > -class base_atomic_generic< T, false > : - public base_atomic_common< T, false > +template< typename T, bool Interprocess > +class base_atomic_generic< T, Interprocess, false > : + public base_atomic_common< T, false, Interprocess > { private: - typedef base_atomic_common< T, false > base_type; + typedef base_atomic_common< T, false, Interprocess > base_type; public: typedef typename base_type::value_type value_type; @@ -164,16 +172,16 @@ public: }; -template< typename T, typename Kind > +template< typename T, typename Kind, bool Interprocess > class base_atomic; //! General template. Implementation for user-defined types, such as structs and enums, and pointers to non-object types -template< typename T > -class base_atomic< T, void > : - public base_atomic_generic< T > +template< typename T, bool Interprocess > +class base_atomic< T, void, Interprocess > : + public base_atomic_generic< T, Interprocess > { private: - typedef base_atomic_generic< T > base_type; + typedef base_atomic_generic< T, Interprocess > base_type; public: typedef typename base_type::value_type value_type; @@ -292,12 +300,12 @@ private: //! Implementation for integers -template< typename T > -class base_atomic< T, int > : - public base_atomic_common< T, atomics::detail::is_signed< T >::value > +template< typename T, bool Interprocess > +class base_atomic< T, int, Interprocess > : + public base_atomic_common< T, atomics::detail::is_signed< T >::value, Interprocess > { private: - typedef base_atomic_common< T, atomics::detail::is_signed< T >::value > base_type; + typedef base_atomic_common< T, atomics::detail::is_signed< T >::value, Interprocess > base_type; public: typedef typename base_type::value_type value_type; @@ -621,20 +629,20 @@ private: }; //! Implementation for bool -template< > -class base_atomic< bool, int > : - public base_atomic_common< bool, false > +template< bool Interprocess > +class base_atomic< bool, int, Interprocess > : + public base_atomic_common< bool, false, Interprocess > { private: - typedef base_atomic_common< bool, false > base_type; + typedef base_atomic_common< bool, false, Interprocess > base_type; public: - typedef base_type::value_type value_type; + typedef typename base_type::value_type value_type; protected: - typedef base_type::operations operations; - typedef base_type::wait_operations wait_operations; - typedef base_type::storage_type storage_type; + typedef typename base_type::operations operations; + typedef typename base_type::wait_operations wait_operations; + typedef typename base_type::storage_type storage_type; typedef value_type value_arg_type; private: @@ -746,12 +754,12 @@ private: #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) //! Implementation for floating point types -template< typename T > -class base_atomic< T, float > : - public base_atomic_common< T, false > +template< typename T, bool Interprocess > +class base_atomic< T, float, Interprocess > : + public base_atomic_common< T, false, Interprocess > { private: - typedef base_atomic_common< T, false > base_type; + typedef base_atomic_common< T, false, Interprocess > base_type; public: typedef typename base_type::value_type value_type; @@ -933,12 +941,12 @@ private: //! Implementation for pointers to object types -template< typename T > -class base_atomic< T*, void* > : - public base_atomic_common< T*, false > +template< typename T, bool Interprocess > +class base_atomic< T*, void*, Interprocess > : + public base_atomic_common< T*, false, Interprocess > { private: - typedef base_atomic_common< T*, false > base_type; + typedef base_atomic_common< T*, false, Interprocess > base_type; public: typedef typename base_type::value_type value_type; diff --git a/include/boost/atomic/detail/atomic_ref_impl.hpp b/include/boost/atomic/detail/atomic_ref_impl.hpp index e3f63cf..6007eff 100644 --- a/include/boost/atomic/detail/atomic_ref_impl.hpp +++ b/include/boost/atomic/detail/atomic_ref_impl.hpp @@ -54,17 +54,17 @@ namespace boost { namespace atomics { namespace detail { -template< typename T, bool IsSigned > +template< typename T, bool Signed, bool Interprocess > struct is_atomic_ref_lock_free { typedef T value_type; - typedef atomics::detail::operations< sizeof(value_type), IsSigned > operations; + typedef atomics::detail::operations< sizeof(value_type), Signed, Interprocess > operations; typedef typename operations::storage_type storage_type; static BOOST_CONSTEXPR_OR_CONST bool value = sizeof(value_type) == sizeof(storage_type) && operations::is_always_lock_free; }; -template< typename T, bool IsSigned > +template< typename T, bool Signed, bool Interprocess > class base_atomic_ref_common { public: @@ -72,9 +72,9 @@ public: protected: typedef typename atomics::detail::conditional< - atomics::detail::is_atomic_ref_lock_free< T, IsSigned >::value, - atomics::detail::operations< sizeof(value_type), IsSigned >, - atomics::detail::emulated_operations< sizeof(value_type), atomics::detail::alignment_of< value_type >::value, IsSigned > + atomics::detail::is_atomic_ref_lock_free< T, Signed, Interprocess >::value, + atomics::detail::operations< sizeof(value_type), Signed, Interprocess >, + atomics::detail::emulated_operations< sizeof(value_type), atomics::detail::alignment_of< value_type >::value, Signed, Interprocess > >::type operations; typedef atomics::detail::wait_operations< operations > wait_operations; typedef typename atomics::detail::conditional< sizeof(value_type) <= sizeof(void*), value_type, value_type const& >::type value_arg_type; @@ -84,6 +84,7 @@ protected: public: static BOOST_CONSTEXPR_OR_CONST std::size_t required_alignment = atomics::detail::alignment_of< value_type >::value <= operations::storage_alignment ? operations::storage_alignment : atomics::detail::alignment_of< value_type >::value; static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = operations::is_always_lock_free; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = wait_operations::always_has_native_wait_notify; protected: value_type* m_value; @@ -110,6 +111,11 @@ public: return is_always_lock_free; } + BOOST_FORCEINLINE bool has_native_wait_notify() const BOOST_NOEXCEPT + { + return wait_operations::has_native_wait_notify(this->storage()); + } + BOOST_FORCEINLINE void notify_one() const BOOST_NOEXCEPT { wait_operations::notify_one(this->storage()); @@ -122,23 +128,25 @@ public: }; #if defined(BOOST_NO_CXX17_INLINE_VARIABLES) -template< typename T, bool IsSigned > -BOOST_CONSTEXPR_OR_CONST std::size_t base_atomic_ref_common< T, IsSigned >::required_alignment; -template< typename T, bool IsSigned > -BOOST_CONSTEXPR_OR_CONST bool base_atomic_ref_common< T, IsSigned >::is_always_lock_free; +template< typename T, bool Signed, bool Interprocess > +BOOST_CONSTEXPR_OR_CONST std::size_t base_atomic_ref_common< T, Signed, Interprocess >::required_alignment; +template< typename T, bool Signed, bool Interprocess > +BOOST_CONSTEXPR_OR_CONST bool base_atomic_ref_common< T, Signed, Interprocess >::is_always_lock_free; +template< typename T, bool Signed, bool Interprocess > +BOOST_CONSTEXPR_OR_CONST bool base_atomic_ref_common< T, Signed, Interprocess >::always_has_native_wait_notify; #endif -template< typename T, typename Kind > +template< typename T, typename Kind, bool Interprocess > class base_atomic_ref; //! General template. Implementation for user-defined types, such as structs and enums, and pointers to non-object types -template< typename T > -class base_atomic_ref< T, void > : - public base_atomic_ref_common< T, false > +template< typename T, bool Interprocess > +class base_atomic_ref< T, void, Interprocess > : + public base_atomic_ref_common< T, false, Interprocess > { private: - typedef base_atomic_ref_common< T, false > base_type; + typedef base_atomic_ref_common< T, false, Interprocess > base_type; public: typedef typename base_type::value_type value_type; @@ -256,12 +264,12 @@ private: //! Implementation for integers -template< typename T > -class base_atomic_ref< T, int > : - public base_atomic_ref_common< T, atomics::detail::is_signed< T >::value > +template< typename T, bool Interprocess > +class base_atomic_ref< T, int, Interprocess > : + public base_atomic_ref_common< T, atomics::detail::is_signed< T >::value, Interprocess > { private: - typedef base_atomic_ref_common< T, atomics::detail::is_signed< T >::value > base_type; + typedef base_atomic_ref_common< T, atomics::detail::is_signed< T >::value, Interprocess > base_type; public: typedef typename base_type::value_type value_type; @@ -586,21 +594,20 @@ private: }; //! Implementation for bool -template< > -class base_atomic_ref< bool, int > : - public base_atomic_ref_common< bool, false > +template< bool Interprocess > +class base_atomic_ref< bool, int, Interprocess > : + public base_atomic_ref_common< bool, false, Interprocess > { private: - typedef base_atomic_ref_common< bool, false > base_type; + typedef base_atomic_ref_common< bool, false, Interprocess > base_type; public: typedef bool value_type; protected: - typedef base_type::operations operations; - typedef base_type::wait_operations wait_operations; - typedef atomics::detail::extra_operations< operations > extra_operations; - typedef base_type::storage_type storage_type; + typedef typename base_type::operations operations; + typedef typename base_type::wait_operations wait_operations; + typedef typename base_type::storage_type storage_type; typedef value_type value_arg_type; private: @@ -713,12 +720,12 @@ private: #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) //! Implementation for floating point types -template< typename T > -class base_atomic_ref< T, float > : - public base_atomic_ref_common< T, false > +template< typename T, bool Interprocess > +class base_atomic_ref< T, float, Interprocess > : + public base_atomic_ref_common< T, false, Interprocess > { private: - typedef base_atomic_ref_common< T, false > base_type; + typedef base_atomic_ref_common< T, false, Interprocess > base_type; public: typedef typename base_type::value_type value_type; @@ -918,12 +925,12 @@ private: //! Implementation for pointers to object types -template< typename T > -class base_atomic_ref< T*, void* > : - public base_atomic_ref_common< T*, false > +template< typename T, bool Interprocess > +class base_atomic_ref< T*, void*, Interprocess > : + public base_atomic_ref_common< T*, false, Interprocess > { private: - typedef base_atomic_ref_common< T*, false > base_type; + typedef base_atomic_ref_common< T*, false, Interprocess > base_type; public: typedef typename base_type::value_type value_type; diff --git a/include/boost/atomic/detail/extra_fp_ops_emulated.hpp b/include/boost/atomic/detail/extra_fp_ops_emulated.hpp index 043ee13..427da10 100644 --- a/include/boost/atomic/detail/extra_fp_ops_emulated.hpp +++ b/include/boost/atomic/detail/extra_fp_ops_emulated.hpp @@ -15,6 +15,7 @@ #define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_ #include +#include #include #include #include @@ -28,7 +29,7 @@ namespace boost { namespace atomics { namespace detail { -//! Generic implementation of extra floating point operations +//! Emulated implementation of extra floating point operations template< typename Base, typename Value, std::size_t Size > struct emulated_extra_fp_operations : public Base @@ -40,6 +41,7 @@ struct emulated_extra_fp_operations : static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); @@ -50,6 +52,7 @@ struct emulated_extra_fp_operations : static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); @@ -60,6 +63,7 @@ struct emulated_extra_fp_operations : static BOOST_FORCEINLINE value_type add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); @@ -70,6 +74,7 @@ struct emulated_extra_fp_operations : static BOOST_FORCEINLINE value_type sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); @@ -80,16 +85,19 @@ struct emulated_extra_fp_operations : static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); fetch_negate(storage, order); } static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); base_type::fetch_add(storage, v, order); } static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); base_type::fetch_sub(storage, v, order); } }; diff --git a/include/boost/atomic/detail/extra_ops_emulated.hpp b/include/boost/atomic/detail/extra_ops_emulated.hpp index 4c0e210..ccc2ff6 100644 --- a/include/boost/atomic/detail/extra_ops_emulated.hpp +++ b/include/boost/atomic/detail/extra_ops_emulated.hpp @@ -15,6 +15,7 @@ #define BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_ #include +#include #include #include #include @@ -34,7 +35,7 @@ namespace boost { namespace atomics { namespace detail { -//! Generic implementation of extra operations +//! Emulated implementation of extra operations template< typename Base, std::size_t Size, bool Signed > struct emulated_extra_operations : public Base @@ -45,6 +46,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -54,6 +56,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type new_val = static_cast< storage_type >(-s); @@ -63,6 +66,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type new_val = s; @@ -73,6 +77,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type new_val = s; @@ -83,6 +88,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type new_val = s; @@ -93,6 +99,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type new_val = s; @@ -103,6 +110,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type new_val = s; @@ -113,6 +121,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -122,6 +131,7 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type new_val = static_cast< storage_type >(~s); @@ -131,92 +141,109 @@ struct emulated_extra_operations : static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { - Base::fetch_add(storage, v, order); + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); + base_type::fetch_add(storage, v, order); } static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { - Base::fetch_sub(storage, v, order); + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); + base_type::fetch_sub(storage, v, order); } static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); fetch_negate(storage, order); } static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { - Base::fetch_and(storage, v, order); + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); + base_type::fetch_and(storage, v, order); } static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { - Base::fetch_or(storage, v, order); + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); + base_type::fetch_or(storage, v, order); } static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { - Base::fetch_xor(storage, v, order); + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); + base_type::fetch_xor(storage, v, order); } static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); fetch_complement(storage, order); } static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); return !!add(storage, v, order); } static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); return !!sub(storage, v, order); } static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); return !!negate(storage, order); } static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); return !!bitwise_and(storage, v, order); } static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); return !!bitwise_or(storage, v, order); } static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); return !!bitwise_xor(storage, v, order); } static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); return !!bitwise_complement(storage, order); } static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); - storage_type old_val = Base::fetch_or(storage, mask, order); + storage_type old_val = base_type::fetch_or(storage, mask, order); return !!(old_val & mask); } static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); - storage_type old_val = Base::fetch_and(storage, ~mask, order); + storage_type old_val = base_type::fetch_and(storage, ~mask, order); return !!(old_val & mask); } static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); - storage_type old_val = Base::fetch_xor(storage, mask, order); + storage_type old_val = base_type::fetch_xor(storage, mask, order); return !!(old_val & mask); } }; diff --git a/include/boost/atomic/detail/fp_ops_emulated.hpp b/include/boost/atomic/detail/fp_ops_emulated.hpp index 5beea91..b5e82a5 100644 --- a/include/boost/atomic/detail/fp_ops_emulated.hpp +++ b/include/boost/atomic/detail/fp_ops_emulated.hpp @@ -15,6 +15,7 @@ #define BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_ #include +#include #include #include #include @@ -28,7 +29,7 @@ namespace boost { namespace atomics { namespace detail { -//! Generic implementation of floating point operations +//! Emulated implementation of floating point operations template< typename Base, typename Value, std::size_t Size > struct emulated_fp_operations : public Base @@ -40,6 +41,7 @@ struct emulated_fp_operations : static BOOST_FORCEINLINE value_type fetch_add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); @@ -50,6 +52,7 @@ struct emulated_fp_operations : static BOOST_FORCEINLINE value_type fetch_sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); diff --git a/include/boost/atomic/detail/once_flag.hpp b/include/boost/atomic/detail/once_flag.hpp index a1d5d68..41cb5c9 100644 --- a/include/boost/atomic/detail/once_flag.hpp +++ b/include/boost/atomic/detail/once_flag.hpp @@ -26,7 +26,7 @@ namespace boost { namespace atomics { namespace detail { -typedef atomics::detail::operations< 1u, false > once_flag_operations; +typedef atomics::detail::operations< 1u, false, false > once_flag_operations; struct once_flag { diff --git a/include/boost/atomic/detail/operations_fwd.hpp b/include/boost/atomic/detail/operations_fwd.hpp index e64bfb8..ac9b31c 100644 --- a/include/boost/atomic/detail/operations_fwd.hpp +++ b/include/boost/atomic/detail/operations_fwd.hpp @@ -25,10 +25,10 @@ namespace boost { namespace atomics { namespace detail { -template< std::size_t Size, std::size_t Alignment, bool Signed > +template< std::size_t Size, std::size_t Alignment, bool Signed, bool Interprocess > struct emulated_operations; -template< std::size_t Size, bool Signed > +template< std::size_t Size, bool Signed, bool Interprocess > struct operations; } // namespace detail diff --git a/include/boost/atomic/detail/ops_emulated.hpp b/include/boost/atomic/detail/ops_emulated.hpp index e6de0bb..032f81e 100644 --- a/include/boost/atomic/detail/ops_emulated.hpp +++ b/include/boost/atomic/detail/ops_emulated.hpp @@ -15,6 +15,7 @@ #define BOOST_ATOMIC_DETAIL_OPS_EMULATED_HPP_INCLUDED_ #include +#include #include #include #include @@ -41,7 +42,8 @@ struct base_emulated_operations< Size, Alignment, false > typedef buffer_storage< Size, Alignment > storage_type; }; -template< std::size_t Size, std::size_t Alignment, bool Signed > +//! Emulated implementation of atomic operations +template< std::size_t Size, std::size_t Alignment, bool Signed, bool Interprocess > struct emulated_operations : public base_emulated_operations< Size, Alignment > { @@ -57,6 +59,7 @@ struct emulated_operations : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = Alignment >= storage_traits< Size >::alignment ? storage_traits< Size >::alignment : Alignment; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = false; @@ -65,18 +68,21 @@ struct emulated_operations : static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); scoped_lock lock(&storage); const_cast< storage_type& >(storage) = v; } static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); scoped_lock lock(&storage); return const_cast< storage_type const& >(storage); } static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -86,6 +92,7 @@ struct emulated_operations : static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -95,6 +102,7 @@ struct emulated_operations : static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -105,6 +113,7 @@ struct emulated_operations : static BOOST_FORCEINLINE bool compare_exchange_strong( storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -121,6 +130,7 @@ struct emulated_operations : { // Note: This function is the exact copy of compare_exchange_strong. The reason we're not just forwarding the call // is that MSVC-12 ICEs in this case. + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -134,6 +144,7 @@ struct emulated_operations : static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -143,6 +154,7 @@ struct emulated_operations : static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -152,6 +164,7 @@ struct emulated_operations : static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type& s = const_cast< storage_type& >(storage); scoped_lock lock(&storage); storage_type old_val = s; @@ -161,18 +174,20 @@ struct emulated_operations : static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); return !!exchange(storage, (storage_type)1, order); } static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); store(storage, (storage_type)0, order); } }; -template< std::size_t Size, bool Signed > +template< std::size_t Size, bool Signed, bool Interprocess > struct operations : - public emulated_operations< Size, storage_traits< Size >::alignment, Signed > + public emulated_operations< Size, storage_traits< Size >::alignment, Signed, Interprocess > { }; diff --git a/include/boost/atomic/detail/ops_gcc_alpha.hpp b/include/boost/atomic/detail/ops_gcc_alpha.hpp index ee0c58a..c41169f 100644 --- a/include/boost/atomic/detail/ops_gcc_alpha.hpp +++ b/include/boost/atomic/detail/ops_gcc_alpha.hpp @@ -87,8 +87,8 @@ struct gcc_alpha_operations_base }; -template< bool Signed > -struct operations< 4u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : public gcc_alpha_operations_base { typedef typename storage_traits< 4u >::type storage_type; @@ -96,6 +96,7 @@ struct operations< 4u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 4u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -347,12 +348,12 @@ struct operations< 4u, Signed > : }; -template< > -struct operations< 1u, false > : - public operations< 4u, false > +template< bool Interprocess > +struct operations< 1u, false, Interprocess > : + public operations< 4u, false, Interprocess > { - typedef operations< 4u, false > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, false, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -409,12 +410,12 @@ struct operations< 1u, false > : } }; -template< > -struct operations< 1u, true > : - public operations< 4u, true > +template< bool Interprocess > +struct operations< 1u, true, Interprocess > : + public operations< 4u, true, Interprocess > { - typedef operations< 4u, true > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, true, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -472,12 +473,12 @@ struct operations< 1u, true > : }; -template< > -struct operations< 2u, false > : - public operations< 4u, false > +template< bool Interprocess > +struct operations< 2u, false, Interprocess > : + public operations< 4u, false, Interprocess > { - typedef operations< 4u, false > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, false, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -534,12 +535,12 @@ struct operations< 2u, false > : } }; -template< > -struct operations< 2u, true > : - public operations< 4u, true > +template< bool Interprocess > +struct operations< 2u, true, Interprocess > : + public operations< 4u, true, Interprocess > { - typedef operations< 4u, true > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, true, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -597,8 +598,8 @@ struct operations< 2u, true > : }; -template< bool Signed > -struct operations< 8u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : public gcc_alpha_operations_base { typedef typename storage_traits< 8u >::type storage_type; @@ -606,6 +607,7 @@ struct operations< 8u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 8u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { diff --git a/include/boost/atomic/detail/ops_gcc_arm.hpp b/include/boost/atomic/detail/ops_gcc_arm.hpp index 3eb2d6a..cb74af8 100644 --- a/include/boost/atomic/detail/ops_gcc_arm.hpp +++ b/include/boost/atomic/detail/ops_gcc_arm.hpp @@ -56,8 +56,8 @@ namespace detail { // FIXME these are not yet used; should be mostly a matter of copy-and-paste. // I think you can supply an immediate offset to the address. -template< bool Signed > -struct operations< 4u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : public gcc_arm_operations_base { typedef typename storage_traits< 4u >::type storage_type; @@ -65,6 +65,7 @@ struct operations< 4u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 4u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -314,8 +315,8 @@ struct operations< 4u, Signed > : #if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) -template< bool Signed > -struct operations< 1u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : public gcc_arm_operations_base { typedef typename storage_traits< 1u >::type storage_type; @@ -324,6 +325,7 @@ struct operations< 1u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 1u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -573,12 +575,12 @@ struct operations< 1u, Signed > : #else // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) -template< > -struct operations< 1u, false > : - public operations< 4u, false > +template< bool Interprocess > +struct operations< 1u, false, Interprocess > : + public operations< 4u, false, Interprocess > { - typedef operations< 4u, false > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, false, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -635,12 +637,12 @@ struct operations< 1u, false > : } }; -template< > -struct operations< 1u, true > : - public operations< 4u, true > +template< bool Interprocess > +struct operations< 1u, true, Interprocess > : + public operations< 4u, true, Interprocess > { - typedef operations< 4u, true > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, true, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -701,8 +703,8 @@ struct operations< 1u, true > : #if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) -template< bool Signed > -struct operations< 2u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : public gcc_arm_operations_base { typedef typename storage_traits< 2u >::type storage_type; @@ -711,6 +713,7 @@ struct operations< 2u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 2u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -960,12 +963,12 @@ struct operations< 2u, Signed > : #else // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) -template< > -struct operations< 2u, false > : - public operations< 4u, false > +template< bool Interprocess > +struct operations< 2u, false, Interprocess > : + public operations< 4u, false, Interprocess > { - typedef operations< 4u, false > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, false, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -1022,12 +1025,12 @@ struct operations< 2u, false > : } }; -template< > -struct operations< 2u, true > : - public operations< 4u, true > +template< bool Interprocess > +struct operations< 2u, true, Interprocess > : + public operations< 4u, true, Interprocess > { - typedef operations< 4u, true > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, true, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -1099,8 +1102,8 @@ struct operations< 2u, true > : // and the upper half (Rt2) - via the same placeholder with an 'H' after the '%' sign (e.g. %H0). // See: http://hardwarebug.org/2010/07/06/arm-inline-asm-secrets/ -template< bool Signed > -struct operations< 8u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : public gcc_arm_operations_base { typedef typename storage_traits< 8u >::type storage_type; @@ -1108,6 +1111,7 @@ struct operations< 8u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 8u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { diff --git a/include/boost/atomic/detail/ops_gcc_atomic.hpp b/include/boost/atomic/detail/ops_gcc_atomic.hpp index 7360b88..55e6812 100644 --- a/include/boost/atomic/detail/ops_gcc_atomic.hpp +++ b/include/boost/atomic/detail/ops_gcc_atomic.hpp @@ -81,7 +81,7 @@ BOOST_FORCEINLINE BOOST_CONSTEXPR int convert_memory_order_to_gcc(memory_order o (order == memory_order_acq_rel ? __ATOMIC_ACQ_REL : __ATOMIC_SEQ_CST))))); } -template< std::size_t Size, bool Signed > +template< std::size_t Size, bool Signed, bool Interprocess > struct gcc_atomic_operations { typedef typename storage_traits< Size >::type storage_type; @@ -89,6 +89,7 @@ struct gcc_atomic_operations static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = storage_traits< Size >::alignment; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; // Note: In the current implementation, gcc_atomic_operations are used only when the particularly sized __atomic @@ -176,17 +177,17 @@ struct gcc_atomic_operations // Clang 3.4 does not implement 128-bit __atomic* intrinsics even though it defines __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 // A similar problem exists with gcc 7 as well, as it requires to link with libatomic to use 16-byte intrinsics: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878 -template< bool Signed > -struct operations< 16u, Signed > : - public cas_based_operations< gcc_dcas_x86_64< Signed > > +template< bool Signed, bool Interprocess > +struct operations< 16u, Signed, Interprocess > : + public cas_based_operations< gcc_dcas_x86_64< Signed, Interprocess > > { }; #else -template< bool Signed > -struct operations< 16u, Signed > : - public gcc_atomic_operations< 16u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 16u, Signed, Interprocess > : + public gcc_atomic_operations< 16u, Signed, Interprocess > { }; @@ -198,9 +199,9 @@ struct operations< 16u, Signed > : #if defined(__clang__) && defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) // Workaround for clang bug http://llvm.org/bugs/show_bug.cgi?id=19355 -template< bool Signed > -struct operations< 8u, Signed > : - public cas_based_operations< gcc_dcas_x86< Signed > > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public cas_based_operations< gcc_dcas_x86< Signed, Interprocess > > { static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; @@ -214,17 +215,17 @@ struct operations< 8u, Signed > : #define BOOST_ATOMIC_DETAIL_INT64_EXTENDED -template< bool Signed > -struct operations< 8u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 8u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed, Interprocess >, 8u, Signed > { }; #else -template< bool Signed > -struct operations< 8u, Signed > : - public gcc_atomic_operations< 8u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public gcc_atomic_operations< 8u, Signed, Interprocess > { }; @@ -242,17 +243,17 @@ struct operations< 8u, Signed > : #if !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) -template< bool Signed > -struct operations< 4u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 4u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed, Interprocess >, 4u, Signed > { }; #else // !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) -template< bool Signed > -struct operations< 4u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 4u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed, Interprocess >, 4u, Signed > { }; @@ -260,9 +261,9 @@ struct operations< 4u, Signed > : #else -template< bool Signed > -struct operations< 4u, Signed > : - public gcc_atomic_operations< 4u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : + public gcc_atomic_operations< 4u, Signed, Interprocess > { }; @@ -280,25 +281,25 @@ struct operations< 4u, Signed > : #if !defined(BOOST_ATOMIC_DETAIL_INT32_EXTENDED) -template< bool Signed > -struct operations< 2u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 4u, Signed >, 2u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 4u, Signed, Interprocess >, 2u, Signed > { }; #elif !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) -template< bool Signed > -struct operations< 2u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 2u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed, Interprocess >, 2u, Signed > { }; #else -template< bool Signed > -struct operations< 2u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 2u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed, Interprocess >, 2u, Signed > { }; @@ -306,9 +307,9 @@ struct operations< 2u, Signed > : #else -template< bool Signed > -struct operations< 2u, Signed > : - public gcc_atomic_operations< 2u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public gcc_atomic_operations< 2u, Signed, Interprocess > { }; @@ -326,33 +327,33 @@ struct operations< 2u, Signed > : #if !defined(BOOST_ATOMIC_DETAIL_INT16_EXTENDED) -template< bool Signed > -struct operations< 1u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 2u, Signed >, 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 2u, Signed, Interprocess >, 1u, Signed > { }; #elif !defined(BOOST_ATOMIC_DETAIL_INT32_EXTENDED) -template< bool Signed > -struct operations< 1u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 4u, Signed >, 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 4u, Signed, Interprocess >, 1u, Signed > { }; #elif !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) -template< bool Signed > -struct operations< 1u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed, Interprocess >, 1u, Signed > { }; #else -template< bool Signed > -struct operations< 1u, Signed > : - public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed, Interprocess >, 1u, Signed > { }; @@ -360,9 +361,9 @@ struct operations< 1u, Signed > : #else -template< bool Signed > -struct operations< 1u, Signed > : - public gcc_atomic_operations< 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public gcc_atomic_operations< 1u, Signed, Interprocess > { }; diff --git a/include/boost/atomic/detail/ops_gcc_ppc.hpp b/include/boost/atomic/detail/ops_gcc_ppc.hpp index 82c0310..feff023 100644 --- a/include/boost/atomic/detail/ops_gcc_ppc.hpp +++ b/include/boost/atomic/detail/ops_gcc_ppc.hpp @@ -79,8 +79,8 @@ namespace detail { to pose a problem. */ -template< bool Signed > -struct operations< 4u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : public gcc_ppc_operations_base { typedef typename storage_traits< 4u >::type storage_type; @@ -88,6 +88,7 @@ struct operations< 4u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 4u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -309,8 +310,8 @@ struct operations< 4u, Signed > : #if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) -template< bool Signed > -struct operations< 1u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : public gcc_ppc_operations_base { typedef typename storage_traits< 1u >::type storage_type; @@ -318,6 +319,7 @@ struct operations< 1u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 1u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -539,12 +541,12 @@ struct operations< 1u, Signed > : #else // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) -template< > -struct operations< 1u, false > : - public operations< 4u, false > +template< bool Interprocess > +struct operations< 1u, false, Interprocess > : + public operations< 4u, false, Interprocess > { - typedef operations< 4u, false > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, false, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -587,12 +589,12 @@ struct operations< 1u, false > : } }; -template< > -struct operations< 1u, true > : - public operations< 4u, true > +template< bool Interprocess > +struct operations< 1u, true, Interprocess > : + public operations< 4u, true, Interprocess > { - typedef operations< 4u, true > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, true, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -639,8 +641,8 @@ struct operations< 1u, true > : #if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) -template< bool Signed > -struct operations< 2u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : public gcc_ppc_operations_base { typedef typename storage_traits< 2u >::type storage_type; @@ -648,6 +650,7 @@ struct operations< 2u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 2u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -869,12 +872,12 @@ struct operations< 2u, Signed > : #else // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) -template< > -struct operations< 2u, false > : - public operations< 4u, false > +template< bool Interprocess > +struct operations< 2u, false, Interprocess > : + public operations< 4u, false, Interprocess > { - typedef operations< 4u, false > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, false, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -917,12 +920,12 @@ struct operations< 2u, false > : } }; -template< > -struct operations< 2u, true > : - public operations< 4u, true > +template< bool Interprocess > +struct operations< 2u, true, Interprocess > : + public operations< 4u, true, Interprocess > { - typedef operations< 4u, true > base_type; - typedef base_type::storage_type storage_type; + typedef operations< 4u, true, Interprocess > base_type; + typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -969,8 +972,8 @@ struct operations< 2u, true > : #if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) -template< bool Signed > -struct operations< 8u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : public gcc_ppc_operations_base { typedef typename storage_traits< 8u >::type storage_type; @@ -978,6 +981,7 @@ struct operations< 8u, Signed > : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 8u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { diff --git a/include/boost/atomic/detail/ops_gcc_sparc.hpp b/include/boost/atomic/detail/ops_gcc_sparc.hpp index 3bd968d..45959ce 100644 --- a/include/boost/atomic/detail/ops_gcc_sparc.hpp +++ b/include/boost/atomic/detail/ops_gcc_sparc.hpp @@ -61,7 +61,7 @@ struct gcc_sparc_cas_base } }; -template< bool Signed > +template< bool Signed, bool Interprocess > struct gcc_sparc_cas32 : public gcc_sparc_cas_base { @@ -70,6 +70,7 @@ struct gcc_sparc_cas32 : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 4u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -127,25 +128,25 @@ struct gcc_sparc_cas32 : } }; -template< bool Signed > -struct operations< 4u, Signed > : - public cas_based_operations< gcc_sparc_cas32< Signed > > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : + public cas_based_operations< gcc_sparc_cas32< Signed, Interprocess > > { }; -template< bool Signed > -struct operations< 1u, Signed > : - public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public extending_cas_based_operations< operations< 4u, Signed, Interprocess >, 1u, Signed > { }; -template< bool Signed > -struct operations< 2u, Signed > : - public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public extending_cas_based_operations< operations< 4u, Signed, Interprocess >, 2u, Signed > { }; -template< bool Signed > +template< bool Signed, bool Interprocess > struct gcc_sparc_cas64 : public gcc_sparc_cas_base { @@ -154,6 +155,7 @@ struct gcc_sparc_cas64 : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 8u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -197,9 +199,9 @@ struct gcc_sparc_cas64 : } }; -template< bool Signed > -struct operations< 8u, Signed > : - public cas_based_operations< cas_based_exchange< gcc_sparc_cas64< Signed > > > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public cas_based_operations< cas_based_exchange< gcc_sparc_cas64< Signed, Interprocess > > > { }; diff --git a/include/boost/atomic/detail/ops_gcc_sync.hpp b/include/boost/atomic/detail/ops_gcc_sync.hpp index 279d192..adaa450 100644 --- a/include/boost/atomic/detail/ops_gcc_sync.hpp +++ b/include/boost/atomic/detail/ops_gcc_sync.hpp @@ -56,7 +56,7 @@ struct gcc_sync_operations_base } }; -template< std::size_t Size, bool Signed > +template< std::size_t Size, bool Signed, bool Interprocess > struct gcc_sync_operations : public gcc_sync_operations_base { @@ -65,6 +65,7 @@ struct gcc_sync_operations : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = storage_traits< Size >::alignment; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -154,69 +155,69 @@ struct gcc_sync_operations : }; #if BOOST_ATOMIC_INT8_LOCK_FREE > 0 -template< bool Signed > -struct operations< 1u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) - public gcc_sync_operations< 1u, Signed > + public gcc_sync_operations< 1u, Signed, Interprocess > #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) - public extending_cas_based_operations< gcc_sync_operations< 2u, Signed >, 1u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 2u, Signed, Interprocess >, 1u, Signed > #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) - public extending_cas_based_operations< gcc_sync_operations< 4u, Signed >, 1u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 4u, Signed, Interprocess >, 1u, Signed > #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) - public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 1u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed, Interprocess >, 1u, Signed > #else - public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 1u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed, Interprocess >, 1u, Signed > #endif { }; #endif #if BOOST_ATOMIC_INT16_LOCK_FREE > 0 -template< bool Signed > -struct operations< 2u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) - public gcc_sync_operations< 2u, Signed > + public gcc_sync_operations< 2u, Signed, Interprocess > #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) - public extending_cas_based_operations< gcc_sync_operations< 4u, Signed >, 2u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 4u, Signed, Interprocess >, 2u, Signed > #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) - public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 2u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed, Interprocess >, 2u, Signed > #else - public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 2u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed, Interprocess >, 2u, Signed > #endif { }; #endif #if BOOST_ATOMIC_INT32_LOCK_FREE > 0 -template< bool Signed > -struct operations< 4u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) - public gcc_sync_operations< 4u, Signed > + public gcc_sync_operations< 4u, Signed, Interprocess > #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) - public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 4u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed, Interprocess >, 4u, Signed > #else - public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 4u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed, Interprocess >, 4u, Signed > #endif { }; #endif #if BOOST_ATOMIC_INT64_LOCK_FREE > 0 -template< bool Signed > -struct operations< 8u, Signed > : +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) - public gcc_sync_operations< 8u, Signed > + public gcc_sync_operations< 8u, Signed, Interprocess > #else - public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 8u, Signed > + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed, Interprocess >, 8u, Signed > #endif { }; #endif #if BOOST_ATOMIC_INT128_LOCK_FREE > 0 -template< bool Signed > -struct operations< 16u, Signed > : - public gcc_sync_operations< 16u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 16u, Signed, Interprocess > : + public gcc_sync_operations< 16u, Signed, Interprocess > { }; #endif diff --git a/include/boost/atomic/detail/ops_gcc_x86.hpp b/include/boost/atomic/detail/ops_gcc_x86.hpp index 6633695..a3eaf16 100644 --- a/include/boost/atomic/detail/ops_gcc_x86.hpp +++ b/include/boost/atomic/detail/ops_gcc_x86.hpp @@ -53,12 +53,17 @@ struct gcc_x86_operations_base } }; -template< std::size_t Size, bool Signed, typename Derived > +template< std::size_t Size, bool Signed, bool Interprocess, typename Derived > struct gcc_x86_operations : public gcc_x86_operations_base { typedef typename storage_traits< Size >::type storage_type; + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { if (order != memory_order_seq_cst) @@ -102,18 +107,14 @@ struct gcc_x86_operations : } }; -template< bool Signed > -struct operations< 1u, Signed > : - public gcc_x86_operations< 1u, Signed, operations< 1u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public gcc_x86_operations< 1u, Signed, Interprocess, operations< 1u, Signed, Interprocess > > { - typedef gcc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef gcc_x86_operations< 1u, Signed, Interprocess, operations< 1u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; typedef typename storage_traits< 4u >::type temp_storage_type; - static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; - static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 1u; - static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; - static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { __asm__ __volatile__ @@ -203,18 +204,14 @@ struct operations< 1u, Signed > : #undef BOOST_ATOMIC_DETAIL_CAS_LOOP }; -template< bool Signed > -struct operations< 2u, Signed > : - public gcc_x86_operations< 2u, Signed, operations< 2u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public gcc_x86_operations< 2u, Signed, Interprocess, operations< 2u, Signed, Interprocess > > { - typedef gcc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef gcc_x86_operations< 2u, Signed, Interprocess, operations< 2u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; typedef typename storage_traits< 4u >::type temp_storage_type; - static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; - static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 2u; - static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; - static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { __asm__ __volatile__ @@ -304,17 +301,13 @@ struct operations< 2u, Signed > : #undef BOOST_ATOMIC_DETAIL_CAS_LOOP }; -template< bool Signed > -struct operations< 4u, Signed > : - public gcc_x86_operations< 4u, Signed, operations< 4u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : + public gcc_x86_operations< 4u, Signed, Interprocess, operations< 4u, Signed, Interprocess > > { - typedef gcc_x86_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef gcc_x86_operations< 4u, Signed, Interprocess, operations< 4u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; - static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; - static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 4u; - static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; - static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { __asm__ __volatile__ @@ -406,25 +399,21 @@ struct operations< 4u, Signed > : #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) -template< bool Signed > -struct operations< 8u, Signed > : - public cas_based_operations< gcc_dcas_x86< Signed > > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public cas_based_operations< gcc_dcas_x86< Signed, Interprocess > > { }; #elif defined(__x86_64__) -template< bool Signed > -struct operations< 8u, Signed > : - public gcc_x86_operations< 8u, Signed, operations< 8u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public gcc_x86_operations< 8u, Signed, Interprocess, operations< 8u, Signed, Interprocess > > { - typedef gcc_x86_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef gcc_x86_operations< 8u, Signed, Interprocess, operations< 8u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; - static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; - static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 8u; - static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; - static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT { __asm__ __volatile__ @@ -518,9 +507,9 @@ struct operations< 8u, Signed > : #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) -template< bool Signed > -struct operations< 16u, Signed > : - public cas_based_operations< gcc_dcas_x86_64< Signed > > +template< bool Signed, bool Interprocess > +struct operations< 16u, Signed, Interprocess > : + public cas_based_operations< gcc_dcas_x86_64< Signed, Interprocess > > { }; diff --git a/include/boost/atomic/detail/ops_gcc_x86_dcas.hpp b/include/boost/atomic/detail/ops_gcc_x86_dcas.hpp index f2711f4..d1a545e 100644 --- a/include/boost/atomic/detail/ops_gcc_x86_dcas.hpp +++ b/include/boost/atomic/detail/ops_gcc_x86_dcas.hpp @@ -41,7 +41,7 @@ namespace detail { #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) -template< bool Signed > +template< bool Signed, bool Interprocess > struct gcc_dcas_x86 { typedef typename storage_traits< 8u >::type storage_type; @@ -50,6 +50,7 @@ struct gcc_dcas_x86 static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 8u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; @@ -381,7 +382,7 @@ struct gcc_dcas_x86 #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) -template< bool Signed > +template< bool Signed, bool Interprocess > struct gcc_dcas_x86_64 { typedef typename storage_traits< 16u >::type storage_type; @@ -390,6 +391,7 @@ struct gcc_dcas_x86_64 static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 16u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 16u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; diff --git a/include/boost/atomic/detail/ops_linux_arm.hpp b/include/boost/atomic/detail/ops_linux_arm.hpp index 41c350c..82c7b29 100644 --- a/include/boost/atomic/detail/ops_linux_arm.hpp +++ b/include/boost/atomic/detail/ops_linux_arm.hpp @@ -86,7 +86,7 @@ struct linux_arm_cas_base } }; -template< bool Signed > +template< bool Signed, bool Interprocess > struct linux_arm_cas : public linux_arm_cas_base { @@ -95,6 +95,7 @@ struct linux_arm_cas : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 4u; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -143,21 +144,21 @@ struct linux_arm_cas : } }; -template< bool Signed > -struct operations< 1u, Signed > : - public extending_cas_based_operations< cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > >, 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public extending_cas_based_operations< cas_based_operations< cas_based_exchange< linux_arm_cas< Signed, Interprocess > > >, 1u, Signed > { }; -template< bool Signed > -struct operations< 2u, Signed > : - public extending_cas_based_operations< cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > >, 2u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public extending_cas_based_operations< cas_based_operations< cas_based_exchange< linux_arm_cas< Signed, Interprocess > > >, 2u, Signed > { }; -template< bool Signed > -struct operations< 4u, Signed > : - public cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : + public cas_based_operations< cas_based_exchange< linux_arm_cas< Signed, Interprocess > > > { }; diff --git a/include/boost/atomic/detail/ops_msvc_arm.hpp b/include/boost/atomic/detail/ops_msvc_arm.hpp index fbae0a8..a0eaaa0 100644 --- a/include/boost/atomic/detail/ops_msvc_arm.hpp +++ b/include/boost/atomic/detail/ops_msvc_arm.hpp @@ -100,7 +100,7 @@ struct msvc_arm_operations_base } }; -template< std::size_t Size, bool Signed, typename Derived > +template< std::size_t Size, bool Signed, bool Interprocess, typename Derived > struct msvc_arm_operations : public msvc_arm_operations_base { @@ -109,6 +109,7 @@ struct msvc_arm_operations : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = storage_traits< Size >::alignment; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -133,11 +134,11 @@ struct msvc_arm_operations : } }; -template< bool Signed > -struct operations< 1u, Signed > : - public msvc_arm_operations< 1u, Signed, operations< 1u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public msvc_arm_operations< 1u, Signed, Interprocess, operations< 1u, Signed, Interprocess > > { - typedef msvc_arm_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef msvc_arm_operations< 1u, Signed, Interprocess, operations< 1u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT @@ -298,11 +299,11 @@ struct operations< 1u, Signed > : } }; -template< bool Signed > -struct operations< 2u, Signed > : - public msvc_arm_operations< 2u, Signed, operations< 2u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public msvc_arm_operations< 2u, Signed, Interprocess, operations< 2u, Signed, Interprocess > > { - typedef msvc_arm_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef msvc_arm_operations< 2u, Signed, Interprocess, operations< 2u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT @@ -463,11 +464,11 @@ struct operations< 2u, Signed > : } }; -template< bool Signed > -struct operations< 4u, Signed > : - public msvc_arm_operations< 4u, Signed, operations< 4u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : + public msvc_arm_operations< 4u, Signed, Interprocess, operations< 4u, Signed, Interprocess > > { - typedef msvc_arm_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef msvc_arm_operations< 4u, Signed, Interprocess, operations< 4u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT @@ -628,11 +629,11 @@ struct operations< 4u, Signed > : } }; -template< bool Signed > -struct operations< 8u, Signed > : - public msvc_arm_operations< 8u, Signed, operations< 8u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public msvc_arm_operations< 8u, Signed, Interprocess, operations< 8u, Signed, Interprocess > > { - typedef msvc_arm_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef msvc_arm_operations< 8u, Signed, Interprocess, operations< 8u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT diff --git a/include/boost/atomic/detail/ops_msvc_x86.hpp b/include/boost/atomic/detail/ops_msvc_x86.hpp index 47719a4..a59c06a 100644 --- a/include/boost/atomic/detail/ops_msvc_x86.hpp +++ b/include/boost/atomic/detail/ops_msvc_x86.hpp @@ -109,7 +109,7 @@ struct msvc_x86_operations_base } }; -template< std::size_t Size, bool Signed, typename Derived > +template< std::size_t Size, bool Signed, bool Interprocess, typename Derived > struct msvc_x86_operations : public msvc_x86_operations_base { @@ -118,6 +118,7 @@ struct msvc_x86_operations : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = storage_traits< Size >::alignment; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -163,11 +164,11 @@ struct msvc_x86_operations : } }; -template< bool Signed > -struct operations< 4u, Signed > : - public msvc_x86_operations< 4u, Signed, operations< 4u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, Interprocess > : + public msvc_x86_operations< 4u, Signed, Interprocess, operations< 4u, Signed, Interprocess > > { - typedef msvc_x86_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef msvc_x86_operations< 4u, Signed, Interprocess, operations< 4u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT @@ -234,11 +235,11 @@ struct operations< 4u, Signed > : #if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8) -template< bool Signed > -struct operations< 1u, Signed > : - public msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public msvc_x86_operations< 1u, Signed, Interprocess, operations< 1u, Signed, Interprocess > > { - typedef msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef msvc_x86_operations< 1u, Signed, Interprocess, operations< 1u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT @@ -278,11 +279,11 @@ struct operations< 1u, Signed > : #elif defined(_M_IX86) -template< bool Signed > -struct operations< 1u, Signed > : - public msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public msvc_x86_operations< 1u, Signed, Interprocess, operations< 1u, Signed, Interprocess > > { - typedef msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef msvc_x86_operations< 1u, Signed, Interprocess, operations< 1u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT @@ -399,9 +400,9 @@ struct operations< 1u, Signed > : #else -template< bool Signed > -struct operations< 1u, Signed > : - public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public extending_cas_based_operations< operations< 4u, Signed, Interprocess >, 1u, Signed > { }; @@ -409,11 +410,11 @@ struct operations< 1u, Signed > : #if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16) -template< bool Signed > -struct operations< 2u, Signed > : - public msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public msvc_x86_operations< 2u, Signed, Interprocess, operations< 2u, Signed, Interprocess > > { - typedef msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef msvc_x86_operations< 2u, Signed, Interprocess, operations< 2u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT @@ -453,11 +454,11 @@ struct operations< 2u, Signed > : #elif defined(_M_IX86) -template< bool Signed > -struct operations< 2u, Signed > : - public msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public msvc_x86_operations< 2u, Signed, Interprocess, operations< 2u, Signed, Interprocess > > { - typedef msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef msvc_x86_operations< 2u, Signed, Interprocess, operations< 2u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT @@ -574,9 +575,9 @@ struct operations< 2u, Signed > : #else -template< bool Signed > -struct operations< 2u, Signed > : - public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public extending_cas_based_operations< operations< 4u, Signed, Interprocess >, 2u, Signed > { }; @@ -585,11 +586,12 @@ struct operations< 2u, Signed > : #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) -template< bool Signed > +template< bool Signed, bool Interprocess > struct msvc_dcas_x86 { typedef typename storage_traits< 8u >::type storage_type; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; @@ -784,19 +786,19 @@ struct msvc_dcas_x86 } }; -template< bool Signed > -struct operations< 8u, Signed > : - public cas_based_operations< msvc_dcas_x86< Signed > > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public cas_based_operations< msvc_dcas_x86< Signed, Interprocess > > { }; #elif defined(_M_AMD64) -template< bool Signed > -struct operations< 8u, Signed > : - public msvc_x86_operations< 8u, Signed, operations< 8u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 8u, Signed, Interprocess > : + public msvc_x86_operations< 8u, Signed, Interprocess, operations< 8u, Signed, Interprocess > > { - typedef msvc_x86_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef msvc_x86_operations< 8u, Signed, Interprocess, operations< 8u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT @@ -838,11 +840,12 @@ struct operations< 8u, Signed > : #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) -template< bool Signed > +template< bool Signed, bool Interprocess > struct msvc_dcas_x86_64 { typedef typename storage_traits< 16u >::type storage_type; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; @@ -876,9 +879,9 @@ struct msvc_dcas_x86_64 } }; -template< bool Signed > -struct operations< 16u, Signed > : - public cas_based_operations< cas_based_exchange< msvc_dcas_x86_64< Signed > > > +template< bool Signed, bool Interprocess > +struct operations< 16u, Signed, Interprocess > : + public cas_based_operations< cas_based_exchange< msvc_dcas_x86_64< Signed, Interprocess > > > { }; diff --git a/include/boost/atomic/detail/ops_windows.hpp b/include/boost/atomic/detail/ops_windows.hpp index 5170a64..d02c290 100644 --- a/include/boost/atomic/detail/ops_windows.hpp +++ b/include/boost/atomic/detail/ops_windows.hpp @@ -64,7 +64,7 @@ struct windows_operations_base } }; -template< std::size_t Size, bool Signed, typename Derived > +template< std::size_t Size, bool Signed, bool Interprocess, typename Derived > struct windows_operations : public windows_operations_base { @@ -73,6 +73,7 @@ struct windows_operations : static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = storage_traits< Size >::alignment; static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT { @@ -107,11 +108,11 @@ struct windows_operations : } }; -template< bool Signed > -struct operations< 4u, Signed > : - public windows_operations< 4u, Signed, operations< 4u, Signed > > +template< bool Signed, bool Interprocess > +struct operations< 4u, Signed, bool Interprocess > : + public windows_operations< 4u, Signed, Interprocess, operations< 4u, Signed, Interprocess > > { - typedef windows_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef windows_operations< 4u, Signed, Interprocess, operations< 4u, Signed, Interprocess > > base_type; typedef typename base_type::storage_type storage_type; static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT @@ -185,15 +186,15 @@ struct operations< 4u, Signed > : } }; -template< bool Signed > -struct operations< 1u, Signed > : - public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 1u, Signed, Interprocess > : + public extending_cas_based_operations< operations< 4u, Signed, Interprocess >, 1u, Signed > { }; -template< bool Signed > -struct operations< 2u, Signed > : - public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +template< bool Signed, bool Interprocess > +struct operations< 2u, Signed, Interprocess > : + public extending_cas_based_operations< operations< 4u, Signed, Interprocess >, 2u, Signed > { }; diff --git a/include/boost/atomic/detail/wait_capabilities.hpp b/include/boost/atomic/detail/wait_capabilities.hpp new file mode 100644 index 0000000..c4ae1bd --- /dev/null +++ b/include/boost/atomic/detail/wait_capabilities.hpp @@ -0,0 +1,363 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2020 Andrey Semashev + */ +/*! + * \file atomic/detail/wait_capabilities.hpp + * + * This header defines waiting/notifying operations capabilities macros. + */ + +#ifndef BOOST_ATOMIC_DETAIL_WAIT_CAPABILITIES_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_WAIT_CAPABILITIES_HPP_INCLUDED_ + +#include +#include +#include +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#include +#endif + +#if !defined(BOOST_ATOMIC_EMULATED) && !defined(BOOST_ATOMIC_DETAIL_WAIT_BACKEND_GENERIC) +#include BOOST_ATOMIC_DETAIL_WAIT_BACKEND_HEADER(boost/atomic/detail/wait_caps_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY 0 +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY 0 +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY 0 +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY 0 +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY 0 +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY 0 +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY 0 +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY 0 +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT128_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT128_WAIT_NOTIFY 0 +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT128_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_INT128_IPC_WAIT_NOTIFY 0 +#endif + + +#ifndef BOOST_ATOMIC_HAS_NATIVE_CHAR_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_CHAR_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_CHAR_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_CHAR_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_CHAR8_T_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_CHAR8_T_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_CHAR8_T_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_CHAR8_T_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_CHAR16_T_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_CHAR16_T_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_CHAR16_T_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_CHAR16_T_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_CHAR32_T_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_CHAR32_T_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_CHAR32_T_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_CHAR32_T_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 1 +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 2 +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 4 +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 8 +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_IPC_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 1 +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 2 +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 4 +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 8 +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_WCHAR_T_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_SHORT_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 1 +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 2 +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 4 +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 8 +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_SHORT_IPC_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 1 +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 2 +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 4 +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 8 +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_SHORT_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_INT == 1 +#define BOOST_ATOMIC_HAS_NATIVE_INT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 2 +#define BOOST_ATOMIC_HAS_NATIVE_INT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4 +#define BOOST_ATOMIC_HAS_NATIVE_INT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 8 +#define BOOST_ATOMIC_HAS_NATIVE_INT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_INT_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_INT_IPC_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_INT == 1 +#define BOOST_ATOMIC_HAS_NATIVE_INT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 2 +#define BOOST_ATOMIC_HAS_NATIVE_INT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4 +#define BOOST_ATOMIC_HAS_NATIVE_INT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 8 +#define BOOST_ATOMIC_HAS_NATIVE_INT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_INT_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_LONG_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 1 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 2 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_LONG_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_LONG_IPC_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 1 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 2 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_LONG_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_LLONG_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 1 +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 2 +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 4 +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8 +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_LLONG_IPC_WAIT_NOTIFY +#if BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 1 +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 2 +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 4 +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8 +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_LLONG_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_POINTER_WAIT_NOTIFY +#if (BOOST_ATOMIC_DETAIL_SIZEOF_POINTER + 0) == 8 +#define BOOST_ATOMIC_HAS_NATIVE_POINTER_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#elif (BOOST_ATOMIC_DETAIL_SIZEOF_POINTER + 0) == 4 +#define BOOST_ATOMIC_HAS_NATIVE_POINTER_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_POINTER_WAIT_NOTIFY 0 +#endif +#endif + +#define BOOST_ATOMIC_HAS_NATIVE_ADDRESS_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_POINTER_WAIT_NOTIFY + +#ifndef BOOST_ATOMIC_HAS_NATIVE_POINTER_IPC_WAIT_NOTIFY +#if (BOOST_ATOMIC_DETAIL_SIZEOF_POINTER + 0) == 8 +#define BOOST_ATOMIC_HAS_NATIVE_POINTER_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#elif (BOOST_ATOMIC_DETAIL_SIZEOF_POINTER + 0) == 4 +#define BOOST_ATOMIC_HAS_NATIVE_POINTER_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_POINTER_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#define BOOST_ATOMIC_HAS_NATIVE_ADDRESS_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_POINTER_IPC_WAIT_NOTIFY + +// We store bools in 1-byte storage in all backends +#ifndef BOOST_ATOMIC_HAS_NATIVE_BOOL_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_BOOL_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_BOOL_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_BOOL_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT8_IPC_WAIT_NOTIFY +#endif + +#ifndef BOOST_ATOMIC_HAS_NATIVE_FLAG_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_FLAG_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#endif +#ifndef BOOST_ATOMIC_HAS_NATIVE_FLAG_IPC_WAIT_NOTIFY +#define BOOST_ATOMIC_HAS_NATIVE_FLAG_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#endif + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + +#if !defined(BOOST_ATOMIC_HAS_NATIVE_FLOAT_WAIT_NOTIFY) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) +#if BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 2 +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 4 +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 8 +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 16 +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT128_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_WAIT_NOTIFY 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_HAS_NATIVE_FLOAT_IPC_WAIT_NOTIFY) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) +#if BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 2 +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 4 +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 8 +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 16 +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT128_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_FLOAT_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_HAS_NATIVE_DOUBLE_WAIT_NOTIFY) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) +#if BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 2 +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 4 +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 8 +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 16 +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT128_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_WAIT_NOTIFY 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_HAS_NATIVE_DOUBLE_IPC_WAIT_NOTIFY) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) +#if BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 2 +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 4 +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 8 +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 16 +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT128_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_DOUBLE_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_WAIT_NOTIFY) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) +#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 2 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 4 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 8 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 16 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT128_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_WAIT_NOTIFY 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_IPC_WAIT_NOTIFY) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) +#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 2 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT16_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 4 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 8 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 16 +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_IPC_WAIT_NOTIFY BOOST_ATOMIC_HAS_NATIVE_INT128_IPC_WAIT_NOTIFY +#else +#define BOOST_ATOMIC_HAS_NATIVE_LONG_DOUBLE_IPC_WAIT_NOTIFY 0 +#endif +#endif + +#endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + +#endif // BOOST_ATOMIC_DETAIL_WAIT_CAPABILITIES_HPP_INCLUDED_ diff --git a/include/boost/atomic/detail/wait_caps_dragonfly_umtx.hpp b/include/boost/atomic/detail/wait_caps_dragonfly_umtx.hpp new file mode 100644 index 0000000..7e9b54f --- /dev/null +++ b/include/boost/atomic/detail/wait_caps_dragonfly_umtx.hpp @@ -0,0 +1,30 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2020 Andrey Semashev + */ +/*! + * \file atomic/detail/wait_caps_dragonfly_umtx.hpp + * + * This header defines waiting/notifying operations capabilities macros. + */ + +#ifndef BOOST_ATOMIC_DETAIL_WAIT_CAPS_DRAGONFLY_UMTX_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_WAIT_CAPS_DRAGONFLY_UMTX_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// DragonFly BSD umtx_sleep/umtx_wakeup use physical address to the atomic object as a key, which means it should support address-free operations. +// https://man.dragonflybsd.org/?command=umtx§ion=2 + +#define BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY BOOST_ATOMIC_INT32_LOCK_FREE +#define BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY BOOST_ATOMIC_INT32_LOCK_FREE + +#endif // BOOST_ATOMIC_DETAIL_WAIT_CAPS_DRAGONFLY_UMTX_HPP_INCLUDED_ diff --git a/include/boost/atomic/detail/wait_caps_freebsd_umtx.hpp b/include/boost/atomic/detail/wait_caps_freebsd_umtx.hpp new file mode 100644 index 0000000..5f4359c --- /dev/null +++ b/include/boost/atomic/detail/wait_caps_freebsd_umtx.hpp @@ -0,0 +1,40 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2020 Andrey Semashev + */ +/*! + * \file atomic/detail/wait_caps_freebsd_umtx.hpp + * + * This header defines waiting/notifying operations capabilities macros. + */ + +#ifndef BOOST_ATOMIC_DETAIL_WAIT_CAPS_FREEBSD_UMTX_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_WAIT_CAPS_FREEBSD_UMTX_HPP_INCLUDED_ + +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// FreeBSD _umtx_op uses physical address to the atomic object as a key, which means it should support address-free operations. +// https://www.freebsd.org/cgi/man.cgi?query=_umtx_op&apropos=0&sektion=2&manpath=FreeBSD+11-current&format=html + +#if (defined(UMTX_OP_WAIT_UINT) && BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4) ||\ + (defined(UMTX_OP_WAIT) && BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4) +#define BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY BOOST_ATOMIC_INT32_LOCK_FREE +#define BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY BOOST_ATOMIC_INT32_LOCK_FREE +#endif + +#if defined(UMTX_OP_WAIT) && BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 +#define BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY BOOST_ATOMIC_INT64_LOCK_FREE +#define BOOST_ATOMIC_HAS_NATIVE_INT64_IPC_WAIT_NOTIFY BOOST_ATOMIC_INT64_LOCK_FREE +#endif + +#endif // BOOST_ATOMIC_DETAIL_WAIT_CAPS_FREEBSD_UMTX_HPP_INCLUDED_ diff --git a/include/boost/atomic/detail/wait_caps_futex.hpp b/include/boost/atomic/detail/wait_caps_futex.hpp new file mode 100644 index 0000000..e61d62b --- /dev/null +++ b/include/boost/atomic/detail/wait_caps_futex.hpp @@ -0,0 +1,31 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2020 Andrey Semashev + */ +/*! + * \file atomic/detail/wait_caps_futex.hpp + * + * This header defines waiting/notifying operations capabilities macros. + */ + +#ifndef BOOST_ATOMIC_DETAIL_WAIT_CAPS_FUTEX_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_WAIT_CAPS_FUTEX_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_ATOMIC_DETAIL_HAS_FUTEX) +// futexes are always 32-bit and they always supported address-free operations +#define BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY BOOST_ATOMIC_INT32_LOCK_FREE +#define BOOST_ATOMIC_HAS_NATIVE_INT32_IPC_WAIT_NOTIFY BOOST_ATOMIC_INT32_LOCK_FREE +#endif // defined(BOOST_ATOMIC_DETAIL_HAS_FUTEX) + +#endif // BOOST_ATOMIC_DETAIL_WAIT_CAPS_FUTEX_HPP_INCLUDED_ diff --git a/include/boost/atomic/detail/wait_caps_windows.hpp b/include/boost/atomic/detail/wait_caps_windows.hpp new file mode 100644 index 0000000..37454b6 --- /dev/null +++ b/include/boost/atomic/detail/wait_caps_windows.hpp @@ -0,0 +1,55 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2020 Andrey Semashev + */ +/*! + * \file atomic/detail/wait_caps_windows.hpp + * + * This header defines waiting/notifying operations capabilities macros. + */ + +#ifndef BOOST_ATOMIC_DETAIL_WAIT_CAPS_WINDOWS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_WAIT_CAPS_WINDOWS_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// MSDN says WaitOnAddress, WakeByAddressSingle and WakeByAddressAll only support notifications between threads of the same process, so no address-free operations. +// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress +// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakebyaddresssingle +// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakebyaddressall + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN8 && (BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM) + +#define BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY BOOST_ATOMIC_INT8_LOCK_FREE +#define BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY BOOST_ATOMIC_INT16_LOCK_FREE +#define BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY BOOST_ATOMIC_INT32_LOCK_FREE +#define BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY BOOST_ATOMIC_INT64_LOCK_FREE + +#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN8 && (BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM) + +// Since will detect availability of WaitOnAddress etc. at run time, we have to define capability macros to 1 instead of 2 +#if BOOST_ATOMIC_INT8_LOCK_FREE > 0 +#define BOOST_ATOMIC_HAS_NATIVE_INT8_WAIT_NOTIFY 1 +#endif +#if BOOST_ATOMIC_INT16_LOCK_FREE > 0 +#define BOOST_ATOMIC_HAS_NATIVE_INT16_WAIT_NOTIFY 1 +#endif +#if BOOST_ATOMIC_INT32_LOCK_FREE > 0 +#define BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY 1 +#endif +#if BOOST_ATOMIC_INT64_LOCK_FREE > 0 +#define BOOST_ATOMIC_HAS_NATIVE_INT64_WAIT_NOTIFY 1 +#endif + +#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN8 && (BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM) + +#endif // BOOST_ATOMIC_DETAIL_WAIT_CAPS_WINDOWS_HPP_INCLUDED_ diff --git a/include/boost/atomic/detail/wait_operations_fwd.hpp b/include/boost/atomic/detail/wait_operations_fwd.hpp index dac6d5c..8497f84 100644 --- a/include/boost/atomic/detail/wait_operations_fwd.hpp +++ b/include/boost/atomic/detail/wait_operations_fwd.hpp @@ -25,7 +25,12 @@ namespace boost { namespace atomics { namespace detail { -template< typename Base, std::size_t Size = sizeof(typename Base::storage_type), bool = Base::is_always_lock_free > +template< + typename Base, + std::size_t Size = sizeof(typename Base::storage_type), + bool AlwaysLockFree = Base::is_always_lock_free, + bool Interprocess = Base::is_interprocess +> struct wait_operations; } // namespace detail diff --git a/include/boost/atomic/detail/wait_ops_dragonfly_umtx.hpp b/include/boost/atomic/detail/wait_ops_dragonfly_umtx.hpp index 7410ea4..b6a39c1 100644 --- a/include/boost/atomic/detail/wait_ops_dragonfly_umtx.hpp +++ b/include/boost/atomic/detail/wait_ops_dragonfly_umtx.hpp @@ -28,13 +28,20 @@ namespace boost { namespace atomics { namespace detail { -template< typename Base > -struct wait_operations< Base, sizeof(int), true > : +template< typename Base, bool Interprocess > +struct wait_operations< Base, sizeof(int), true, Interprocess > : public Base { typedef Base base_type; typedef typename base_type::storage_type storage_type; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = true; + + static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT + { + return true; + } + static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT { storage_type new_val = base_type::load(storage, order); diff --git a/include/boost/atomic/detail/wait_ops_emulated.hpp b/include/boost/atomic/detail/wait_ops_emulated.hpp index 1e8a07e..866d4a6 100644 --- a/include/boost/atomic/detail/wait_ops_emulated.hpp +++ b/include/boost/atomic/detail/wait_ops_emulated.hpp @@ -8,13 +8,14 @@ /*! * \file atomic/detail/wait_ops_emulated.hpp * - * This header contains emulated (lock-based) implementation of the wait/notify atomic operations. + * This header contains emulated (lock-based) implementation of the waiting and notifying atomic operations. */ #ifndef BOOST_ATOMIC_DETAIL_WAIT_OPS_EMULATED_HPP_INCLUDED_ #define BOOST_ATOMIC_DETAIL_WAIT_OPS_EMULATED_HPP_INCLUDED_ #include +#include #include #include #include @@ -28,7 +29,7 @@ namespace boost { namespace atomics { namespace detail { -//! Emulated implementation of wait/notify operations +//! Emulated implementation of waiting and notifying operations template< typename Base > struct emulated_wait_operations : public Base @@ -38,8 +39,16 @@ struct emulated_wait_operations : typedef lock_pool::scoped_lock< base_type::storage_alignment, true > scoped_lock; typedef lock_pool::scoped_wait_state< base_type::storage_alignment > scoped_wait_state; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = false; + + static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT + { + return false; + } + static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); storage_type const& s = const_cast< storage_type const& >(storage); scoped_wait_state wait_state(&storage); storage_type new_val = s; @@ -54,19 +63,21 @@ struct emulated_wait_operations : static BOOST_FORCEINLINE void notify_one(storage_type volatile& storage) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); scoped_lock lock(&storage); lock_pool::notify_one(lock.get_lock_state(), &storage); } static BOOST_FORCEINLINE void notify_all(storage_type volatile& storage) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object"); scoped_lock lock(&storage); lock_pool::notify_all(lock.get_lock_state(), &storage); } }; -template< typename Base, std::size_t Size > -struct wait_operations< Base, Size, false > : +template< typename Base, std::size_t Size, bool Interprocess > +struct wait_operations< Base, Size, false, Interprocess > : public emulated_wait_operations< Base > { }; diff --git a/include/boost/atomic/detail/wait_ops_freebsd_umtx.hpp b/include/boost/atomic/detail/wait_ops_freebsd_umtx.hpp index 8e9b723..f15297f 100644 --- a/include/boost/atomic/detail/wait_ops_freebsd_umtx.hpp +++ b/include/boost/atomic/detail/wait_ops_freebsd_umtx.hpp @@ -40,6 +40,13 @@ struct freebsd_umtx_wait_operations_common : typedef Base base_type; typedef typename base_type::storage_type storage_type; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = true; + + static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT + { + return true; + } + static BOOST_FORCEINLINE void notify_one(storage_type volatile& storage) BOOST_NOEXCEPT { ::_umtx_op(const_cast< storage_type* >(&storage), UMTX_OP_WAKE, 1u, NULL, NULL); @@ -56,8 +63,8 @@ struct freebsd_umtx_wait_operations_common : // UMTX_OP_WAIT_UINT only appeared in FreeBSD 8.0 #if defined(UMTX_OP_WAIT_UINT) && BOOST_ATOMIC_DETAIL_SIZEOF_INT < BOOST_ATOMIC_DETAIL_SIZEOF_LONG -template< typename Base > -struct wait_operations< Base, sizeof(unsigned int), true > : +template< typename Base, bool Interprocess > +struct wait_operations< Base, sizeof(unsigned int), true, Interprocess > : public freebsd_umtx_wait_operations_common< Base > { typedef freebsd_umtx_wait_operations_common< Base > base_type; @@ -80,8 +87,8 @@ struct wait_operations< Base, sizeof(unsigned int), true > : #if defined(UMTX_OP_WAIT) -template< typename Base > -struct wait_operations< Base, sizeof(unsigned long), true > : +template< typename Base, bool Interprocess > +struct wait_operations< Base, sizeof(unsigned long), true, Interprocess > : public freebsd_umtx_wait_operations_common< Base > { typedef freebsd_umtx_wait_operations_common< Base > base_type; diff --git a/include/boost/atomic/detail/wait_ops_futex.hpp b/include/boost/atomic/detail/wait_ops_futex.hpp index 7e73cbe..e518a7c 100644 --- a/include/boost/atomic/detail/wait_ops_futex.hpp +++ b/include/boost/atomic/detail/wait_ops_futex.hpp @@ -28,12 +28,19 @@ namespace atomics { namespace detail { template< typename Base > -struct wait_operations< Base, 4u, true > : +struct wait_operations< Base, 4u, true, false > : public Base { typedef Base base_type; typedef typename base_type::storage_type storage_type; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = true; + + static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT + { + return true; + } + static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT { storage_type new_val = base_type::load(storage, order); @@ -57,6 +64,43 @@ struct wait_operations< Base, 4u, true > : } }; +template< typename Base > +struct wait_operations< Base, 4u, true, true > : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = true; + + static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT + { + return true; + } + + static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT + { + storage_type new_val = base_type::load(storage, order); + while (new_val == old_val) + { + atomics::detail::futex_wait(const_cast< storage_type* >(&storage), old_val); + new_val = base_type::load(storage, order); + } + + return new_val; + } + + static BOOST_FORCEINLINE void notify_one(storage_type volatile& storage) BOOST_NOEXCEPT + { + atomics::detail::futex_signal(const_cast< storage_type* >(&storage)); + } + + static BOOST_FORCEINLINE void notify_all(storage_type volatile& storage) BOOST_NOEXCEPT + { + atomics::detail::futex_broadcast(const_cast< storage_type* >(&storage)); + } +}; + } // namespace detail } // namespace atomics } // namespace boost diff --git a/include/boost/atomic/detail/wait_ops_generic.hpp b/include/boost/atomic/detail/wait_ops_generic.hpp index da2918c..97b35f6 100644 --- a/include/boost/atomic/detail/wait_ops_generic.hpp +++ b/include/boost/atomic/detail/wait_ops_generic.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -29,8 +30,11 @@ namespace atomics { namespace detail { //! Generic implementation of wait/notify operations +template< typename Base, bool Interprocess > +struct generic_wait_operations; + template< typename Base > -struct generic_wait_operations : +struct generic_wait_operations< Base, false > : public Base { typedef Base base_type; @@ -38,6 +42,13 @@ struct generic_wait_operations : typedef lock_pool::scoped_lock< base_type::storage_alignment, true > scoped_lock; typedef lock_pool::scoped_wait_state< base_type::storage_alignment > scoped_wait_state; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = false; + + static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT + { + return false; + } + static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT { storage_type new_val = base_type::load(storage, order); @@ -68,9 +79,57 @@ struct generic_wait_operations : } }; -template< typename Base, std::size_t Size > -struct wait_operations< Base, Size, true > : - public generic_wait_operations< Base > +template< typename Base > +struct generic_wait_operations< Base, true > : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = false; + + static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT + { + return false; + } + + static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT + { + storage_type new_val = base_type::load(storage, order); + if (new_val == old_val) + { + for (unsigned int i = 0u; i < 16u; ++i) + { + atomics::detail::pause(); + new_val = base_type::load(storage, order); + if (new_val != old_val) + goto finish; + } + + do + { + atomics::detail::wait_some(); + new_val = base_type::load(storage, order); + } + while (new_val == old_val); + } + + finish: + return new_val; + } + + static BOOST_FORCEINLINE void notify_one(storage_type volatile& storage) BOOST_NOEXCEPT + { + } + + static BOOST_FORCEINLINE void notify_all(storage_type volatile& storage) BOOST_NOEXCEPT + { + } +}; + +template< typename Base, std::size_t Size, bool Interprocess > +struct wait_operations< Base, Size, true, Interprocess > : + public generic_wait_operations< Base, Interprocess > { }; diff --git a/include/boost/atomic/detail/wait_ops_windows.hpp b/include/boost/atomic/detail/wait_ops_windows.hpp index c55b72b..0e1d337 100644 --- a/include/boost/atomic/detail/wait_ops_windows.hpp +++ b/include/boost/atomic/detail/wait_ops_windows.hpp @@ -61,11 +61,19 @@ BOOST_FORCEINLINE void ensure_wait_functions_initialized() BOOST_NOEXCEPT template< typename Base, std::size_t Size > struct windows_wait_operations : - public atomics::detail::generic_wait_operations< Base > + public atomics::detail::generic_wait_operations< Base, false > { - typedef atomics::detail::generic_wait_operations< Base > base_type; + typedef atomics::detail::generic_wait_operations< Base, false > base_type; typedef typename base_type::storage_type storage_type; + static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = false; + + static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT + { + ensure_wait_functions_initialized(); + return atomics::detail::wait_on_address != NULL; + } + static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT { ensure_wait_functions_initialized(); @@ -109,25 +117,25 @@ struct windows_wait_operations : }; template< typename Base > -struct wait_operations< Base, 1u, true > : +struct wait_operations< Base, 1u, true, false > : public windows_wait_operations< Base, 1u > { }; template< typename Base > -struct wait_operations< Base, 2u, true > : +struct wait_operations< Base, 2u, true, false > : public windows_wait_operations< Base, 2u > { }; template< typename Base > -struct wait_operations< Base, 4u, true > : +struct wait_operations< Base, 4u, true, false > : public windows_wait_operations< Base, 4u > { }; template< typename Base > -struct wait_operations< Base, 8u, true > : +struct wait_operations< Base, 8u, true, false > : public windows_wait_operations< Base, 8u > { }; diff --git a/include/boost/atomic/ipc_atomic.hpp b/include/boost/atomic/ipc_atomic.hpp new file mode 100644 index 0000000..4710d0c --- /dev/null +++ b/include/boost/atomic/ipc_atomic.hpp @@ -0,0 +1,92 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2020 Andrey Semashev + */ +/*! + * \file atomic/ipc_atomic.hpp + * + * This header contains definition of \c ipc_atomic template. + */ + +#ifndef BOOST_ATOMIC_IPC_ATOMIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_IPC_ATOMIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// 'boost::atomics::ipc_atomic' : multiple assignment operators specified +#pragma warning(disable: 4522) +#endif + +namespace boost { +namespace atomics { + +//! Atomic object for inter-process communication +template< typename T > +class ipc_atomic : + public atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type, true > +{ +private: + typedef atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type, true > base_type; + typedef typename base_type::value_arg_type value_arg_type; + +public: + typedef typename base_type::value_type value_type; + + BOOST_STATIC_ASSERT_MSG(sizeof(value_type) > 0u, "boost::ipc_atomic requires T to be a complete type"); +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_IS_TRIVIALLY_COPYABLE) + BOOST_STATIC_ASSERT_MSG(atomics::detail::is_trivially_copyable< value_type >::value, "boost::ipc_atomic requires T to be a trivially copyable type"); +#endif + +public: + BOOST_DEFAULTED_FUNCTION(ipc_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE BOOST_ATOMIC_DETAIL_CONSTEXPR_UNION_INIT ipc_atomic(value_arg_type v) BOOST_NOEXCEPT : base_type(v) {} + + BOOST_FORCEINLINE value_type operator= (value_arg_type v) BOOST_NOEXCEPT + { + this->store(v); + return v; + } + + BOOST_FORCEINLINE value_type operator= (value_arg_type v) volatile BOOST_NOEXCEPT + { + this->store(v); + return v; + } + + BOOST_FORCEINLINE operator value_type() const volatile BOOST_NOEXCEPT + { + return this->load(); + } + + BOOST_DELETED_FUNCTION(ipc_atomic(ipc_atomic const&)) + BOOST_DELETED_FUNCTION(ipc_atomic& operator= (ipc_atomic const&)) + BOOST_DELETED_FUNCTION(ipc_atomic& operator= (ipc_atomic const&) volatile) +}; + +} // namespace atomics + +using atomics::ipc_atomic; + +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_IPC_ATOMIC_HPP_INCLUDED_ diff --git a/include/boost/atomic/ipc_atomic_flag.hpp b/include/boost/atomic/ipc_atomic_flag.hpp new file mode 100644 index 0000000..38d84a8 --- /dev/null +++ b/include/boost/atomic/ipc_atomic_flag.hpp @@ -0,0 +1,37 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2020 Andrey Semashev + */ +/*! + * \file atomic/ipc_atomic_flag.hpp + * + * This header contains definition of \c ipc_atomic_flag. + */ + +#ifndef BOOST_ATOMIC_IPC_ATOMIC_FLAG_HPP_INCLUDED_ +#define BOOST_ATOMIC_IPC_ATOMIC_FLAG_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { + +//! Atomic flag for inter-process communication +typedef atomics::detail::atomic_flag_impl< true > ipc_atomic_flag; + +} // namespace atomics + +using atomics::ipc_atomic_flag; + +} // namespace boost + +#endif // BOOST_ATOMIC_IPC_ATOMIC_FLAG_HPP_INCLUDED_ diff --git a/include/boost/atomic/ipc_atomic_ref.hpp b/include/boost/atomic/ipc_atomic_ref.hpp new file mode 100644 index 0000000..17e73d4 --- /dev/null +++ b/include/boost/atomic/ipc_atomic_ref.hpp @@ -0,0 +1,92 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2020 Andrey Semashev + */ +/*! + * \file atomic/ipc_atomic_ref.hpp + * + * This header contains definition of \c ipc_atomic_ref template. + */ + +#ifndef BOOST_ATOMIC_IPC_ATOMIC_REF_HPP_INCLUDED_ +#define BOOST_ATOMIC_IPC_ATOMIC_REF_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// 'boost::atomics::ipc_atomic_ref' : multiple assignment operators specified +#pragma warning(disable: 4522) +#endif + +namespace boost { +namespace atomics { + +//! Atomic reference to external object for inter-process communication +template< typename T > +class ipc_atomic_ref : + public atomics::detail::base_atomic_ref< T, typename atomics::detail::classify< T >::type, true > +{ +private: + typedef atomics::detail::base_atomic_ref< T, typename atomics::detail::classify< T >::type, true > base_type; + typedef typename base_type::value_arg_type value_arg_type; + +public: + typedef typename base_type::value_type value_type; + + BOOST_STATIC_ASSERT_MSG(sizeof(value_type) > 0u, "boost::ipc_atomic_ref requires T to be a complete type"); +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_IS_TRIVIALLY_COPYABLE) + BOOST_STATIC_ASSERT_MSG(atomics::detail::is_trivially_copyable< value_type >::value, "boost::ipc_atomic_ref requires T to be a trivially copyable type"); +#endif + +private: + typedef typename base_type::storage_type storage_type; + +public: + BOOST_DEFAULTED_FUNCTION(ipc_atomic_ref(ipc_atomic_ref const& that) BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL : base_type(static_cast< base_type const& >(that)) {}) + BOOST_FORCEINLINE explicit ipc_atomic_ref(value_type& v) BOOST_NOEXCEPT : base_type(v) + { + // Check that referenced object alignment satisfies required alignment + BOOST_ASSERT((((atomics::detail::uintptr_t)this->m_value) & (base_type::required_alignment - 1u)) == 0u); + } + + BOOST_FORCEINLINE value_type operator= (value_arg_type v) const BOOST_NOEXCEPT + { + this->store(v); + return v; + } + + BOOST_FORCEINLINE operator value_type() const BOOST_NOEXCEPT + { + return this->load(); + } + + BOOST_DELETED_FUNCTION(ipc_atomic_ref& operator= (ipc_atomic_ref const&)) +}; + +} // namespace atomics + +using atomics::ipc_atomic_ref; + +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_IPC_ATOMIC_REF_HPP_INCLUDED_ diff --git a/src/lock_pool.cpp b/src/lock_pool.cpp index 25b3bb7..9c002c6 100644 --- a/src/lock_pool.cpp +++ b/src/lock_pool.cpp @@ -288,7 +288,7 @@ inline void wait_state::wait(lock_state& state) BOOST_NOEXCEPT #elif defined(BOOST_ATOMIC_USE_FUTEX) -typedef atomics::detail::operations< 4u, false > futex_operations; +typedef atomics::detail::operations< 4u, false, false > futex_operations; // The storage type must be a 32-bit object, as required by futex API BOOST_STATIC_ASSERT_MSG(futex_operations::is_always_lock_free && sizeof(futex_operations::storage_type) == 4u, "Boost.Atomic unsupported target platform: native atomic operations not implemented for 32-bit integers"); typedef atomics::detail::extra_operations< futex_operations, futex_operations::storage_size, futex_operations::is_signed > futex_extra_operations; @@ -533,7 +533,7 @@ inline void wait_state::wait(lock_state& state) BOOST_NOEXCEPT #else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 -typedef atomics::detail::operations< 4u, false > mutex_operations; +typedef atomics::detail::operations< 4u, false, false > mutex_operations; BOOST_STATIC_ASSERT_MSG(mutex_operations::is_always_lock_free, "Boost.Atomic unsupported target platform: native atomic operations not implemented for 32-bit integers"); namespace fallback_mutex_bits { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 298c9df..de91648 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -31,6 +31,10 @@ test-suite atomic [ run wait_ref_api.cpp : : : BOOST_ATOMIC_FORCE_FALLBACK : fallback_wait_ref_api ] [ run wait_fuzz.cpp ] [ run wait_fuzz.cpp : : : BOOST_ATOMIC_FORCE_FALLBACK : fallback_wait_fuzz ] + [ run ipc_atomic_api.cpp ] + [ run ipc_atomic_ref_api.cpp ] + [ run ipc_wait_api.cpp ] + [ run ipc_wait_ref_api.cpp ] [ run atomicity.cpp ] [ run atomicity_ref.cpp ] [ run ordering.cpp ] diff --git a/test/api_test_helpers.hpp b/test/api_test_helpers.hpp index 91d7d65..24b106d 100644 --- a/test/api_test_helpers.hpp +++ b/test/api_test_helpers.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -32,17 +33,49 @@ const unsigned int max_weak_cas_loops = 1000; -/* provide helpers that exercise whether the API -functions of "boost::atomic" provide the correct -operational semantic in the case of sequential -execution */ +template< typename T > +struct is_atomic : + public boost::false_type +{ +}; +template< typename T > +struct is_atomic< boost::atomic< T > > : + public boost::true_type +{ +}; + +template< typename T > +struct is_atomic< boost::ipc_atomic< T > > : + public boost::true_type +{ +}; + +template< typename T > +struct is_atomic_ref : + public boost::false_type +{ +}; + +template< typename T > +struct is_atomic_ref< boost::atomic_ref< T > > : + public boost::true_type +{ +}; + +template< typename T > +struct is_atomic_ref< boost::ipc_atomic_ref< T > > : + public boost::true_type +{ +}; + +template< typename Flag > inline void test_flag_api(void) { #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT - boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT; + Flag f = BOOST_ATOMIC_FLAG_INIT; #else - boost::atomic_flag f; + Flag f; #endif BOOST_TEST( !f.test() ); @@ -56,22 +89,22 @@ inline void test_flag_api(void) } template< typename T > -inline void test_atomic_type_traits(boost::type< boost::atomic< T > >) +inline typename boost::enable_if< is_atomic< T > >::type test_atomic_type_traits(boost::type< T >) { - BOOST_TEST_GE(sizeof(boost::atomic< T >), sizeof(T)); + BOOST_TEST_GE(sizeof(T), sizeof(typename T::value_type)); } template< typename T > -inline void test_atomic_type_traits(boost::type< boost::atomic_ref< T > >) +inline typename boost::enable_if< is_atomic_ref< T > >::type test_atomic_type_traits(boost::type< T >) { - if (boost::atomic_ref< T >::is_always_lock_free) + if (T::is_always_lock_free) { - BOOST_TEST_GE(boost::atomic_ref< T >::required_alignment, boost::alignment_of< T >::value); + BOOST_TEST_GE(T::required_alignment, boost::alignment_of< typename T::value_type >::value); } else { // Lock-based implementation should not require alignment higher than alignof(T) - BOOST_TEST_EQ(boost::atomic_ref< T >::required_alignment, boost::alignment_of< T >::value); + BOOST_TEST_EQ(T::required_alignment, boost::alignment_of< typename T::value_type >::value); } } diff --git a/test/atomic_api.cpp b/test/atomic_api.cpp index 4704e55..d3058fa 100644 --- a/test/atomic_api.cpp +++ b/test/atomic_api.cpp @@ -14,7 +14,7 @@ int main(int, char *[]) { - test_flag_api(); + test_flag_api< boost::atomic_flag >(); test_integral_api< atomic_wrapper, char >(); test_integral_api< atomic_wrapper, signed char >(); diff --git a/test/atomic_wrapper.hpp b/test/atomic_wrapper.hpp index 875e41c..0a04062 100644 --- a/test/atomic_wrapper.hpp +++ b/test/atomic_wrapper.hpp @@ -9,7 +9,8 @@ #include #include -#include +#include +#include #include #include "aligned_object.hpp" @@ -40,4 +41,31 @@ struct atomic_ref_wrapper explicit atomic_ref_wrapper(T const& value) : object(value), a(object.get()) {} }; +//! Wrapper type for ipc_atomic template +template< typename T > +struct ipc_atomic_wrapper +{ + typedef boost::ipc_atomic< T > atomic_type; + typedef atomic_type& atomic_reference_type; + + atomic_type a; + + BOOST_DEFAULTED_FUNCTION(ipc_atomic_wrapper(), {}) + explicit ipc_atomic_wrapper(T const& value) : a(value) {} +}; + +//! Wrapper type for atomic_ref template +template< typename T > +struct ipc_atomic_ref_wrapper +{ + typedef boost::ipc_atomic_ref< T > atomic_type; + typedef atomic_type const& atomic_reference_type; + + aligned_object< T, atomic_type::required_alignment > object; + const atomic_type a; + + ipc_atomic_ref_wrapper() : a(object.get()) {} + explicit ipc_atomic_ref_wrapper(T const& value) : object(value), a(object.get()) {} +}; + #endif // BOOST_ATOMIC_TEST_ATOMIC_WRAPPER_HPP_INCLUDED_ diff --git a/test/ipc_atomic_api.cpp b/test/ipc_atomic_api.cpp new file mode 100644 index 0000000..493e975 --- /dev/null +++ b/test/ipc_atomic_api.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2020 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#include +#include + +#include "api_test_helpers.hpp" + +int main(int, char *[]) +{ +#if BOOST_ATOMIC_FLAG_LOCK_FREE == 2 + test_flag_api< boost::ipc_atomic_flag >(); +#endif + +#if BOOST_ATOMIC_INT8_LOCK_FREE == 2 + test_integral_api< ipc_atomic_wrapper, boost::uint8_t >(); + test_integral_api< ipc_atomic_wrapper, boost::int8_t >(); +#endif +#if BOOST_ATOMIC_INT16_LOCK_FREE == 2 + test_integral_api< ipc_atomic_wrapper, boost::uint16_t >(); + test_integral_api< ipc_atomic_wrapper, boost::int16_t >(); +#endif +#if BOOST_ATOMIC_INT32_LOCK_FREE == 2 + test_integral_api< ipc_atomic_wrapper, boost::uint32_t >(); + test_integral_api< ipc_atomic_wrapper, boost::int32_t >(); +#endif +#if BOOST_ATOMIC_INT64_LOCK_FREE == 2 + test_integral_api< ipc_atomic_wrapper, boost::uint64_t >(); + test_integral_api< ipc_atomic_wrapper, boost::int64_t >(); +#endif +#if defined(BOOST_HAS_INT128) && !defined(BOOST_ATOMIC_TESTS_NO_INT128) && BOOST_ATOMIC_INT128_LOCK_FREE == 2 + test_integral_api< ipc_atomic_wrapper, boost::int128_type >(); + test_integral_api< ipc_atomic_wrapper, boost::uint128_type >(); +#endif + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#if BOOST_ATOMIC_FLOAT_LOCK_FREE == 2 + test_floating_point_api< ipc_atomic_wrapper, float >(); +#endif +#if BOOST_ATOMIC_DOUBLE_LOCK_FREE == 2 + test_floating_point_api< ipc_atomic_wrapper, double >(); +#endif +#if BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE == 2 + test_floating_point_api< ipc_atomic_wrapper, long double >(); +#endif +#if defined(BOOST_HAS_FLOAT128) && !defined(BOOST_ATOMIC_TESTS_NO_FLOAT128) && BOOST_ATOMIC_FLOAT128_LOCK_FREE == 2 + test_floating_point_api< ipc_atomic_wrapper, boost::float128_type >(); +#endif +#endif + +#if BOOST_ATOMIC_POINTER_LOCK_FREE == 2 + test_pointer_api< ipc_atomic_wrapper, int >(); +#endif + +#if BOOST_ATOMIC_INT_LOCK_FREE == 2 + test_enum_api< ipc_atomic_wrapper >(); +#endif + + return boost::report_errors(); +} diff --git a/test/ipc_atomic_ref_api.cpp b/test/ipc_atomic_ref_api.cpp new file mode 100644 index 0000000..b686ff6 --- /dev/null +++ b/test/ipc_atomic_ref_api.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2020 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include +#include + +#include "api_test_helpers.hpp" + +int main(int, char *[]) +{ +#if BOOST_ATOMIC_INT8_LOCK_FREE == 2 + test_integral_api< ipc_atomic_ref_wrapper, boost::uint8_t >(); + test_integral_api< ipc_atomic_ref_wrapper, boost::int8_t >(); +#endif +#if BOOST_ATOMIC_INT16_LOCK_FREE == 2 + test_integral_api< ipc_atomic_ref_wrapper, boost::uint16_t >(); + test_integral_api< ipc_atomic_ref_wrapper, boost::int16_t >(); +#endif +#if BOOST_ATOMIC_INT32_LOCK_FREE == 2 + test_integral_api< ipc_atomic_ref_wrapper, boost::uint32_t >(); + test_integral_api< ipc_atomic_ref_wrapper, boost::int32_t >(); +#endif +#if BOOST_ATOMIC_INT64_LOCK_FREE == 2 + test_integral_api< ipc_atomic_ref_wrapper, boost::uint64_t >(); + test_integral_api< ipc_atomic_ref_wrapper, boost::int64_t >(); +#endif +#if defined(BOOST_HAS_INT128) && !defined(BOOST_ATOMIC_TESTS_NO_INT128) && BOOST_ATOMIC_INT128_LOCK_FREE == 2 + test_integral_api< ipc_atomic_ref_wrapper, boost::int128_type >(); + test_integral_api< ipc_atomic_ref_wrapper, boost::uint128_type >(); +#endif + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#if BOOST_ATOMIC_FLOAT_LOCK_FREE == 2 + test_floating_point_api< ipc_atomic_ref_wrapper, float >(); +#endif +#if BOOST_ATOMIC_DOUBLE_LOCK_FREE == 2 + test_floating_point_api< ipc_atomic_ref_wrapper, double >(); +#endif +#if BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE == 2 + test_floating_point_api< ipc_atomic_ref_wrapper, long double >(); +#endif +#if defined(BOOST_HAS_FLOAT128) && !defined(BOOST_ATOMIC_TESTS_NO_FLOAT128) && BOOST_ATOMIC_FLOAT128_LOCK_FREE == 2 + test_floating_point_api< ipc_atomic_ref_wrapper, boost::float128_type >(); +#endif +#endif + +#if BOOST_ATOMIC_POINTER_LOCK_FREE == 2 + test_pointer_api< ipc_atomic_ref_wrapper, int >(); +#endif + +#if BOOST_ATOMIC_INT_LOCK_FREE == 2 + test_enum_api< ipc_atomic_ref_wrapper >(); +#endif + + return boost::report_errors(); +} diff --git a/test/ipc_wait_api.cpp b/test/ipc_wait_api.cpp new file mode 100644 index 0000000..2852472 --- /dev/null +++ b/test/ipc_wait_api.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2020 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#include +#include + +#include "ipc_wait_test_helpers.hpp" + +int main(int, char *[]) +{ +#if BOOST_ATOMIC_FLAG_LOCK_FREE == 2 + test_flag_wait_notify_api(); +#endif + +#if BOOST_ATOMIC_INT8_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_wrapper, boost::uint8_t >(1, 2, 3); +#endif +#if BOOST_ATOMIC_INT16_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_wrapper, boost::uint16_t >(1, 2, 3); +#endif +#if BOOST_ATOMIC_INT32_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_wrapper, boost::uint32_t >(1, 2, 3); +#endif +#if BOOST_ATOMIC_INT64_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_wrapper, boost::uint64_t >(1, 2, 3); +#endif +#if defined(BOOST_HAS_INT128) && !defined(BOOST_ATOMIC_TESTS_NO_INT128) && BOOST_ATOMIC_INT128_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_wrapper, boost::uint128_type >(1, 2, 3); +#endif + + return boost::report_errors(); +} diff --git a/test/ipc_wait_ref_api.cpp b/test/ipc_wait_ref_api.cpp new file mode 100644 index 0000000..6914589 --- /dev/null +++ b/test/ipc_wait_ref_api.cpp @@ -0,0 +1,34 @@ +// Copyright (c) 2020 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include +#include + +#include "ipc_wait_test_helpers.hpp" + +int main(int, char *[]) +{ +#if BOOST_ATOMIC_INT8_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_ref_wrapper, boost::uint8_t >(1, 2, 3); +#endif +#if BOOST_ATOMIC_INT16_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_ref_wrapper, boost::uint16_t >(1, 2, 3); +#endif +#if BOOST_ATOMIC_INT32_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_ref_wrapper, boost::uint32_t >(1, 2, 3); +#endif +#if BOOST_ATOMIC_INT64_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_ref_wrapper, boost::uint64_t >(1, 2, 3); +#endif +#if defined(BOOST_HAS_INT128) && !defined(BOOST_ATOMIC_TESTS_NO_INT128) && BOOST_ATOMIC_INT128_LOCK_FREE == 2 + test_wait_notify_api< ipc_atomic_ref_wrapper, boost::uint128_type >(1, 2, 3); +#endif + + return boost::report_errors(); +} diff --git a/test/ipc_wait_test_helpers.hpp b/test/ipc_wait_test_helpers.hpp new file mode 100644 index 0000000..380268a --- /dev/null +++ b/test/ipc_wait_test_helpers.hpp @@ -0,0 +1,309 @@ +// Copyright (c) 2020 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_ATOMIC_TEST_IPC_WAIT_TEST_HELPERS_HPP_INCLUDED_ +#define BOOST_ATOMIC_TEST_IPC_WAIT_TEST_HELPERS_HPP_INCLUDED_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "atomic_wrapper.hpp" +#include "lightweight_test_stream.hpp" + +namespace chrono = boost::chrono; + +#if defined(BOOST_CHRONO_HAS_CLOCK_STEADY) +typedef chrono::steady_clock test_clock; +#else +typedef chrono::system_clock test_clock; +#endif + +//! Since some of the tests below are allowed to fail, we retry up to this many times to pass the test +BOOST_CONSTEXPR_OR_CONST unsigned int test_retry_count = 5u; + +//! The test verifies that the wait operation returns immediately if the passed value does not match the atomic value +template< template< typename > class Wrapper, typename T > +inline void test_wait_value_mismatch(T value1, T value2) +{ + Wrapper< T > m_wrapper(value1); + + T received_value = m_wrapper.a.wait(value2); + BOOST_TEST(received_value == value1); +} + +/*! + * The test verifies that notify_one releases one blocked thread and that the released thread receives the modified atomic value. + * + * Technically, this test is allowed to fail since wait() is allowed to return spuriously. However, normally this should not happen. + */ +template< template< typename > class Wrapper, typename T > +class notify_one_test +{ +private: + struct thread_state + { + T m_received_value; + test_clock::time_point m_wakeup_time; + + explicit thread_state(T value) : m_received_value(value) + { + } + }; + +private: + Wrapper< T > m_wrapper; + + char m_padding[1024]; + + T m_value1, m_value2, m_value3; + + boost::barrier m_barrier; + + thread_state m_thread1_state; + thread_state m_thread2_state; + +public: + explicit notify_one_test(T value1, T value2, T value3) : + m_wrapper(value1), + m_value1(value1), + m_value2(value2), + m_value3(value3), + m_barrier(3), + m_thread1_state(value1), + m_thread2_state(value1) + { + } + + bool run() + { + boost::thread thread1(¬ify_one_test::thread_func, this, &m_thread1_state); + boost::thread thread2(¬ify_one_test::thread_func, this, &m_thread2_state); + + m_barrier.wait(); + + test_clock::time_point start_time = test_clock::now(); + + boost::this_thread::sleep_for(chrono::milliseconds(200)); + + m_wrapper.a.store(m_value2, boost::memory_order_release); + m_wrapper.a.notify_one(); + + boost::this_thread::sleep_for(chrono::milliseconds(200)); + + m_wrapper.a.store(m_value3, boost::memory_order_release); + m_wrapper.a.notify_one(); + + if (!thread1.try_join_for(chrono::seconds(3))) + { + BOOST_ERROR("Thread 1 failed to join"); + std::abort(); + } + if (!thread2.try_join_for(chrono::seconds(3))) + { + BOOST_ERROR("Thread 2 failed to join"); + std::abort(); + } + + thread_state* first_state = &m_thread1_state; + thread_state* second_state = &m_thread2_state; + if (second_state->m_wakeup_time < first_state->m_wakeup_time) + std::swap(first_state, second_state); + + if (m_wrapper.a.has_native_wait_notify()) + { + if ((first_state->m_wakeup_time - start_time) < chrono::milliseconds(200)) + { + std::cout << "notify_one_test: first thread woke up too soon: " << chrono::duration_cast< chrono::milliseconds >(first_state->m_wakeup_time - start_time).count() << " ms" << std::endl; + return false; + } + + if ((second_state->m_wakeup_time - start_time) < chrono::milliseconds(400)) + { + std::cout << "notify_one_test: second thread woke up too soon: " << chrono::duration_cast< chrono::milliseconds >(second_state->m_wakeup_time - start_time).count() << " ms" << std::endl; + return false; + } + + BOOST_TEST_EQ(first_state->m_received_value, m_value2); + BOOST_TEST_EQ(second_state->m_received_value, m_value3); + } + else + { + // With the emulated wait/notify the threads are most likely to return prior to notify + BOOST_TEST_EQ(first_state->m_received_value, m_value2); + BOOST_TEST(second_state->m_received_value == m_value2 || second_state->m_received_value == m_value3); + } + + return true; + } + +private: + void thread_func(thread_state* state) + { + m_barrier.wait(); + + state->m_received_value = m_wrapper.a.wait(m_value1); + state->m_wakeup_time = test_clock::now(); + } +}; + +template< template< typename > class Wrapper, typename T > +inline void test_notify_one(T value1, T value2, T value3) +{ + for (unsigned int i = 0u; i < test_retry_count; ++i) + { + notify_one_test< Wrapper, T > test(value1, value2, value3); + if (test.run()) + return; + } + + BOOST_ERROR("notify_one_test could not complete because blocked thread wake up too soon"); +} + +/*! + * The test verifies that notify_all releases all blocked threads and that the released threads receive the modified atomic value. + * + * Technically, this test is allowed to fail since wait() is allowed to return spuriously. However, normally this should not happen. + */ +template< template< typename > class Wrapper, typename T > +class notify_all_test +{ +private: + struct thread_state + { + T m_received_value; + test_clock::time_point m_wakeup_time; + + explicit thread_state(T value) : m_received_value(value) + { + } + }; + +private: + Wrapper< T > m_wrapper; + + char m_padding[1024]; + + T m_value1, m_value2; + + boost::barrier m_barrier; + + thread_state m_thread1_state; + thread_state m_thread2_state; + +public: + explicit notify_all_test(T value1, T value2) : + m_wrapper(value1), + m_value1(value1), + m_value2(value2), + m_barrier(3), + m_thread1_state(value1), + m_thread2_state(value1) + { + } + + bool run() + { + boost::thread thread1(¬ify_all_test::thread_func, this, &m_thread1_state); + boost::thread thread2(¬ify_all_test::thread_func, this, &m_thread2_state); + + m_barrier.wait(); + + test_clock::time_point start_time = test_clock::now(); + + boost::this_thread::sleep_for(chrono::milliseconds(200)); + + m_wrapper.a.store(m_value2, boost::memory_order_release); + m_wrapper.a.notify_all(); + + if (!thread1.try_join_for(chrono::seconds(3))) + { + BOOST_ERROR("Thread 1 failed to join"); + std::abort(); + } + if (!thread2.try_join_for(chrono::seconds(3))) + { + BOOST_ERROR("Thread 2 failed to join"); + std::abort(); + } + + if (m_wrapper.a.has_native_wait_notify()) + { + if ((m_thread1_state.m_wakeup_time - start_time) < chrono::milliseconds(200)) + { + std::cout << "notify_all_test: first thread woke up too soon: " << chrono::duration_cast< chrono::milliseconds >(m_thread1_state.m_wakeup_time - start_time).count() << " ms" << std::endl; + return false; + } + + if ((m_thread2_state.m_wakeup_time - start_time) < chrono::milliseconds(200)) + { + std::cout << "notify_all_test: second thread woke up too soon: " << chrono::duration_cast< chrono::milliseconds >(m_thread2_state.m_wakeup_time - start_time).count() << " ms" << std::endl; + return false; + } + } + + BOOST_TEST_EQ(m_thread1_state.m_received_value, m_value2); + BOOST_TEST_EQ(m_thread2_state.m_received_value, m_value2); + + return true; + } + +private: + void thread_func(thread_state* state) + { + m_barrier.wait(); + + state->m_received_value = m_wrapper.a.wait(m_value1); + state->m_wakeup_time = test_clock::now(); + } +}; + +template< template< typename > class Wrapper, typename T > +inline void test_notify_all(T value1, T value2) +{ + for (unsigned int i = 0u; i < test_retry_count; ++i) + { + notify_all_test< Wrapper, T > test(value1, value2); + if (test.run()) + return; + } + + BOOST_ERROR("notify_all_test could not complete because blocked thread wake up too soon"); +} + +//! Invokes all wait/notify tests +template< template< typename > class Wrapper, typename T > +void test_wait_notify_api(T value1, T value2, T value3) +{ + test_wait_value_mismatch< Wrapper >(value1, value2); + test_notify_one< Wrapper >(value1, value2, value3); + test_notify_all< Wrapper >(value1, value2); +} + + +inline void test_flag_wait_notify_api() +{ +#ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT + boost::ipc_atomic_flag f = BOOST_ATOMIC_FLAG_INIT; +#else + boost::ipc_atomic_flag f; +#endif + + bool received_value = f.wait(true); + BOOST_TEST(!received_value); + f.notify_one(); + f.notify_all(); +} + +#endif // BOOST_ATOMIC_TEST_IPC_WAIT_TEST_HELPERS_HPP_INCLUDED_ diff --git a/test/wait_api.cpp b/test/wait_api.cpp index cfb753a..2cce1af 100644 --- a/test/wait_api.cpp +++ b/test/wait_api.cpp @@ -4,7 +4,9 @@ // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include +#include +#include +#include #include #include diff --git a/test/wait_fuzz.cpp b/test/wait_fuzz.cpp index a6d94f5..f944d39 100644 --- a/test/wait_fuzz.cpp +++ b/test/wait_fuzz.cpp @@ -10,7 +10,8 @@ // while incrementing the atomic object. The test ends when the atomic counter reaches the predefined limit. // The goal of the test is to verify that (a) it doesn't crash and (b) all threads get unblocked in the end. -#include +#include +#include #include #include diff --git a/test/wait_ref_api.cpp b/test/wait_ref_api.cpp index fe60c0d..48028db 100644 --- a/test/wait_ref_api.cpp +++ b/test/wait_ref_api.cpp @@ -4,7 +4,8 @@ // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include +#include +#include #include #include diff --git a/test/wait_test_helpers.hpp b/test/wait_test_helpers.hpp index 06c8307..adb0f72 100644 --- a/test/wait_test_helpers.hpp +++ b/test/wait_test_helpers.hpp @@ -7,7 +7,8 @@ #ifndef BOOST_ATOMIC_TEST_WAIT_TEST_HELPERS_HPP_INCLUDED_ #define BOOST_ATOMIC_TEST_WAIT_TEST_HELPERS_HPP_INCLUDED_ -#include +#include +#include #include #include