/* * Copyright 2002-2019 Intel Corporation. * * This software and the related documents are Intel copyrighted materials, and your * use of them is governed by the express license under which they were provided to * you ("License"). Unless the License provides otherwise, you may not use, modify, * copy, publish, distribute, disclose or transmit this software or the related * documents without Intel's prior written permission. * * This software and the related documents are provided as is, with no express or * implied warranties, other than those that are expressly stated in the License. */ // : atomic // : component public header #ifndef ATOMIC_OPS_HPP #define ATOMIC_OPS_HPP #include "atomic/exponential-backoff.hpp" #include "atomic/ops-enum.hpp" #include "atomic/private/ops-common-impl.hpp" #include "atomic/private/backoff-impl.hpp" #if defined(HOST_IA32) # include "atomic/private/ia32/ops-impl.hpp" #elif defined(HOST_IA32E) # include "atomic/private/intel64/ops-impl.hpp" #endif namespace ATOMIC { /*! @brief Low-level atomic memory operations. * * A collection of low-level atomic memory operations that can be performed on fundemental data types * (integers, pointers, etc.) All of the operations are static template methods, so they automatically * adapt to whatever data type you use. * * @par Example: * \code * #include "atomic/ops.hpp" * * int Count; * * void Foo() * { * ATOMIC::OPS::Increment(&Count, 1); * } * \endcode */ class /**/ OPS { public: /*! * Perform an atomic compare-and-swap. * * @param[in] location Pointer to the location to modify. * @param[in] oldVal The \a location is only changed if its value is * equal to \a oldVal. * @param[in] newVal The new value to write to \a location. * @param[in] barrier Tells the memory ordering semantics of this operation. * * @return The value of \a location prior to the operation. The \a newVal was stored * only if the return value is equal to \a oldVal. */ template static T CompareAndSwap(volatile T *location, T oldVal, T newVal, BARRIER_CS barrier = BARRIER_CS_NONE) { OPS_IMPL::CompareAndSwap(static_cast(location), static_cast(&oldVal), static_cast(&newVal), barrier); return newVal; } /*! * This is exactly the same as CompareAndSwap() except the return value is a * boolean. * * @param[in] location Pointer to the location to modify. * @param[in] oldVal The \a location is only changed if its value is * equal to \a oldVal. * @param[in] newVal The new value to write to \a location. * @param[in] barrier Tells the memory ordering semantics of this operation. * * @return TRUE if \a newVal was stored to \a location. */ template static bool CompareAndDidSwap(volatile T *location, T oldVal, T newVal, BARRIER_CS barrier = BARRIER_CS_NONE) { OPS_IMPL::CompareAndSwap(static_cast(location), static_cast(&oldVal), static_cast(&newVal), barrier); return (newVal == oldVal); } /*! * Perform an atomic swap. * * @param[in] location Pointer to the location to modify. * @param[in] newVal The new value to write to \a location. * @param[in] barrier Tells the memory ordering semantics of this operation. * * @return The value swapped out of \a location */ template static T Swap(volatile T *location, T newVal, BARRIER_SWAP barrier = BARRIER_SWAP_NONE) { T oldVal; OPS_IMPL::Swap(static_cast(location), static_cast(&oldVal), static_cast(&newVal), barrier); return oldVal; } /*! * Atomically set the value of a location. Any outside observer using an OPS method * is guaranteed to see either the old value or the new value (but not an intermediate value). * * @param[in] location Pointer to the location. * @param[in] val The value to write to \a location. * @param[in] barrier Tells the memory ordering semantics of this operation. */ template static void Store(volatile T *location, T val, BARRIER_ST barrier = BARRIER_ST_NONE) { OPS_IMPL::Store(static_cast(location), static_cast(&val), barrier); } /*! * Atomically get the value of a location. If another thread changes the location using an * OPS method, Load() is guaranteed to either return the old value or the new value (but not * an intermediate value). * * @param[in] location Pointer to the location. * @param[in] barrier Tells the memory ordering semantics of this operation. * * @return The value at \a location. */ template static T Load(volatile const T *location, BARRIER_LD barrier = BARRIER_LD_NONE) { T val; OPS_IMPL::Load(static_cast(location), static_cast(&val), barrier); return val; } /*! * Atomically increment a value. * * @param[in] location Pointer to the location to modify. * @param[in] inc The increment amount. * @param[in] barrier Tells the memory ordering semantics of this operation. * * @return The value of \a location prior to being incremented. */ template static T Increment(volatile T *location, T inc, BARRIER_CS barrier = BARRIER_CS_NONE) { T oldVal; OPS_IMPL::Increment(static_cast(location), static_cast(&inc), static_cast(&oldVal), barrier); return oldVal; } /*! * Atomically set a location if it is less than a value. This allows you to * compute the maximum of a series of values. * * @param[in] location Pointer to the location to modify. * @param[in] val If \a location is less than \a val it is updated. */ template static void MaxValue(volatile T *location, T val) { EXPONENTIAL_BACKOFF<> backoff; T oldVal = Load(location); while (oldVal < val && !CompareAndDidSwap(location, oldVal, val)) { backoff.Delay(); oldVal = Load(location); } } /*! * Delay the calling thread in a spin loop, using a processor specific * "spin loop hint" if available. * * @param[in] delay The number of iterations for the spin loop. */ static void Delay(unsigned delay) { ATOMIC_SpinDelay(static_cast(delay)); } }; } // namespace #endif // file guard