| /* |
| Copyright 2005-2010 Intel Corporation. All Rights Reserved. |
| |
| This file is part of Threading Building Blocks. |
| |
| Threading Building Blocks is free software; you can redistribute it |
| and/or modify it under the terms of the GNU General Public License |
| version 2 as published by the Free Software Foundation. |
| |
| Threading Building Blocks is distributed in the hope that it will be |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with Threading Building Blocks; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| |
| As a special exception, you may use this file as part of a free software |
| library without restriction. Specifically, if other files instantiate |
| templates or use macros or inline functions from this file, or you compile |
| this file and link it with other files to produce an executable, this |
| file does not by itself cause the resulting executable to be covered by |
| the GNU General Public License. This exception does not however |
| invalidate any other reasons why the executable file might be covered by |
| the GNU General Public License. |
| */ |
| |
| #ifndef __TBB_atomic_H |
| #define __TBB_atomic_H |
| |
| #include <cstddef> |
| #include "tbb_stddef.h" |
| |
| #if _MSC_VER |
| #define __TBB_LONG_LONG __int64 |
| #else |
| #define __TBB_LONG_LONG long long |
| #endif /* _MSC_VER */ |
| |
| #include "tbb_machine.h" |
| |
| #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) |
| // Workaround for overzealous compiler warnings |
| #pragma warning (push) |
| #pragma warning (disable: 4244 4267) |
| #endif |
| |
| namespace tbb { |
| |
| //! Specifies memory fencing. |
| enum memory_semantics { |
| //! For internal use only. |
| __TBB_full_fence, |
| //! Acquire fence |
| acquire, |
| //! Release fence |
| release |
| }; |
| |
| //! @cond INTERNAL |
| namespace internal { |
| |
| #if __GNUC__ || __SUNPRO_CC |
| #define __TBB_DECL_ATOMIC_FIELD(t,f,a) t f __attribute__ ((aligned(a))); |
| #elif defined(__INTEL_COMPILER)||_MSC_VER >= 1300 |
| #define __TBB_DECL_ATOMIC_FIELD(t,f,a) __declspec(align(a)) t f; |
| #else |
| #error Do not know syntax for forcing alignment. |
| #endif /* __GNUC__ */ |
| |
| template<size_t S> |
| struct atomic_rep; // Primary template declared, but never defined. |
| |
| template<> |
| struct atomic_rep<1> { // Specialization |
| typedef int8_t word; |
| int8_t value; |
| }; |
| template<> |
| struct atomic_rep<2> { // Specialization |
| typedef int16_t word; |
| __TBB_DECL_ATOMIC_FIELD(int16_t,value,2) |
| }; |
| template<> |
| struct atomic_rep<4> { // Specialization |
| #if _MSC_VER && __TBB_WORDSIZE==4 |
| // Work-around that avoids spurious /Wp64 warnings |
| typedef intptr_t word; |
| #else |
| typedef int32_t word; |
| #endif |
| __TBB_DECL_ATOMIC_FIELD(int32_t,value,4) |
| }; |
| template<> |
| struct atomic_rep<8> { // Specialization |
| typedef int64_t word; |
| __TBB_DECL_ATOMIC_FIELD(int64_t,value,8) |
| }; |
| |
| template<size_t Size, memory_semantics M> |
| struct atomic_traits; // Primary template declared, but not defined. |
| |
| #define __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(S,M) \ |
| template<> struct atomic_traits<S,M> { \ |
| typedef atomic_rep<S>::word word; \ |
| inline static word compare_and_swap( volatile void* location, word new_value, word comparand ) {\ |
| return __TBB_CompareAndSwap##S##M(location,new_value,comparand); \ |
| } \ |
| inline static word fetch_and_add( volatile void* location, word addend ) { \ |
| return __TBB_FetchAndAdd##S##M(location,addend); \ |
| } \ |
| inline static word fetch_and_store( volatile void* location, word value ) {\ |
| return __TBB_FetchAndStore##S##M(location,value); \ |
| } \ |
| }; |
| |
| #define __TBB_DECL_ATOMIC_PRIMITIVES(S) \ |
| template<memory_semantics M> \ |
| struct atomic_traits<S,M> { \ |
| typedef atomic_rep<S>::word word; \ |
| inline static word compare_and_swap( volatile void* location, word new_value, word comparand ) {\ |
| return __TBB_CompareAndSwap##S(location,new_value,comparand); \ |
| } \ |
| inline static word fetch_and_add( volatile void* location, word addend ) { \ |
| return __TBB_FetchAndAdd##S(location,addend); \ |
| } \ |
| inline static word fetch_and_store( volatile void* location, word value ) {\ |
| return __TBB_FetchAndStore##S(location,value); \ |
| } \ |
| }; |
| |
| #if __TBB_DECL_FENCED_ATOMICS |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(1,__TBB_full_fence) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(2,__TBB_full_fence) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(4,__TBB_full_fence) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(8,__TBB_full_fence) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(1,acquire) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(2,acquire) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(4,acquire) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(8,acquire) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(1,release) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(2,release) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(4,release) |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(8,release) |
| #else |
| __TBB_DECL_ATOMIC_PRIMITIVES(1) |
| __TBB_DECL_ATOMIC_PRIMITIVES(2) |
| __TBB_DECL_ATOMIC_PRIMITIVES(4) |
| __TBB_DECL_ATOMIC_PRIMITIVES(8) |
| #endif |
| |
| //! Additive inverse of 1 for type T. |
| /** Various compilers issue various warnings if -1 is used with various integer types. |
| The baroque expression below avoids all the warnings (we hope). */ |
| #define __TBB_MINUS_ONE(T) (T(T(0)-T(1))) |
| |
| //! Base class that provides basic functionality for atomic<T> without fetch_and_add. |
| /** Works for any type T that has the same size as an integral type, has a trivial constructor/destructor, |
| and can be copied/compared by memcpy/memcmp. */ |
| template<typename T> |
| struct atomic_impl { |
| protected: |
| atomic_rep<sizeof(T)> rep; |
| private: |
| //! Union type used to convert type T to underlying integral type. |
| union converter { |
| T value; |
| typename atomic_rep<sizeof(T)>::word bits; |
| }; |
| public: |
| typedef T value_type; |
| |
| template<memory_semantics M> |
| value_type fetch_and_store( value_type value ) { |
| converter u, w; |
| u.value = value; |
| w.bits = internal::atomic_traits<sizeof(value_type),M>::fetch_and_store(&rep.value,u.bits); |
| return w.value; |
| } |
| |
| value_type fetch_and_store( value_type value ) { |
| return fetch_and_store<__TBB_full_fence>(value); |
| } |
| |
| template<memory_semantics M> |
| value_type compare_and_swap( value_type value, value_type comparand ) { |
| converter u, v, w; |
| u.value = value; |
| v.value = comparand; |
| w.bits = internal::atomic_traits<sizeof(value_type),M>::compare_and_swap(&rep.value,u.bits,v.bits); |
| return w.value; |
| } |
| |
| value_type compare_and_swap( value_type value, value_type comparand ) { |
| return compare_and_swap<__TBB_full_fence>(value,comparand); |
| } |
| |
| operator value_type() const volatile { // volatile qualifier here for backwards compatibility |
| converter w; |
| w.bits = __TBB_load_with_acquire( rep.value ); |
| return w.value; |
| } |
| |
| protected: |
| value_type store_with_release( value_type rhs ) { |
| converter u; |
| u.value = rhs; |
| __TBB_store_with_release(rep.value,u.bits); |
| return rhs; |
| } |
| }; |
| |
| //! Base class that provides basic functionality for atomic<T> with fetch_and_add. |
| /** I is the underlying type. |
| D is the difference type. |
| StepType should be char if I is an integral type, and T if I is a T*. */ |
| template<typename I, typename D, typename StepType> |
| struct atomic_impl_with_arithmetic: atomic_impl<I> { |
| public: |
| typedef I value_type; |
| |
| template<memory_semantics M> |
| value_type fetch_and_add( D addend ) { |
| return value_type(internal::atomic_traits<sizeof(value_type),M>::fetch_and_add( &this->rep.value, addend*sizeof(StepType) )); |
| } |
| |
| value_type fetch_and_add( D addend ) { |
| return fetch_and_add<__TBB_full_fence>(addend); |
| } |
| |
| template<memory_semantics M> |
| value_type fetch_and_increment() { |
| return fetch_and_add<M>(1); |
| } |
| |
| value_type fetch_and_increment() { |
| return fetch_and_add(1); |
| } |
| |
| template<memory_semantics M> |
| value_type fetch_and_decrement() { |
| return fetch_and_add<M>(__TBB_MINUS_ONE(D)); |
| } |
| |
| value_type fetch_and_decrement() { |
| return fetch_and_add(__TBB_MINUS_ONE(D)); |
| } |
| |
| public: |
| value_type operator+=( D addend ) { |
| return fetch_and_add(addend)+addend; |
| } |
| |
| value_type operator-=( D addend ) { |
| // Additive inverse of addend computed using binary minus, |
| // instead of unary minus, for sake of avoiding compiler warnings. |
| return operator+=(D(0)-addend); |
| } |
| |
| value_type operator++() { |
| return fetch_and_add(1)+1; |
| } |
| |
| value_type operator--() { |
| return fetch_and_add(__TBB_MINUS_ONE(D))-1; |
| } |
| |
| value_type operator++(int) { |
| return fetch_and_add(1); |
| } |
| |
| value_type operator--(int) { |
| return fetch_and_add(__TBB_MINUS_ONE(D)); |
| } |
| }; |
| |
| #if __TBB_WORDSIZE == 4 |
| // Plaforms with 32-bit hardware require special effort for 64-bit loads and stores. |
| #if defined(__INTEL_COMPILER)||!defined(_MSC_VER)||_MSC_VER>=1400 |
| |
| template<> |
| inline atomic_impl<__TBB_LONG_LONG>::operator atomic_impl<__TBB_LONG_LONG>::value_type() const volatile { |
| return __TBB_Load8(&rep.value); |
| } |
| |
| template<> |
| inline atomic_impl<unsigned __TBB_LONG_LONG>::operator atomic_impl<unsigned __TBB_LONG_LONG>::value_type() const volatile { |
| return __TBB_Load8(&rep.value); |
| } |
| |
| template<> |
| inline atomic_impl<__TBB_LONG_LONG>::value_type atomic_impl<__TBB_LONG_LONG>::store_with_release( value_type rhs ) { |
| __TBB_Store8(&rep.value,rhs); |
| return rhs; |
| } |
| |
| template<> |
| inline atomic_impl<unsigned __TBB_LONG_LONG>::value_type atomic_impl<unsigned __TBB_LONG_LONG>::store_with_release( value_type rhs ) { |
| __TBB_Store8(&rep.value,rhs); |
| return rhs; |
| } |
| |
| #endif /* defined(__INTEL_COMPILER)||!defined(_MSC_VER)||_MSC_VER>=1400 */ |
| #endif /* __TBB_WORDSIZE==4 */ |
| |
| } /* Internal */ |
| //! @endcond |
| |
| //! Primary template for atomic. |
| /** See the Reference for details. |
| @ingroup synchronization */ |
| template<typename T> |
| struct atomic: internal::atomic_impl<T> { |
| T operator=( T rhs ) { |
| // "this" required here in strict ISO C++ because store_with_release is a dependent name |
| return this->store_with_release(rhs); |
| } |
| atomic<T>& operator=( const atomic<T>& rhs ) {this->store_with_release(rhs); return *this;} |
| }; |
| |
| #define __TBB_DECL_ATOMIC(T) \ |
| template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T,char> { \ |
| T operator=( T rhs ) {return store_with_release(rhs);} \ |
| atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rhs); return *this;} \ |
| }; |
| |
| #if defined(__INTEL_COMPILER)||!defined(_MSC_VER)||_MSC_VER>=1400 |
| __TBB_DECL_ATOMIC(__TBB_LONG_LONG) |
| __TBB_DECL_ATOMIC(unsigned __TBB_LONG_LONG) |
| #else |
| // Some old versions of MVSC cannot correctly compile templates with "long long". |
| #endif /* defined(__INTEL_COMPILER)||!defined(_MSC_VER)||_MSC_VER>=1400 */ |
| |
| __TBB_DECL_ATOMIC(long) |
| __TBB_DECL_ATOMIC(unsigned long) |
| |
| #if defined(_MSC_VER) && __TBB_WORDSIZE==4 |
| /* Special version of __TBB_DECL_ATOMIC that avoids gratuitous warnings from cl /Wp64 option. |
| It is identical to __TBB_DECL_ATOMIC(unsigned) except that it replaces operator=(T) |
| with an operator=(U) that explicitly converts the U to a T. Types T and U should be |
| type synonyms on the platform. Type U should be the wider variant of T from the |
| perspective of /Wp64. */ |
| #define __TBB_DECL_ATOMIC_ALT(T,U) \ |
| template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T,char> { \ |
| T operator=( U rhs ) {return store_with_release(T(rhs));} \ |
| atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rhs); return *this;} \ |
| }; |
| __TBB_DECL_ATOMIC_ALT(unsigned,size_t) |
| __TBB_DECL_ATOMIC_ALT(int,ptrdiff_t) |
| #else |
| __TBB_DECL_ATOMIC(unsigned) |
| __TBB_DECL_ATOMIC(int) |
| #endif /* defined(_MSC_VER) && __TBB_WORDSIZE==4 */ |
| |
| __TBB_DECL_ATOMIC(unsigned short) |
| __TBB_DECL_ATOMIC(short) |
| __TBB_DECL_ATOMIC(char) |
| __TBB_DECL_ATOMIC(signed char) |
| __TBB_DECL_ATOMIC(unsigned char) |
| |
| #if !defined(_MSC_VER)||defined(_NATIVE_WCHAR_T_DEFINED) |
| __TBB_DECL_ATOMIC(wchar_t) |
| #endif /* _MSC_VER||!defined(_NATIVE_WCHAR_T_DEFINED) */ |
| |
| //! Specialization for atomic<T*> with arithmetic and operator->. |
| template<typename T> struct atomic<T*>: internal::atomic_impl_with_arithmetic<T*,ptrdiff_t,T> { |
| T* operator=( T* rhs ) { |
| // "this" required here in strict ISO C++ because store_with_release is a dependent name |
| return this->store_with_release(rhs); |
| } |
| atomic<T*>& operator=( const atomic<T*>& rhs ) { |
| this->store_with_release(rhs); return *this; |
| } |
| T* operator->() const { |
| return (*this); |
| } |
| }; |
| |
| //! Specialization for atomic<void*>, for sake of not allowing arithmetic or operator->. |
| template<> struct atomic<void*>: internal::atomic_impl<void*> { |
| void* operator=( void* rhs ) { |
| // "this" required here in strict ISO C++ because store_with_release is a dependent name |
| return this->store_with_release(rhs); |
| } |
| atomic<void*>& operator=( const atomic<void*>& rhs ) { |
| this->store_with_release(rhs); return *this; |
| } |
| }; |
| |
| } // namespace tbb |
| |
| #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) |
| #pragma warning (pop) |
| #endif // warnings 4244, 4267 are back |
| |
| #endif /* __TBB_atomic_H */ |