This is a Boost.Atomic extension over std::atomic.
Bitwise operations can be useful if the enumeration is used to implement
a bit mask or a set of flags. Without these operations, users have to
manually perform conversions between the enum type and the underlying
type, which can be tedious.
There are caveats with enums with non-fixed underlying type, but the
convenience outweighs the potential pitfalls.
Although smt_pause matches the equivalent global function on Solaris and
some BSD systems both in name and behavior, this naming clash may cause
confusion and ambiguities in users' code that imports boost::atomics
namespace into their scope and calls smt_pause unqualified. Better
avoid these issues and pick a different name.
Add a simple test for thread_pause, which only tests that the operation
compiles and executes.
Also include the recently added headers in the global atomic.hpp.
The smt_pause() operation may be useful in spin loops to release CPU
resources for use in simpling threads on SMT-capable CPUs.
Compared to the previous pause() implementation, added support for
PowerPC and Solaris and use isb instruction on AArch64, which seems
to be used in various open source projects instead of yield.
Boost.Atomic unconditionally writes to `expected` upon returning from
compare_exchange in most backends, and this behavior is documented. This
is different from std::atomic, which only writes to `expected` if
compare_exchange returns false. This may be a significant difference,
if `expected` references data that is supposed to be protected by
the atomic via the memory order constraint.
Added a note in the docs that highlights this difference. Since this
is a documented behavior, and relying on the strict std::atomic-conforming
behavior is probably not a good idea in practice anyway (i.e. such code
would be dubious at best), the implementation is left as is. The generated
code may be slightly more efficient this way, too, since there is one less
branch. We may revisit this later, if there appears a stronger incentive
to be more C++ standard compliant.
As a result of dependent libraries dropping support for C++03, Boost.Atomic
is no longer able to support C++03 and now requires C++11 as a minimum.
Drop C++03 compilers from the CI and update docs accordingly. No code changes
at this time.
The new macro disables ulock-based implementation of waiting and notifying
operations on Darwin systems. This may be useful to comply with Apple
App Store requirements.
Closes https://github.com/boostorg/atomic/issues/55.
This is in line with the C++20 change that requires the default constructor
of std::atomic to value initialize the atomic object.
Also, use is_nothrow_default_constructible to properly deduce noexceptness
of the default constructors of atomics.
This allows to mark bitwise_cast constexpr when the conditions to use
bit_cast are met:
- both source and target types have the same size, and
- the source type has no padding bits.
The latter is checked using has_unique_object_representations trait, which
we also implement using intrinsics when not available in the standard
library.
This allows atomic constructors to become constexpr for structs and floating
point types with no padding and whose size matches the atomic storage size.
Use __builtin_clear_padding and __builtin_zero_non_value_bits that were
introduced in gcc 11 and MSVC 19.27 to clear the padding bits in atomic
types. The intrinsics are used in bitwise_cast and atomic reference
constructors.
Also, separated atomic impl specializations for enums to allow using
static_cast to convert values to storage. This in turn allows to
relax compiler requirements to mark atomic constructors constexpr.
Updated docs and added tests for structs with padding and constexpr
atomic constructors.
This works around spurious test failures on Mac OS as the notifying operation
sometimes fails with ENOENT. Presumably, the OS sometimes invalidates the
internal identification of the stack memory region, which makes __ulock_wake
fail to find the ulock object that other threads are blocked on.
By using dynamic memory we (hopefully) are using a location in a normal mapped
memory region that should not be mangled by the OS. Ideally, we would use
process-shared memory for this test, but that makes it more difficult to make
it portable and runnable in parallel. Dynamic local memory should do for now.
mfence is more expensive on most recent CPUs than a lock-prefixed instruction
on a dummy location, while the latter is sufficient to implement sequential
consistency on x86. Some performance test results are available here:
https://shipilev.net/blog/2014/on-the-fence-with-dependencies/
Also, for seq_cst stores in gcc_atomic backend, use an xchg instead of
mov+mfence, which are generated by gcc versions older than 10.1.
The machinery to detect mfence presence is still left intact just in case
if we need to use this instruction in the future.
Closes https://github.com/boostorg/atomic/issues/36.
The typedefs indicate the atomic object type for an unsigned/signed
integer that is lock-free and preferably has native support for waiting
and notifying operations.
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_<T>_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_<T>_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.
The value() operation is useful with futexes, but should not be used for
anything else, basically.
The lack of support for types with padding bits is documented more prominently.
The docs do mention that `long double` on x86 is supported though.
Also, added description of the new tests added recently.
Related to https://github.com/boostorg/atomic/issues/34.
The user may define BOOST_ATOMIC_LOCK_POOL_SIZE_LOG2 macro to specify
binary logarithm of the size of the internal lock pool. The macro
only has effect when building Boost.Atomic.
The generic implementation is based on the lock pool. A list of condition
variables (or waiting futexes) is added per lock. Basically, the lock
pool serves as a global hash table, where each lock represents
a bucket and each wait state is an element. Every wait operation
allocates a wait state keyed on the pointer to the atomic object. Notify
operations look up the wait state by the atomic pointer and notify
the condition variable/futex. The corresponding lock needs to be acquired
to protect the wait state list during all wait/notify operations.
Backends not involving the lock pool are going to be added later.
The implementation of wait operation extends the C++20 definition in that
it returns the newly loaded value instead of void. This allows the caller
to avoid loading the value himself.
The waiting/notifying operations are not address-free. Address-free variants
will be added later.
Added tests for the new operations and refactored existing tests for atomic
operations. Added docs for the new operations.
The macro was used to highlight the (op)_and_test methods of atomic<>
that changed the returned value to the opposite in Boost 1.67. The old
behavior was only released in 1.66 and the macro was a means to help
1.66 users to transition to the new releases.
1.67 will have been released 2 years before the upcoming 1.73 release,
in which this macro will be removed.
We currently don't support structs with padding bits, so the checks
are useless. Also, updated docs so that users are not given the idea
that structs with padding bits are supported.
The support includes:
- The standard fetch_add/fetch_sub operations.
- Extra operations: (fetch_/opaque_)negate, (opaque_)add/sub.
- Extra capability macros: BOOST_ATOMIC_FLOAT/DOUBLE/LONG_DOUBLE_LOCK_FREE.
The atomic operations are currently implemented on top of the integer-based
backends and thus are mostly CAS-based. The CAS operations perform binary
comparisons, and as such have different behavior wrt. special FP values like
NaN and signed zero than normal C++.
The support for floating point types is optional and can be disabled by
defining BOOST_ATOMIC_NO_FLOATING_POINT. This can be useful if on a certain
platform parameters of the floating point types cannot be deduced from the
compiler-defined or system macros (in which case the compilation fails).
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0020r6.html
These operations are useful for two reasons. First, they are needed by
atomic<> interface as the pre-increment/decrement and add/subtract operators
need to perform the corresponding arithmetics and return the actual result while
not exhibiting UB in case of overflow. This means that the operation must be
performed on the unsigned storage type in the backend. Second, the (op)_and_test
operations on ARM and PowerPC can be implemented in a more generic way on top of
the operations that return the result. And since we have those operations
internally, why not expose them to users.
Added tests and docs for the new operations. Also, added docs for the recently
added scoped names of the memory_order enum values.
Also, added a specialized "emulated" backend for the extra operations. This
backend makes better use of the fact that the operations are lock-protected
by avoiding any CAS-based loops.
As the names suggest, the methods perform the corresponding operation and test
if the result is not zero.
Also, for the emulated fetch_complement, take care of integral promotion, which
could mess up the storage bits that were not part of the value on backends
where the storage is larger than the value. This could in turn break CAS on
the atomic value as it compares the whole storage.
This makes the result of (op)_and_test more consistent with other
methods such as test_and_set and bit_test_and_set, as well as the
methods used in the C++ standard library.
This is a breaking change. The users are able to define
BOOST_ATOMIC_HIGHLIGHT_OP_AND_TEST macro to generate warnings on each
use of the changed functions. This will help users to port from Boost
1.66 to newer Boost releases.
More info at:
https://github.com/boostorg/atomic/issues/11http://boost.2283326.n4.nabble.com/atomic-op-and-test-naming-
tc4701445.html
Also made a few wording corrections and added is_always_lock_free and
a section about atomic<> typedefs. Clarified the status quo regarding
memory_order_consume. Removed the obsolete preudo-header for doxygen
that was not used for docs (if we want doxygen, it's better to
add comments to the real headers anyway).