|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- /*
- ==============================================================================
-
- This file is part of the Water library.
- Copyright (c) 2016 ROLI Ltd.
- Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
-
- 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.
-
- ==============================================================================
- */
-
- #ifndef WATER_ATOMIC_H_INCLUDED
- #define WATER_ATOMIC_H_INCLUDED
-
- #include "../water.h"
-
- #include <stdint.h>
-
- namespace water {
-
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma clang diagnostic ignored "-Weffc++"
- #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Weffc++"
- #endif
-
- //==============================================================================
- /**
- 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
- {
- #ifdef CARLA_PROPER_CPP11_SUPPORT
- // This class can only be used for types which are 32 or 64 bits in size.
- static_wassert (sizeof (Type) == 4 || sizeof (Type) == 8);
- #endif
- }
-
- /** 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.
- */
- #ifdef CARLA_OS_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 Type castFrom32Bit (uint32 value) noexcept { return castTo <Type, uint32> (value); }
- static inline Type castFrom64Bit (uint64 value) noexcept { return castTo <Type, uint64> (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<>
- inline int32 Atomic<int32>::get() const noexcept
- {
- #ifdef CARLA_PROPER_CPP11_SUPPORT
- static_wassert (sizeof (int32) == 4);
- #endif
- return castFrom32Bit ((int32) __sync_add_and_fetch (const_cast<volatile int32*>(&value), 0));
- }
-
- template<>
- inline int64 Atomic<int64>::get() const noexcept
- {
- #ifdef CARLA_PROPER_CPP11_SUPPORT
- static_wassert (sizeof (int64) == 8);
- #endif
- return castFrom64Bit ((int64) __sync_add_and_fetch (const_cast<volatile int64*>(&value), 0));
- }
-
- template<>
- inline uint32 Atomic<uint32>::get() const noexcept
- {
- #ifdef CARLA_PROPER_CPP11_SUPPORT
- static_wassert (sizeof (uint32) == 4);
- #endif
- return castFrom32Bit ((uint32) __sync_add_and_fetch (const_cast<volatile uint32*>(&value), 0));
- }
-
- template<>
- inline uint64 Atomic<uint64>::get() const noexcept
- {
- #ifdef CARLA_PROPER_CPP11_SUPPORT
- static_wassert (sizeof (uint64) == 8);
- #endif
- return castFrom64Bit ((uint64) __sync_add_and_fetch (const_cast<volatile uint64*>(&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 ((volatile int64*) &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 ((volatile int64*) &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();
- }
-
- #if defined(__clang__)
- # pragma clang diagnostic pop
- #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
- # pragma GCC diagnostic pop
- #endif
-
- }
-
- #endif // WATER_ATOMIC_H_INCLUDED
|