|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2016 - ROLI Ltd.
-
- Permission is granted to use this software under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license/
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
- TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
- OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- OF THIS SOFTWARE.
-
- -----------------------------------------------------------------------------
-
- To release a closed-source product which uses other parts of JUCE not
- licensed under the ISC terms, commercial licenses are available: visit
- www.juce.com for more information.
-
- ==============================================================================
- */
-
- #ifndef JUCE_ATOMIC_H_INCLUDED
- #define JUCE_ATOMIC_H_INCLUDED
-
-
- //==============================================================================
- /**
- Simple class to hold a primitive value and perform atomic operations on it.
-
- The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
- There are methods to perform most of the basic atomic operations.
- */
- template <typename Type>
- class Atomic
- {
- public:
- /** Creates a new value, initialised to zero. */
- inline Atomic() noexcept
- : value (0)
- {
- }
-
- /** Creates a new value, with a given initial value. */
- inline explicit Atomic (const Type initialValue) noexcept
- : value (initialValue)
- {
- }
-
- /** Copies another value (atomically). */
- inline Atomic (const Atomic& other) noexcept
- : value (other.get())
- {
- }
-
- /** Destructor. */
- inline ~Atomic() noexcept
- {
- // This class can only be used for types which are 32 or 64 bits in size.
- static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8);
- }
-
- /** Atomically reads and returns the current value. */
- Type get() const noexcept;
-
- /** Copies another value onto this one (atomically). */
- inline Atomic& operator= (const Atomic& other) noexcept { exchange (other.get()); return *this; }
-
- /** Copies another value onto this one (atomically). */
- inline Atomic& operator= (const Type newValue) noexcept { exchange (newValue); return *this; }
-
- /** Atomically sets the current value. */
- void set (Type newValue) noexcept { exchange (newValue); }
-
- /** Atomically sets the current value, returning the value that was replaced. */
- Type exchange (Type value) noexcept;
-
- /** Atomically adds a number to this value, returning the new value. */
- Type operator+= (Type amountToAdd) noexcept;
-
- /** Atomically subtracts a number from this value, returning the new value. */
- Type operator-= (Type amountToSubtract) noexcept;
-
- /** Atomically increments this value, returning the new value. */
- Type operator++() noexcept;
-
- /** Atomically decrements this value, returning the new value. */
- Type operator--() noexcept;
-
- /** Atomically compares this value with a target value, and if it is equal, sets
- this to be equal to a new value.
-
- This operation is the atomic equivalent of doing this:
- @code
- bool compareAndSetBool (Type newValue, Type valueToCompare)
- {
- if (get() == valueToCompare)
- {
- set (newValue);
- return true;
- }
-
- return false;
- }
- @endcode
-
- @returns true if the comparison was true and the value was replaced; false if
- the comparison failed and the value was left unchanged.
- @see compareAndSetValue
- */
- bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept;
-
- /** Atomically compares this value with a target value, and if it is equal, sets
- this to be equal to a new value.
-
- This operation is the atomic equivalent of doing this:
- @code
- Type compareAndSetValue (Type newValue, Type valueToCompare)
- {
- Type oldValue = get();
- if (oldValue == valueToCompare)
- set (newValue);
-
- return oldValue;
- }
- @endcode
-
- @returns the old value before it was changed.
- @see compareAndSetBool
- */
- Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept;
-
- /** Implements a memory read/write barrier. */
- static void memoryBarrier() noexcept;
-
- //==============================================================================
- /** The raw value that this class operates on.
- This is exposed publicly in case you need to manipulate it directly
- for performance reasons.
- */
- #if JUCE_64BIT
- __attribute__ ((aligned (8)))
- #else
- __attribute__ ((aligned (4)))
- #endif
- volatile Type value;
-
- private:
- template <typename Dest, typename Source>
- static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; }
-
- static inline Type castFrom32Bit (int32 value) noexcept { return castTo <Type, int32> (value); }
- static inline Type castFrom64Bit (int64 value) noexcept { return castTo <Type, int64> (value); }
- static inline int32 castTo32Bit (Type value) noexcept { return castTo <int32, Type> (value); }
- static inline int64 castTo64Bit (Type value) noexcept { return castTo <int64, Type> (value); }
-
- Type operator++ (int); // better to just use pre-increment with atomics..
- Type operator-- (int);
-
- /** This templated negate function will negate pointers as well as integers */
- template <typename ValueType>
- inline ValueType negateValue (ValueType n) noexcept
- {
- return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n
- : (sizeof (ValueType) == 2 ? (ValueType) -(short) n
- : (sizeof (ValueType) == 4 ? (ValueType) -(int) n
- : ((ValueType) -(int64) n)));
- }
-
- /** This templated negate function will negate pointers as well as integers */
- template <typename PointerType>
- inline PointerType* negateValue (PointerType* n) noexcept
- {
- return reinterpret_cast<PointerType*> (-reinterpret_cast<pointer_sized_int> (n));
- }
- };
-
- //==============================================================================
- template <typename Type>
- inline Type Atomic<Type>::get() const noexcept
- {
- return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0))
- : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0));
- }
-
- template <typename Type>
- inline Type Atomic<Type>::exchange (const Type newValue) noexcept
- {
- Type currentVal = value;
- while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
- return currentVal;
- }
-
- template <typename Type>
- inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
- {
- return (Type) __sync_add_and_fetch (&value, amountToAdd);
- }
-
- template <typename Type>
- inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
- {
- return operator+= (negateValue (amountToSubtract));
- }
-
- template <typename Type>
- inline Type Atomic<Type>::operator++() noexcept
- {
- return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (&value, (Type) 1)
- : (Type) __sync_add_and_fetch ((int64_t*) &value, 1);
- }
-
- template <typename Type>
- inline Type Atomic<Type>::operator--() noexcept
- {
- return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (&value, (Type) -1)
- : (Type) __sync_add_and_fetch ((int64_t*) &value, -1);
- }
-
- template <typename Type>
- inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
- {
- return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
- : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
- }
-
- template <typename Type>
- inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
- {
- return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
- : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
- }
-
- template <typename Type>
- inline void Atomic<Type>::memoryBarrier() noexcept
- {
- __sync_synchronize();
- }
-
- #endif // JUCE_ATOMIC_H_INCLUDED
|