| atomic.h | | atomic.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 80 | | skipping to change at line 80 | |
| #else | | #else | |
| #error Do not know syntax for forcing alignment. | | #error Do not know syntax for forcing alignment. | |
| #endif | | #endif | |
| | | | |
| template<size_t S> | | template<size_t S> | |
| struct atomic_rep; // Primary template declared, but never define
d. | | struct atomic_rep; // Primary template declared, but never define
d. | |
| | | | |
| template<> | | template<> | |
| struct atomic_rep<1> { // Specialization | | struct atomic_rep<1> { // Specialization | |
| typedef int8_t word; | | typedef int8_t word; | |
|
| int8_t value; | | | |
| }; | | }; | |
| template<> | | template<> | |
| struct atomic_rep<2> { // Specialization | | struct atomic_rep<2> { // Specialization | |
| typedef int16_t word; | | typedef int16_t word; | |
|
| __TBB_DECL_ATOMIC_FIELD(int16_t,value,2) | | | |
| }; | | }; | |
| template<> | | template<> | |
| struct atomic_rep<4> { // Specialization | | struct atomic_rep<4> { // Specialization | |
| #if _MSC_VER && !_WIN64 | | #if _MSC_VER && !_WIN64 | |
| // Work-around that avoids spurious /Wp64 warnings | | // Work-around that avoids spurious /Wp64 warnings | |
| typedef intptr_t word; | | typedef intptr_t word; | |
| #else | | #else | |
| typedef int32_t word; | | typedef int32_t word; | |
| #endif | | #endif | |
|
| __TBB_DECL_ATOMIC_FIELD(int32_t,value,4) | | | |
| }; | | }; | |
| #if __TBB_64BIT_ATOMICS | | #if __TBB_64BIT_ATOMICS | |
| template<> | | template<> | |
| struct atomic_rep<8> { // Specialization | | struct atomic_rep<8> { // Specialization | |
| typedef int64_t word; | | typedef int64_t word; | |
|
| __TBB_DECL_ATOMIC_FIELD(int64_t,value,8) | | | |
| }; | | }; | |
| #endif | | #endif | |
| | | | |
|
| | | template<typename value_type, size_t size> | |
| | | struct aligned_storage; | |
| | | | |
| | | //the specializations are needed to please MSVC syntax of __declspec(align( | |
| | | )) which accept _literal_ constants only | |
| | | #if __TBB_ATOMIC_CTORS | |
| | | #define ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(S) \ | |
| | | template<typename value_type> \ | |
| | | struct aligned_storage<value_type,S> { \ | |
| | | __TBB_DECL_ATOMIC_FIELD(value_type,my_value,S) \ | |
| | | aligned_storage() = default ; \ | |
| | | constexpr aligned_storage(value_type value):my_value(value){} \ | |
| | | }; \ | |
| | | | |
| | | #else | |
| | | #define ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(S) \ | |
| | | template<typename value_type> \ | |
| | | struct aligned_storage<value_type,S> { \ | |
| | | __TBB_DECL_ATOMIC_FIELD(value_type,my_value,S) \ | |
| | | }; \ | |
| | | | |
| | | #endif | |
| | | | |
| | | template<typename value_type> | |
| | | struct aligned_storage<value_type,1> { | |
| | | value_type my_value; | |
| | | #if __TBB_ATOMIC_CTORS | |
| | | aligned_storage() = default ; | |
| | | constexpr aligned_storage(value_type value):my_value(value){} | |
| | | #endif | |
| | | }; | |
| | | | |
| | | ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(2) | |
| | | ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(4) | |
| | | #if __TBB_64BIT_ATOMICS | |
| | | ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(8) | |
| | | #endif | |
| | | | |
| template<size_t Size, memory_semantics M> | | template<size_t Size, memory_semantics M> | |
| struct atomic_traits; // Primary template declared, but not defined. | | struct atomic_traits; // Primary template declared, but not defined. | |
| | | | |
| #define __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(S,M)
\ | | #define __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(S,M)
\ | |
| template<> struct atomic_traits<S,M> {
\ | | template<> struct atomic_traits<S,M> {
\ | |
| typedef atomic_rep<S>::word word;
\ | | typedef atomic_rep<S>::word word;
\ | |
| inline static word compare_and_swap( volatile void* location, word
new_value, word comparand ) { \ | | inline static word compare_and_swap( volatile void* location, word
new_value, word comparand ) { \ | |
| return __TBB_machine_cmpswp##S##M(location,new_value,comparand)
; \ | | return __TBB_machine_cmpswp##S##M(location,new_value,comparand)
; \ | |
| }
\ | | }
\ | |
| inline static word fetch_and_add( volatile void* location, word add
end ) { \ | | inline static word fetch_and_add( volatile void* location, word add
end ) { \ | |
| | | | |
| skipping to change at line 196 | | skipping to change at line 229 | |
| /** Various compilers issue various warnings if -1 is used with various int
eger types. | | /** Various compilers issue various warnings if -1 is used with various int
eger types. | |
| The baroque expression below avoids all the warnings (we hope). */ | | The baroque expression below avoids all the warnings (we hope). */ | |
| #define __TBB_MINUS_ONE(T) (T(T(0)-T(1))) | | #define __TBB_MINUS_ONE(T) (T(T(0)-T(1))) | |
| | | | |
| //! Base class that provides basic functionality for atomic<T> without fetc
h_and_add. | | //! Base class that provides basic functionality for atomic<T> without fetc
h_and_add. | |
| /** Works for any type T that has the same size as an integral type, has a
trivial constructor/destructor, | | /** 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. */ | | and can be copied/compared by memcpy/memcmp. */ | |
| template<typename T> | | template<typename T> | |
| struct atomic_impl { | | struct atomic_impl { | |
| protected: | | protected: | |
|
| atomic_rep<sizeof(T)> rep; | | aligned_storage<T,sizeof(T)> my_storage; | |
| private: | | private: | |
|
| | | //TODO: rechecks on recent versions of gcc if union is still the _only_
way to do a conversion without warnings | |
| //! Union type used to convert type T to underlying integral type. | | //! Union type used to convert type T to underlying integral type. | |
|
| | | template<typename value_type> | |
| union converter { | | union converter { | |
|
| T value; | | typedef typename atomic_rep<sizeof(value_type)>::word bits_type; | |
| typename atomic_rep<sizeof(T)>::word bits; | | converter(){} | |
| | | converter(value_type a_value) : value(a_value) {} | |
| | | value_type value; | |
| | | bits_type bits; | |
| | | }; | |
| | | | |
| | | template<typename value_t> | |
| | | union ptr_converter; //Primary template declared, but never | |
| | | defined. | |
| | | | |
| | | template<typename value_t> | |
| | | union ptr_converter<value_t *> { | |
| | | typedef typename atomic_rep<sizeof(value_t)>::word * bits_ptr_type; | |
| | | ptr_converter(){} | |
| | | ptr_converter(value_t* a_value) : value(a_value) {} | |
| | | value_t* value; | |
| | | bits_ptr_type bits; | |
| }; | | }; | |
|
| | | | |
| | | template<typename value_t> | |
| | | static typename converter<value_t>::bits_type to_bits(value_t value){ | |
| | | return converter<value_t>(value).bits; | |
| | | } | |
| | | template<typename value_t> | |
| | | static value_t to_value(typename converter<value_t>::bits_type bits){ | |
| | | converter<value_t> u; | |
| | | u.bits = bits; | |
| | | return u.value; | |
| | | } | |
| | | | |
| | | //separate function is needed as it is impossible to distinguish (and t | |
| | | hus overload to_bits) | |
| | | //whether the pointer passed in is a pointer to atomic location or a va | |
| | | lue of that location | |
| | | template<typename value_t> | |
| | | static typename ptr_converter<value_t*>::bits_ptr_type to_bits_ptr(valu | |
| | | e_t* value){ | |
| | | //TODO: try to use cast to void* and second cast to required pointe | |
| | | r type; | |
| | | //Once (and if) union converter goes away - check if strict aliasin | |
| | | g warning | |
| | | //suppression is still needed once. | |
| | | //TODO: this #ifdef is temporary workaround, as union conversion se | |
| | | ems to fail | |
| | | //on suncc for 64 bit types for 32 bit target | |
| | | #if !__SUNPRO_CC | |
| | | return ptr_converter<value_t*>(value).bits; | |
| | | #else | |
| | | return typename ptr_converter<value_t*>::bits_ptr_type (value); | |
| | | #endif | |
| | | } | |
| | | | |
| public: | | public: | |
| typedef T value_type; | | typedef T value_type; | |
| | | | |
|
| | | #if __TBB_ATOMIC_CTORS | |
| | | atomic_impl() = default ; | |
| | | constexpr atomic_impl(value_type value):my_storage(value){} | |
| | | #endif | |
| template<memory_semantics M> | | template<memory_semantics M> | |
| value_type fetch_and_store( value_type value ) { | | value_type fetch_and_store( value_type value ) { | |
|
| converter u, w; | | return to_value<value_type>(internal::atomic_traits<sizeof(value_ | |
| u.value = value; | | type),M>::fetch_and_store(&my_storage.my_value,to_bits(value))); | |
| w.bits = internal::atomic_traits<sizeof(value_type),M>::fetch_and_s | | | |
| tore(&rep.value,u.bits); | | | |
| return w.value; | | | |
| } | | } | |
| | | | |
| value_type fetch_and_store( value_type value ) { | | value_type fetch_and_store( value_type value ) { | |
| return fetch_and_store<full_fence>(value); | | return fetch_and_store<full_fence>(value); | |
| } | | } | |
| | | | |
| template<memory_semantics M> | | template<memory_semantics M> | |
| value_type compare_and_swap( value_type value, value_type comparand ) { | | value_type compare_and_swap( value_type value, value_type comparand ) { | |
|
| converter u, v, w; | | return to_value<value_type>(internal::atomic_traits<sizeof(value_ty | |
| u.value = value; | | pe),M>::compare_and_swap(&my_storage.my_value,to_bits(value),to_bits(compar | |
| v.value = comparand; | | and))); | |
| 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 ) { | | value_type compare_and_swap( value_type value, value_type comparand ) { | |
| return compare_and_swap<full_fence>(value,comparand); | | return compare_and_swap<full_fence>(value,comparand); | |
| } | | } | |
| | | | |
| operator value_type() const volatile { // volatile quali
fier here for backwards compatibility | | operator value_type() const volatile { // volatile quali
fier here for backwards compatibility | |
|
| converter w; | | return to_value<value_type>(__TBB_load_with_acquire(*to_bits_ptr(& | |
| w.bits = __TBB_load_with_acquire( rep.value ); | | my_storage.my_value))); | |
| return w.value; | | | |
| } | | } | |
| | | | |
| template<memory_semantics M> | | template<memory_semantics M> | |
| value_type load () const { | | value_type load () const { | |
|
| converter u; | | return to_value<value_type>(internal::atomic_load_store_traits<M>:: | |
| u.bits = internal::atomic_load_store_traits<M>::load( rep.value ); | | load(*to_bits_ptr(&my_storage.my_value))); | |
| return u.value; | | | |
| } | | } | |
| | | | |
| value_type load () const { | | value_type load () const { | |
| return load<acquire>(); | | return load<acquire>(); | |
| } | | } | |
| | | | |
| template<memory_semantics M> | | template<memory_semantics M> | |
| void store ( value_type value ) { | | void store ( value_type value ) { | |
|
| converter u; | | internal::atomic_load_store_traits<M>::store( *to_bits_ptr(&my_stor | |
| u.value = value; | | age.my_value), to_bits(value)); | |
| internal::atomic_load_store_traits<M>::store( rep.value, u.bits ); | | | |
| } | | } | |
| | | | |
| void store ( value_type value ) { | | void store ( value_type value ) { | |
| store<release>( value ); | | store<release>( value ); | |
| } | | } | |
| | | | |
| protected: | | protected: | |
| value_type store_with_release( value_type rhs ) { | | value_type store_with_release( value_type rhs ) { | |
|
| converter u; | | __TBB_store_with_release(*to_bits_ptr(&my_storage.my_value),to_bits | |
| u.value = rhs; | | (rhs)); | |
| __TBB_store_with_release(rep.value,u.bits); | | | |
| return rhs; | | return rhs; | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! Base class that provides basic functionality for atomic<T> with fetch_a
nd_add. | | //! Base class that provides basic functionality for atomic<T> with fetch_a
nd_add. | |
| /** I is the underlying type. | | /** I is the underlying type. | |
| D is the difference type. | | D is the difference type. | |
| StepType should be char if I is an integral type, and T if I is a T*. *
/ | | StepType should be char if I is an integral type, and T if I is a T*. *
/ | |
| template<typename I, typename D, typename StepType> | | template<typename I, typename D, typename StepType> | |
| struct atomic_impl_with_arithmetic: atomic_impl<I> { | | struct atomic_impl_with_arithmetic: atomic_impl<I> { | |
| public: | | public: | |
| typedef I value_type; | | typedef I value_type; | |
|
| | | #if __TBB_ATOMIC_CTORS | |
| | | atomic_impl_with_arithmetic() = default ; | |
| | | constexpr atomic_impl_with_arithmetic(value_type value): atomic_impl<I> | |
| | | (value){} | |
| | | #endif | |
| template<memory_semantics M> | | template<memory_semantics M> | |
| value_type fetch_and_add( D addend ) { | | value_type fetch_and_add( D addend ) { | |
|
| return value_type(internal::atomic_traits<sizeof(value_type),M>::fe
tch_and_add( &this->rep.value, addend*sizeof(StepType) )); | | return value_type(internal::atomic_traits<sizeof(value_type),M>::fe
tch_and_add( &this->my_storage.my_value, addend*sizeof(StepType) )); | |
| } | | } | |
| | | | |
| value_type fetch_and_add( D addend ) { | | value_type fetch_and_add( D addend ) { | |
| return fetch_and_add<full_fence>(addend); | | return fetch_and_add<full_fence>(addend); | |
| } | | } | |
| | | | |
| template<memory_semantics M> | | template<memory_semantics M> | |
| value_type fetch_and_increment() { | | value_type fetch_and_increment() { | |
| return fetch_and_add<M>(1); | | return fetch_and_add<M>(1); | |
| } | | } | |
| | | | |
| skipping to change at line 340 | | skipping to change at line 410 | |
| }; | | }; | |
| | | | |
| } /* Internal */ | | } /* Internal */ | |
| //! @endcond | | //! @endcond | |
| | | | |
| //! Primary template for atomic. | | //! Primary template for atomic. | |
| /** See the Reference for details. | | /** See the Reference for details. | |
| @ingroup synchronization */ | | @ingroup synchronization */ | |
| template<typename T> | | template<typename T> | |
| struct atomic: internal::atomic_impl<T> { | | struct atomic: internal::atomic_impl<T> { | |
|
| | | #if __TBB_ATOMIC_CTORS | |
| | | atomic() = default; | |
| | | constexpr atomic(T arg): internal::atomic_impl<T>(arg) {} | |
| | | #endif | |
| T operator=( T rhs ) { | | T operator=( T rhs ) { | |
| // "this" required here in strict ISO C++ because store_with_releas
e is a dependent name | | // "this" required here in strict ISO C++ because store_with_releas
e is a dependent name | |
| return this->store_with_release(rhs); | | return this->store_with_release(rhs); | |
| } | | } | |
| atomic<T>& operator=( const atomic<T>& rhs ) {this->store_with_release(
rhs); return *this;} | | atomic<T>& operator=( const atomic<T>& rhs ) {this->store_with_release(
rhs); return *this;} | |
| }; | | }; | |
| | | | |
|
| #define __TBB_DECL_ATOMIC(T) \ | | #if __TBB_ATOMIC_CTORS | |
| template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T, | | #define __TBB_DECL_ATOMIC(T) | |
| char> { \ | | \ | |
| T operator=( T rhs ) {return store_with_release(rhs);} \ | | template<> struct atomic<T>: internal::atomic_impl_with_arithmetic< | |
| atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rh | | T,T,char> { \ | |
| s); return *this;} \ | | atomic() = default; | |
| }; | | \ | |
| | | constexpr atomic(T arg): internal::atomic_impl_with_arithmetic< | |
| | | T,T,char>(arg) {} \ | |
| | | | |
| | | \ | |
| | | T operator=( T rhs ) {return store_with_release(rhs);} | |
| | | \ | |
| | | atomic<T>& operator=( const atomic<T>& rhs ) {store_with_releas | |
| | | e(rhs); return *this;} \ | |
| | | }; | |
| | | #else | |
| | | #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_releas | |
| | | e(rhs); return *this;} \ | |
| | | }; | |
| | | #endif | |
| | | | |
| #if __TBB_64BIT_ATOMICS | | #if __TBB_64BIT_ATOMICS | |
|
| | | //TODO: consider adding non-default (and atomic) copy constructor for 32bit
platform | |
| __TBB_DECL_ATOMIC(__TBB_LONG_LONG) | | __TBB_DECL_ATOMIC(__TBB_LONG_LONG) | |
| __TBB_DECL_ATOMIC(unsigned __TBB_LONG_LONG) | | __TBB_DECL_ATOMIC(unsigned __TBB_LONG_LONG) | |
| #else | | #else | |
| // test_atomic will verify that sizeof(long long)==8 | | // test_atomic will verify that sizeof(long long)==8 | |
| #endif | | #endif | |
| __TBB_DECL_ATOMIC(long) | | __TBB_DECL_ATOMIC(long) | |
| __TBB_DECL_ATOMIC(unsigned long) | | __TBB_DECL_ATOMIC(unsigned long) | |
| | | | |
| #if _MSC_VER && !_WIN64 | | #if _MSC_VER && !_WIN64 | |
|
| | | #if __TBB_ATOMIC_CTORS | |
| /* Special version of __TBB_DECL_ATOMIC that avoids gratuitous warnings fro
m cl /Wp64 option. | | /* Special version of __TBB_DECL_ATOMIC that avoids gratuitous warnings fro
m cl /Wp64 option. | |
| It is identical to __TBB_DECL_ATOMIC(unsigned) except that it replaces o
perator=(T) | | It is identical to __TBB_DECL_ATOMIC(unsigned) except that it replaces o
perator=(T) | |
| with an operator=(U) that explicitly converts the U to a T. Types T and
U should be | | 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 | | type synonyms on the platform. Type U should be the wider variant of T
from the | |
| perspective of /Wp64. */ | | perspective of /Wp64. */ | |
| #define __TBB_DECL_ATOMIC_ALT(T,U) \ | | #define __TBB_DECL_ATOMIC_ALT(T,U) \ | |
|
| template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T, | | template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T, | |
| char> { \ | | char> { \ | |
| T operator=( U rhs ) {return store_with_release(T(rhs));} \ | | atomic() = default ; | |
| | | \ | |
| | | constexpr atomic(T arg): internal::atomic_impl_with_arithmetic<T,T, | |
| | | char>(arg) {} \ | |
| | | T operator=( U rhs ) {return store_with_release(T(rhs));} | |
| | | \ | |
| atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rh
s); return *this;} \ | | atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rh
s); return *this;} \ | |
| }; | | }; | |
|
| | | #else | |
| | | #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(rh | |
| | | s); return *this;} \ | |
| | | }; | |
| | | #endif | |
| __TBB_DECL_ATOMIC_ALT(unsigned,size_t) | | __TBB_DECL_ATOMIC_ALT(unsigned,size_t) | |
| __TBB_DECL_ATOMIC_ALT(int,ptrdiff_t) | | __TBB_DECL_ATOMIC_ALT(int,ptrdiff_t) | |
| #else | | #else | |
| __TBB_DECL_ATOMIC(unsigned) | | __TBB_DECL_ATOMIC(unsigned) | |
| __TBB_DECL_ATOMIC(int) | | __TBB_DECL_ATOMIC(int) | |
| #endif /* _MSC_VER && !_WIN64 */ | | #endif /* _MSC_VER && !_WIN64 */ | |
| | | | |
| __TBB_DECL_ATOMIC(unsigned short) | | __TBB_DECL_ATOMIC(unsigned short) | |
| __TBB_DECL_ATOMIC(short) | | __TBB_DECL_ATOMIC(short) | |
| __TBB_DECL_ATOMIC(char) | | __TBB_DECL_ATOMIC(char) | |
| __TBB_DECL_ATOMIC(signed char) | | __TBB_DECL_ATOMIC(signed char) | |
| __TBB_DECL_ATOMIC(unsigned char) | | __TBB_DECL_ATOMIC(unsigned char) | |
| | | | |
| #if !_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) | | #if !_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) | |
| __TBB_DECL_ATOMIC(wchar_t) | | __TBB_DECL_ATOMIC(wchar_t) | |
| #endif /* _MSC_VER||!defined(_NATIVE_WCHAR_T_DEFINED) */ | | #endif /* _MSC_VER||!defined(_NATIVE_WCHAR_T_DEFINED) */ | |
| | | | |
| //! Specialization for atomic<T*> with arithmetic and operator->. | | //! Specialization for atomic<T*> with arithmetic and operator->. | |
| template<typename T> struct atomic<T*>: internal::atomic_impl_with_arithmet
ic<T*,ptrdiff_t,T> { | | template<typename T> struct atomic<T*>: internal::atomic_impl_with_arithmet
ic<T*,ptrdiff_t,T> { | |
|
| | | #if __TBB_ATOMIC_CTORS | |
| | | atomic() = default ; | |
| | | constexpr atomic(T* arg): internal::atomic_impl_with_arithmetic<T*,ptrd | |
| | | iff_t,T>(arg) {} | |
| | | #endif | |
| T* operator=( T* rhs ) { | | T* operator=( T* rhs ) { | |
| // "this" required here in strict ISO C++ because store_with_releas
e is a dependent name | | // "this" required here in strict ISO C++ because store_with_releas
e is a dependent name | |
| return this->store_with_release(rhs); | | return this->store_with_release(rhs); | |
| } | | } | |
| atomic<T*>& operator=( const atomic<T*>& rhs ) { | | atomic<T*>& operator=( const atomic<T*>& rhs ) { | |
| this->store_with_release(rhs); return *this; | | this->store_with_release(rhs); return *this; | |
| } | | } | |
| T* operator->() const { | | T* operator->() const { | |
| return (*this); | | return (*this); | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! Specialization for atomic<void*>, for sake of not allowing arithmetic o
r operator->. | | //! Specialization for atomic<void*>, for sake of not allowing arithmetic o
r operator->. | |
| template<> struct atomic<void*>: internal::atomic_impl<void*> { | | template<> struct atomic<void*>: internal::atomic_impl<void*> { | |
|
| | | #if __TBB_ATOMIC_CTORS | |
| | | atomic() = default ; | |
| | | constexpr atomic(void* arg): internal::atomic_impl<void*>(arg) {} | |
| | | #endif | |
| void* operator=( void* rhs ) { | | void* operator=( void* rhs ) { | |
| // "this" required here in strict ISO C++ because store_with_releas
e is a dependent name | | // "this" required here in strict ISO C++ because store_with_releas
e is a dependent name | |
| return this->store_with_release(rhs); | | return this->store_with_release(rhs); | |
| } | | } | |
| atomic<void*>& operator=( const atomic<void*>& rhs ) { | | atomic<void*>& operator=( const atomic<void*>& rhs ) { | |
| this->store_with_release(rhs); return *this; | | this->store_with_release(rhs); return *this; | |
| } | | } | |
| }; | | }; | |
| | | | |
| // Helpers to workaround ugly syntax of calling template member function of
a | | // Helpers to workaround ugly syntax of calling template member function of
a | |
| | | | |
End of changes. 28 change blocks. |
| 43 lines changed or deleted | | 177 lines changed or added | |
|
| concurrent_unordered_map.h | | concurrent_unordered_map.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 80 | | skipping to change at line 80 | |
| }; | | }; | |
| | | | |
| template<class Type1, class Type2> | | template<class Type1, class Type2> | |
| static const Key& get_key(const std::pair<Type1, Type2>& value) { | | static const Key& get_key(const std::pair<Type1, Type2>& value) { | |
| return (value.first); | | return (value.first); | |
| } | | } | |
| | | | |
| hash_compare my_hash_compare; // the comparator predicate for keys | | hash_compare my_hash_compare; // the comparator predicate for keys | |
| }; | | }; | |
| | | | |
|
| template <typename Key, typename T, typename Hasher = tbb::tbb_hash<Key>, t | | template <typename Key, typename T, typename Hasher = tbb::tbb_hash<Key>, t | |
| ypename Key_equality = std::equal_to<Key>, typename Allocator = tbb::tbb_al | | ypename Key_equality = std::equal_to<Key>, | |
| locator<std::pair<const Key, T> > > | | typename Allocator = tbb::tbb_allocator<std::pair<const Key, T> > | |
| class concurrent_unordered_map : public internal::concurrent_unordered_base | | > | |
| < concurrent_unordered_map_traits<Key, T, internal::hash_compare<Key, Hashe | | class concurrent_unordered_map : | |
| r, Key_equality>, Allocator, false> > | | public internal::concurrent_unordered_base< concurrent_unordered_map_tr | |
| | | aits<Key, T, | |
| | | internal::hash_compare<Key, Hasher, Key_equality>, Allocator, false> > | |
| { | | { | |
| // Base type definitions | | // Base type definitions | |
| typedef internal::hash_compare<Key, Hasher, Key_equality> hash_compare; | | typedef internal::hash_compare<Key, Hasher, Key_equality> hash_compare; | |
|
| typedef internal::concurrent_unordered_base< concurrent_unordered_map_t | | typedef concurrent_unordered_map_traits<Key, T, hash_compare, Allocator | |
| raits<Key, T, hash_compare, Allocator, false> > base_type; | | , false> traits_type; | |
| typedef concurrent_unordered_map_traits<Key, T, internal::hash_compare< | | typedef internal::concurrent_unordered_base< traits_type > base_type; | |
| Key, Hasher, Key_equality>, Allocator, false> traits_type; | | | |
| using traits_type::my_hash_compare; | | using traits_type::my_hash_compare; | |
| #if __TBB_EXTRA_DEBUG | | #if __TBB_EXTRA_DEBUG | |
| public: | | public: | |
| #endif | | #endif | |
| using traits_type::allow_multimapping; | | using traits_type::allow_multimapping; | |
| public: | | public: | |
| using base_type::end; | | using base_type::end; | |
| using base_type::find; | | using base_type::find; | |
| using base_type::insert; | | using base_type::insert; | |
| | | | |
| | | | |
| skipping to change at line 120 | | skipping to change at line 123 | |
| | | | |
| typedef typename base_type::size_type size_type; | | typedef typename base_type::size_type size_type; | |
| typedef typename base_type::difference_type difference_type; | | typedef typename base_type::difference_type difference_type; | |
| | | | |
| typedef typename base_type::iterator iterator; | | typedef typename base_type::iterator iterator; | |
| typedef typename base_type::const_iterator const_iterator; | | typedef typename base_type::const_iterator const_iterator; | |
| typedef typename base_type::iterator local_iterator; | | typedef typename base_type::iterator local_iterator; | |
| typedef typename base_type::const_iterator const_local_iterator; | | typedef typename base_type::const_iterator const_local_iterator; | |
| | | | |
| // Construction/destruction/copying | | // Construction/destruction/copying | |
|
| explicit concurrent_unordered_map(size_type n_of_buckets = 8, const has | | explicit concurrent_unordered_map(size_type n_of_buckets = 8, | |
| her& a_hasher = hasher(), | | const hasher& _Hasher = hasher(), const key_equal& _Key_equality = | |
| const key_equal& a_keyeq = key_equal(), const allocator_type& a = a | | key_equal(), | |
| llocator_type()) | | const allocator_type& a = allocator_type()) | |
| : base_type(n_of_buckets, key_compare(a_hasher, a_keyeq), a) | | : base_type(n_of_buckets, key_compare(_Hasher, _Key_equality), a) | |
| { | | { | |
| } | | } | |
| | | | |
| concurrent_unordered_map(const Allocator& a) : base_type(8, key_compare
(), a) | | concurrent_unordered_map(const Allocator& a) : base_type(8, key_compare
(), a) | |
| { | | { | |
| } | | } | |
| | | | |
| template <typename Iterator> | | template <typename Iterator> | |
|
| concurrent_unordered_map(Iterator first, Iterator last, size_type n_of_ | | concurrent_unordered_map(Iterator first, Iterator last, size_type n_of_ | |
| buckets = 8, const hasher& a_hasher = hasher(), | | buckets = 8, | |
| const key_equal& a_keyeq = key_equal(), const allocator_type& a = a | | const hasher& _Hasher = hasher(), const key_equal& _Key_equality = | |
| llocator_type()) | | key_equal(), | |
| : base_type(n_of_buckets, key_compare(a_hasher, a_keyeq), a) | | const allocator_type& a = allocator_type()) | |
| | | : base_type(n_of_buckets, key_compare(_Hasher, _Key_equality), a) | |
| { | | { | |
| for (; first != last; ++first) | | for (; first != last; ++first) | |
| base_type::insert(*first); | | base_type::insert(*first); | |
| } | | } | |
| | | | |
| concurrent_unordered_map(const concurrent_unordered_map& table) : base_
type(table) | | concurrent_unordered_map(const concurrent_unordered_map& table) : base_
type(table) | |
| { | | { | |
| } | | } | |
| | | | |
| concurrent_unordered_map(const concurrent_unordered_map& table, const A
llocator& a) | | concurrent_unordered_map(const concurrent_unordered_map& table, const A
llocator& a) | |
| | | | |
| skipping to change at line 222 | | skipping to change at line 227 | |
| | | | |
| if (where == end()) | | if (where == end()) | |
| { | | { | |
| tbb::internal::throw_exception(tbb::internal::eid_invalid_key); | | tbb::internal::throw_exception(tbb::internal::eid_invalid_key); | |
| } | | } | |
| | | | |
| return ((*where).second); | | return ((*where).second); | |
| } | | } | |
| }; | | }; | |
| | | | |
|
| | | template < typename Key, typename T, typename Hasher = tbb::tbb_hash<Key>, | |
| | | typename Key_equality = std::equal_to<Key>, | |
| | | typename Allocator = tbb::tbb_allocator<std::pair<const Key, T> > > | |
| | | class concurrent_unordered_multimap : | |
| | | public internal::concurrent_unordered_base< concurrent_unordered_map_tr | |
| | | aits< Key, T, | |
| | | internal::hash_compare<Key, Hasher, Key_equality>, Allocator, true> > | |
| | | { | |
| | | // Base type definitions | |
| | | typedef internal::hash_compare<Key, Hasher, Key_equality> hash_compare; | |
| | | typedef concurrent_unordered_map_traits<Key, T, hash_compare, Allocator | |
| | | , true> traits_type; | |
| | | typedef internal::concurrent_unordered_base< traits_type > base_type; | |
| | | using traits_type::my_hash_compare; | |
| | | #if __TBB_EXTRA_DEBUG | |
| | | public: | |
| | | #endif | |
| | | using traits_type::allow_multimapping; | |
| | | public: | |
| | | using base_type::end; | |
| | | using base_type::find; | |
| | | using base_type::insert; | |
| | | | |
| | | // Type definitions | |
| | | typedef Key key_type; | |
| | | typedef typename base_type::value_type value_type; | |
| | | typedef T mapped_type; | |
| | | typedef Hasher hasher; | |
| | | typedef Key_equality key_equal; | |
| | | typedef hash_compare key_compare; | |
| | | | |
| | | typedef typename base_type::allocator_type allocator_type; | |
| | | typedef typename base_type::pointer pointer; | |
| | | typedef typename base_type::const_pointer const_pointer; | |
| | | typedef typename base_type::reference reference; | |
| | | typedef typename base_type::const_reference const_reference; | |
| | | | |
| | | typedef typename base_type::size_type size_type; | |
| | | typedef typename base_type::difference_type difference_type; | |
| | | | |
| | | typedef typename base_type::iterator iterator; | |
| | | typedef typename base_type::const_iterator const_iterator; | |
| | | typedef typename base_type::iterator local_iterator; | |
| | | typedef typename base_type::const_iterator const_local_iterator; | |
| | | | |
| | | // Construction/destruction/copying | |
| | | explicit concurrent_unordered_multimap(size_type n_of_buckets = 8, | |
| | | const hasher& _Hasher = hasher(), const key_equal& _Key_equality = | |
| | | key_equal(), | |
| | | const allocator_type& a = allocator_type()) | |
| | | : base_type(n_of_buckets, key_compare(_Hasher, _Key_equality), a) | |
| | | { | |
| | | } | |
| | | | |
| | | concurrent_unordered_multimap(const Allocator& a) : base_type(8, key_co | |
| | | mpare(), a) | |
| | | { | |
| | | } | |
| | | | |
| | | template <typename Iterator> | |
| | | concurrent_unordered_multimap(Iterator first, Iterator last, size_type | |
| | | n_of_buckets = 8, | |
| | | const hasher& _Hasher = hasher(), const key_equal& _Key_equality = | |
| | | key_equal(), | |
| | | const allocator_type& a = allocator_type()) | |
| | | : base_type(n_of_buckets,key_compare(_Hasher,_Key_equality), a) | |
| | | { | |
| | | for (; first != last; ++first) | |
| | | base_type::insert(*first); | |
| | | } | |
| | | | |
| | | concurrent_unordered_multimap(const concurrent_unordered_multimap& tabl | |
| | | e) : base_type(table) | |
| | | { | |
| | | } | |
| | | | |
| | | concurrent_unordered_multimap(const concurrent_unordered_multimap& tabl | |
| | | e, const Allocator& a) | |
| | | : base_type(table, a) | |
| | | { | |
| | | } | |
| | | | |
| | | concurrent_unordered_multimap& operator=(const concurrent_unordered_mul | |
| | | timap& table) | |
| | | { | |
| | | base_type::operator=(table); | |
| | | return (*this); | |
| | | } | |
| | | | |
| | | iterator unsafe_erase(const_iterator where) | |
| | | { | |
| | | return base_type::unsafe_erase(where); | |
| | | } | |
| | | | |
| | | size_type unsafe_erase(const key_type& key) | |
| | | { | |
| | | return base_type::unsafe_erase(key); | |
| | | } | |
| | | | |
| | | iterator unsafe_erase(const_iterator first, const_iterator last) | |
| | | { | |
| | | return base_type::unsafe_erase(first, last); | |
| | | } | |
| | | | |
| | | void swap(concurrent_unordered_multimap& table) | |
| | | { | |
| | | base_type::swap(table); | |
| | | } | |
| | | | |
| | | // Observers | |
| | | hasher hash_function() const | |
| | | { | |
| | | return my_hash_compare.my_hash_object; | |
| | | } | |
| | | | |
| | | key_equal key_eq() const | |
| | | { | |
| | | return my_hash_compare.my_key_compare_object; | |
| | | } | |
| | | }; | |
| } // namespace interface5 | | } // namespace interface5 | |
| | | | |
| using interface5::concurrent_unordered_map; | | using interface5::concurrent_unordered_map; | |
|
| | | using interface5::concurrent_unordered_multimap; | |
| | | | |
| } // namespace tbb | | } // namespace tbb | |
| | | | |
| #endif// __TBB_concurrent_unordered_map_H | | #endif// __TBB_concurrent_unordered_map_H | |
| | | | |
End of changes. 7 change blocks. |
| 21 lines changed or deleted | | 144 lines changed or added | |
|
| concurrent_unordered_set.h | | concurrent_unordered_set.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 171 | | skipping to change at line 171 | |
| { | | { | |
| return my_hash_compare.my_hash_object; | | return my_hash_compare.my_hash_object; | |
| } | | } | |
| | | | |
| key_equal key_eq() const | | key_equal key_eq() const | |
| { | | { | |
| return my_hash_compare.my_key_compare_object; | | return my_hash_compare.my_key_compare_object; | |
| } | | } | |
| }; | | }; | |
| | | | |
|
| | | template <typename Key, typename Hasher = tbb::tbb_hash<Key>, typename Key_ | |
| | | equality = std::equal_to<Key>, | |
| | | typename Allocator = tbb::tbb_allocator<Key> > | |
| | | class concurrent_unordered_multiset : | |
| | | public internal::concurrent_unordered_base< concurrent_unordered_set_tr | |
| | | aits<Key, | |
| | | internal::hash_compare<Key, Hasher, Key_equality>, Allocator, true> > | |
| | | { | |
| | | public: | |
| | | // Base type definitions | |
| | | typedef internal::hash_compare<Key, Hasher, Key_equality> hash_compare; | |
| | | typedef concurrent_unordered_set_traits<Key, hash_compare, Allocator, t | |
| | | rue> traits_type; | |
| | | typedef internal::concurrent_unordered_base< traits_type > base_type; | |
| | | using traits_type::allow_multimapping; | |
| | | using traits_type::my_hash_compare; | |
| | | | |
| | | // Type definitions | |
| | | typedef Key key_type; | |
| | | typedef typename base_type::value_type value_type; | |
| | | typedef Key mapped_type; | |
| | | typedef Hasher hasher; | |
| | | typedef Key_equality key_equal; | |
| | | typedef hash_compare key_compare; | |
| | | | |
| | | typedef typename base_type::allocator_type allocator_type; | |
| | | typedef typename base_type::pointer pointer; | |
| | | typedef typename base_type::const_pointer const_pointer; | |
| | | typedef typename base_type::reference reference; | |
| | | typedef typename base_type::const_reference const_reference; | |
| | | | |
| | | typedef typename base_type::size_type size_type; | |
| | | typedef typename base_type::difference_type difference_type; | |
| | | | |
| | | typedef typename base_type::iterator iterator; | |
| | | typedef typename base_type::const_iterator const_iterator; | |
| | | typedef typename base_type::iterator local_iterator; | |
| | | typedef typename base_type::const_iterator const_local_iterator; | |
| | | | |
| | | // Construction/destruction/copying | |
| | | explicit concurrent_unordered_multiset(size_type n_of_buckets = 8, | |
| | | const hasher& _Hasher = hasher(), const key_equal& _Key_equality = | |
| | | key_equal(), | |
| | | const allocator_type& a = allocator_type()) | |
| | | : base_type(n_of_buckets, key_compare(_Hasher, _Key_equality), a) | |
| | | { | |
| | | } | |
| | | | |
| | | concurrent_unordered_multiset(const Allocator& a) : base_type(8, key_co | |
| | | mpare(), a) | |
| | | { | |
| | | } | |
| | | | |
| | | template <typename Iterator> | |
| | | concurrent_unordered_multiset(Iterator first, Iterator last, size_type | |
| | | n_of_buckets = 8, | |
| | | const hasher& _Hasher = hasher(), const key_equal& _Key_equality = | |
| | | key_equal(), | |
| | | const allocator_type& a = allocator_type()) | |
| | | : base_type(n_of_buckets, key_compare(_Hasher, _Key_equality), a) | |
| | | { | |
| | | for (; first != last; ++first) | |
| | | { | |
| | | base_type::insert(*first); | |
| | | } | |
| | | } | |
| | | | |
| | | concurrent_unordered_multiset(const concurrent_unordered_multiset& tabl | |
| | | e) : base_type(table) | |
| | | { | |
| | | } | |
| | | | |
| | | concurrent_unordered_multiset(const concurrent_unordered_multiset& tabl | |
| | | e, const Allocator& a) : base_type(table, a) | |
| | | { | |
| | | } | |
| | | | |
| | | concurrent_unordered_multiset& operator=(const concurrent_unordered_mul | |
| | | tiset& table) | |
| | | { | |
| | | base_type::operator=(table); | |
| | | return (*this); | |
| | | } | |
| | | | |
| | | // Modifiers | |
| | | std::pair<iterator, bool> insert(const value_type& value) | |
| | | { | |
| | | return base_type::insert(value); | |
| | | } | |
| | | | |
| | | iterator insert(const_iterator where, const value_type& value) | |
| | | { | |
| | | return base_type::insert(where, value); | |
| | | } | |
| | | | |
| | | template<class Iterator> | |
| | | void insert(Iterator first, Iterator last) | |
| | | { | |
| | | base_type::insert(first, last); | |
| | | } | |
| | | | |
| | | iterator unsafe_erase(const_iterator where) | |
| | | { | |
| | | return base_type::unsafe_erase(where); | |
| | | } | |
| | | | |
| | | size_type unsafe_erase(const key_type& key) | |
| | | { | |
| | | return base_type::unsafe_erase(key); | |
| | | } | |
| | | | |
| | | iterator unsafe_erase(const_iterator first, const_iterator last) | |
| | | { | |
| | | return base_type::unsafe_erase(first, last); | |
| | | } | |
| | | | |
| | | void swap(concurrent_unordered_multiset& table) | |
| | | { | |
| | | base_type::swap(table); | |
| | | } | |
| | | | |
| | | // Observers | |
| | | hasher hash_function() const | |
| | | { | |
| | | return my_hash_compare.my_hash_object; | |
| | | } | |
| | | | |
| | | key_equal key_eq() const | |
| | | { | |
| | | return my_hash_compare.my_key_compare_object; | |
| | | } | |
| | | }; | |
| } // namespace interface5 | | } // namespace interface5 | |
| | | | |
| using interface5::concurrent_unordered_set; | | using interface5::concurrent_unordered_set; | |
|
| | | using interface5::concurrent_unordered_multiset; | |
| | | | |
| } // namespace tbb | | } // namespace tbb | |
| | | | |
| #endif// __TBB_concurrent_unordered_set_H | | #endif// __TBB_concurrent_unordered_set_H | |
| | | | |
End of changes. 3 change blocks. |
| 1 lines changed or deleted | | 134 lines changed or added | |
|
| icc_generic.h | | icc_generic.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 80 | | skipping to change at line 80 | |
| namespace tbb { namespace internal { | | namespace tbb { namespace internal { | |
| //TODO: is there any way to reuse definition of memory_order enum from ICC
instead of copy paste. | | //TODO: is there any way to reuse definition of memory_order enum from ICC
instead of copy paste. | |
| //however it seems unlikely that ICC will silently change exact enum values
, as they are defined | | //however it seems unlikely that ICC will silently change exact enum values
, as they are defined | |
| //in the ISO exactly like this. | | //in the ISO exactly like this. | |
| //TODO: add test that exact values of the enum are same as in the ISO C++11 | | //TODO: add test that exact values of the enum are same as in the ISO C++11 | |
| typedef enum memory_order { | | typedef enum memory_order { | |
| memory_order_relaxed, memory_order_consume, memory_order_acquire, | | memory_order_relaxed, memory_order_consume, memory_order_acquire, | |
| memory_order_release, memory_order_acq_rel, memory_order_seq_cst | | memory_order_release, memory_order_acq_rel, memory_order_seq_cst | |
| } memory_order; | | } memory_order; | |
| | | | |
|
| | | namespace icc_intrinsics_port { | |
| | | template <typename T> | |
| | | T convert_argument(T value){ | |
| | | return value; | |
| | | } | |
| | | //The overload below is needed to have explicit conversion of pointer t | |
| | | o void* in argument list. | |
| | | //compiler bug? | |
| | | //TODO: add according broken macro and recheck with ICC 13.0 if the ove | |
| | | rload is still needed | |
| | | template <typename T> | |
| | | void* convert_argument(T* value){ | |
| | | return (void*)value; | |
| | | } | |
| | | } | |
| | | //TODO: code bellow is a bit repetitive, consider simplifying it | |
| template <typename T, size_t S> | | template <typename T, size_t S> | |
| struct machine_load_store { | | struct machine_load_store { | |
| static T load_with_acquire ( const volatile T& location ) { | | static T load_with_acquire ( const volatile T& location ) { | |
| return __atomic_load_explicit(&location, memory_order_acquire); | | return __atomic_load_explicit(&location, memory_order_acquire); | |
| } | | } | |
| static void store_with_release ( volatile T &location, T value ) { | | static void store_with_release ( volatile T &location, T value ) { | |
|
| __atomic_store_explicit(&location, value, memory_order_release); | | __atomic_store_explicit(&location, icc_intrinsics_port::convert_arg | |
| } | | ument(value), memory_order_release); | |
| }; | | | |
| //The specializations below are needed to have explicit conversion of point | | | |
| er to void* in argument list. | | | |
| //compiler bug? | | | |
| //TODO: move to workaround to separate layer by wrapping the call to __atom | | | |
| ic_store_explicit in overloaded template function | | | |
| template <typename T, size_t S> | | | |
| struct machine_load_store<T*, S> { | | | |
| static T* load_with_acquire ( T* const volatile & location ) { | | | |
| return __atomic_load_explicit(&location, memory_order_acquire); | | | |
| } | | | |
| static void store_with_release ( T* volatile &location, T* value ) { | | | |
| __atomic_store_explicit(&location, (void*) value, memory_order_rele | | | |
| ase); | | | |
| } | | } | |
| }; | | }; | |
|
| | | | |
| template <typename T, size_t S> | | template <typename T, size_t S> | |
| struct machine_load_store_relaxed { | | struct machine_load_store_relaxed { | |
| static inline T load ( const T& location ) { | | static inline T load ( const T& location ) { | |
| return __atomic_load_explicit(&location, memory_order_relaxed); | | return __atomic_load_explicit(&location, memory_order_relaxed); | |
| } | | } | |
| static inline void store ( T& location, T value ) { | | static inline void store ( T& location, T value ) { | |
|
| __atomic_store_explicit(&location, value, memory_order_relaxed); | | __atomic_store_explicit(&location, icc_intrinsics_port::convert_arg
ument(value), memory_order_relaxed); | |
| } | | } | |
| }; | | }; | |
| | | | |
| template <typename T, size_t S> | | template <typename T, size_t S> | |
|
| struct machine_load_store_relaxed<T*, S> { | | | |
| static inline T* load ( T* const& location ) { | | | |
| return (T*)__atomic_load_explicit(&location, memory_order_relaxed); | | | |
| } | | | |
| static inline void store ( T*& location, T* value ) { | | | |
| __atomic_store_explicit(&location, (void*)value, memory_order_relax | | | |
| ed); | | | |
| } | | | |
| }; | | | |
| template <typename T, size_t S> | | | |
| struct machine_load_store_seq_cst { | | struct machine_load_store_seq_cst { | |
| static T load ( const volatile T& location ) { | | static T load ( const volatile T& location ) { | |
| return __atomic_load_explicit(&location, memory_order_seq_cst); | | return __atomic_load_explicit(&location, memory_order_seq_cst); | |
| } | | } | |
| | | | |
| static void store ( volatile T &location, T value ) { | | static void store ( volatile T &location, T value ) { | |
| __atomic_store_explicit(&location, value, memory_order_seq_cst); | | __atomic_store_explicit(&location, value, memory_order_seq_cst); | |
| } | | } | |
| }; | | }; | |
|
| | | | |
| }} // namespace tbb::internal | | }} // namespace tbb::internal | |
| | | | |
| namespace tbb{ namespace internal { namespace icc_intrinsics_port{ | | namespace tbb{ namespace internal { namespace icc_intrinsics_port{ | |
| typedef enum memory_order_map { | | typedef enum memory_order_map { | |
| relaxed = memory_order_relaxed, | | relaxed = memory_order_relaxed, | |
| acquire = memory_order_acquire, | | acquire = memory_order_acquire, | |
| release = memory_order_release, | | release = memory_order_release, | |
| full_fence= memory_order_seq_cst | | full_fence= memory_order_seq_cst | |
| } memory_order_map; | | } memory_order_map; | |
| }}}// namespace tbb::internal | | }}}// namespace tbb::internal | |
| | | | |
| skipping to change at line 184 | | skipping to change at line 179 | |
| | | | |
| __TBB_MACHINE_DEFINE_ATOMICS(8,tbb::internal::int64_t, full_fence) | | __TBB_MACHINE_DEFINE_ATOMICS(8,tbb::internal::int64_t, full_fence) | |
| __TBB_MACHINE_DEFINE_ATOMICS(8,tbb::internal::int64_t, acquire) | | __TBB_MACHINE_DEFINE_ATOMICS(8,tbb::internal::int64_t, acquire) | |
| __TBB_MACHINE_DEFINE_ATOMICS(8,tbb::internal::int64_t, release) | | __TBB_MACHINE_DEFINE_ATOMICS(8,tbb::internal::int64_t, release) | |
| __TBB_MACHINE_DEFINE_ATOMICS(8,tbb::internal::int64_t, relaxed) | | __TBB_MACHINE_DEFINE_ATOMICS(8,tbb::internal::int64_t, relaxed) | |
| | | | |
| #undef __TBB_MACHINE_DEFINE_ATOMICS | | #undef __TBB_MACHINE_DEFINE_ATOMICS | |
| | | | |
| #define __TBB_USE_FENCED_ATOMICS 1 | | #define __TBB_USE_FENCED_ATOMICS 1 | |
| | | | |
|
| | | namespace tbb { namespace internal { | |
| | | #if __TBB_FORCE_64BIT_ALIGNMENT_BROKEN | |
| | | __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(full_fence) | |
| | | __TBB_MACHINE_DEFINE_STORE8_GENERIC_FENCED(full_fence) | |
| | | | |
| | | __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(acquire) | |
| | | __TBB_MACHINE_DEFINE_STORE8_GENERIC_FENCED(release) | |
| | | | |
| | | __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(relaxed) | |
| | | __TBB_MACHINE_DEFINE_STORE8_GENERIC_FENCED(relaxed) | |
| | | | |
| | | template <typename T> | |
| | | struct machine_load_store<T,8> { | |
| | | static T load_with_acquire ( const volatile T& location ) { | |
| | | if( tbb::internal::is_aligned(&location,8)) { | |
| | | return __atomic_load_explicit(&location, memory_order_acquire); | |
| | | } else { | |
| | | return __TBB_machine_generic_load8acquire(&location); | |
| | | } | |
| | | } | |
| | | static void store_with_release ( volatile T &location, T value ) { | |
| | | if( tbb::internal::is_aligned(&location,8)) { | |
| | | __atomic_store_explicit(&location, icc_intrinsics_port::convert | |
| | | _argument(value), memory_order_release); | |
| | | } else { | |
| | | return __TBB_machine_generic_store8release(&location,value); | |
| | | } | |
| | | } | |
| | | }; | |
| | | | |
| | | template <typename T> | |
| | | struct machine_load_store_relaxed<T,8> { | |
| | | static T load( const volatile T& location ) { | |
| | | if( tbb::internal::is_aligned(&location,8)) { | |
| | | return __atomic_load_explicit(&location, memory_order_relaxed); | |
| | | } else { | |
| | | return __TBB_machine_generic_load8relaxed(&location); | |
| | | } | |
| | | } | |
| | | static void store( volatile T &location, T value ) { | |
| | | if( tbb::internal::is_aligned(&location,8)) { | |
| | | __atomic_store_explicit(&location, icc_intrinsics_port::convert | |
| | | _argument(value), memory_order_relaxed); | |
| | | } else { | |
| | | return __TBB_machine_generic_store8relaxed(&location,value); | |
| | | } | |
| | | } | |
| | | }; | |
| | | | |
| | | template <typename T > | |
| | | struct machine_load_store_seq_cst<T,8> { | |
| | | static T load ( const volatile T& location ) { | |
| | | if( tbb::internal::is_aligned(&location,8)) { | |
| | | return __atomic_load_explicit(&location, memory_order_seq_cst); | |
| | | } else { | |
| | | return __TBB_machine_generic_load8full_fence(&location); | |
| | | } | |
| | | | |
| | | } | |
| | | | |
| | | static void store ( volatile T &location, T value ) { | |
| | | if( tbb::internal::is_aligned(&location,8)) { | |
| | | __atomic_store_explicit(&location, value, memory_order_seq_cst) | |
| | | ; | |
| | | } else { | |
| | | return __TBB_machine_generic_store8full_fence(&location,value); | |
| | | } | |
| | | | |
| | | } | |
| | | }; | |
| | | | |
| | | #endif | |
| | | }} // namespace tbb::internal | |
| template <typename T> | | template <typename T> | |
| inline void __TBB_machine_OR( T *operand, T addend ) { | | inline void __TBB_machine_OR( T *operand, T addend ) { | |
| __atomic_fetch_or_explicit(operand, addend, tbb::internal::memory_order
_seq_cst); | | __atomic_fetch_or_explicit(operand, addend, tbb::internal::memory_order
_seq_cst); | |
| } | | } | |
| | | | |
| template <typename T> | | template <typename T> | |
| inline void __TBB_machine_AND( T *operand, T addend ) { | | inline void __TBB_machine_AND( T *operand, T addend ) { | |
| __atomic_fetch_and_explicit(operand, addend, tbb::internal::memory_orde
r_seq_cst); | | __atomic_fetch_and_explicit(operand, addend, tbb::internal::memory_orde
r_seq_cst); | |
| } | | } | |
| | | | |
End of changes. 8 change blocks. |
| 28 lines changed or deleted | | 95 lines changed or added | |
|
| linux_ia32.h | | linux_ia32.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 172 | | skipping to change at line 172 | |
| //for sequentially consistent load/store, instead of CAS. | | //for sequentially consistent load/store, instead of CAS. | |
| | | | |
| #if __clang__ | | #if __clang__ | |
| #define __TBB_fildq "fildll" | | #define __TBB_fildq "fildll" | |
| #define __TBB_fistpq "fistpll" | | #define __TBB_fistpq "fistpll" | |
| #else | | #else | |
| #define __TBB_fildq "fildq" | | #define __TBB_fildq "fildq" | |
| #define __TBB_fistpq "fistpq" | | #define __TBB_fistpq "fistpq" | |
| #endif | | #endif | |
| | | | |
|
| static inline int64_t __TBB_machine_load8 (const volatile void *ptr) { | | static inline int64_t __TBB_machine_aligned_load8 (const volatile void *ptr | |
| | | ) { | |
| | | __TBB_ASSERT(tbb::internal::is_aligned(ptr,8),"__TBB_machine_aligned_lo | |
| | | ad8 should be used with 8 byte aligned locations only \n"); | |
| int64_t result; | | int64_t result; | |
|
| if( ((uint32_t)ptr&7u)==0 ) { | | __asm__ __volatile__ ( __TBB_fildq " %1\n\t" | |
| // Aligned load | | __TBB_fistpq " %0" : "=m"(result) : "m"(*(const | |
| __asm__ __volatile__ ( __TBB_fildq " %1\n\t" | | __TBB_VOLATILE uint64_t*)ptr) : "memory" ); | |
| __TBB_fistpq " %0" : "=m"(result) : "m"(*(c | | return result; | |
| onst __TBB_VOLATILE uint64_t*)ptr) : "memory" ); | | } | |
| | | | |
| | | static inline void __TBB_machine_aligned_store8 (volatile void *ptr, int64_ | |
| | | t value ) { | |
| | | __TBB_ASSERT(tbb::internal::is_aligned(ptr,8),"__TBB_machine_aligned_st | |
| | | ore8 should be used with 8 byte aligned locations only \n"); | |
| | | // Aligned store | |
| | | __asm__ __volatile__ ( __TBB_fildq " %1\n\t" | |
| | | __TBB_fistpq " %0" : "=m"(*(__TBB_VOLATILE int6 | |
| | | 4_t*)ptr) : "m"(value) : "memory" ); | |
| | | } | |
| | | | |
| | | static inline int64_t __TBB_machine_load8 (const volatile void *ptr) { | |
| | | #if __TBB_FORCE_64BIT_ALIGNMENT_BROKEN | |
| | | if( tbb::internal::is_aligned(ptr,8)) { | |
| | | #endif | |
| | | return __TBB_machine_aligned_load8(ptr); | |
| | | #if __TBB_FORCE_64BIT_ALIGNMENT_BROKEN | |
| } else { | | } else { | |
| // Unaligned load | | // Unaligned load | |
|
| result = __TBB_machine_cmpswp8(const_cast<void*>(ptr),0,0); | | return __TBB_machine_cmpswp8(const_cast<void*>(ptr),0,0); | |
| } | | } | |
|
| return result; | | #endif | |
| } | | } | |
| | | | |
| //! Handles misaligned 8-byte store | | //! Handles misaligned 8-byte store | |
| /** Defined in tbb_misc.cpp */ | | /** Defined in tbb_misc.cpp */ | |
| extern "C" void __TBB_machine_store8_slow( volatile void *ptr, int64_t valu
e ); | | extern "C" void __TBB_machine_store8_slow( volatile void *ptr, int64_t valu
e ); | |
| extern "C" void __TBB_machine_store8_slow_perf_warning( volatile void *ptr
); | | extern "C" void __TBB_machine_store8_slow_perf_warning( volatile void *ptr
); | |
| | | | |
| static inline void __TBB_machine_store8(volatile void *ptr, int64_t value)
{ | | static inline void __TBB_machine_store8(volatile void *ptr, int64_t value)
{ | |
|
| if( ((uint32_t)ptr&7u)==0 ) { | | #if __TBB_FORCE_64BIT_ALIGNMENT_BROKEN | |
| // Aligned store | | if( tbb::internal::is_aligned(ptr,8)) { | |
| __asm__ __volatile__ ( __TBB_fildq " %1\n\t" | | #endif | |
| __TBB_fistpq " %0" : "=m"(*(__TBB_VOLATILE | | __TBB_machine_aligned_store8(ptr,value); | |
| int64_t*)ptr) : "m"(value) : "memory" ); | | #if __TBB_FORCE_64BIT_ALIGNMENT_BROKEN | |
| } else { | | } else { | |
| // Unaligned store | | // Unaligned store | |
| #if TBB_USE_PERFORMANCE_WARNINGS | | #if TBB_USE_PERFORMANCE_WARNINGS | |
| __TBB_machine_store8_slow_perf_warning(ptr); | | __TBB_machine_store8_slow_perf_warning(ptr); | |
| #endif /* TBB_USE_PERFORMANCE_WARNINGS */ | | #endif /* TBB_USE_PERFORMANCE_WARNINGS */ | |
| __TBB_machine_store8_slow(ptr,value); | | __TBB_machine_store8_slow(ptr,value); | |
| } | | } | |
|
| | | #endif | |
| } | | } | |
| | | | |
| // Machine specific atomic operations | | // Machine specific atomic operations | |
| #define __TBB_AtomicOR(P,V) __TBB_machine_or(P,V) | | #define __TBB_AtomicOR(P,V) __TBB_machine_or(P,V) | |
| #define __TBB_AtomicAND(P,V) __TBB_machine_and(P,V) | | #define __TBB_AtomicAND(P,V) __TBB_machine_and(P,V) | |
| | | | |
| #define __TBB_USE_GENERIC_DWORD_FETCH_ADD 1 | | #define __TBB_USE_GENERIC_DWORD_FETCH_ADD 1 | |
| #define __TBB_USE_GENERIC_DWORD_FETCH_STORE 1 | | #define __TBB_USE_GENERIC_DWORD_FETCH_STORE 1 | |
| #define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | | #define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | |
| #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | | #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | |
| | | | |
End of changes. 7 change blocks. |
| 14 lines changed or deleted | | 35 lines changed or added | |
|
| macos_common.h | | macos_common.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 59 | | skipping to change at line 59 | |
| } | | } | |
| | | | |
| #define __TBB_HardwareConcurrency() __TBB_macos_available_cpu() | | #define __TBB_HardwareConcurrency() __TBB_macos_available_cpu() | |
| | | | |
| #ifndef __TBB_full_memory_fence | | #ifndef __TBB_full_memory_fence | |
| // TBB has not recognized the architecture (none of the architecture ab
straction | | // TBB has not recognized the architecture (none of the architecture ab
straction | |
| // headers was included). | | // headers was included). | |
| #define __TBB_UnknownArchitecture 1 | | #define __TBB_UnknownArchitecture 1 | |
| #endif | | #endif | |
| | | | |
|
| #if __TBB_UnknownArchitecture || (__TBB_WORDSIZE==4 && !TBB_USE_ICC_BUILTIN | | #if __TBB_UnknownArchitecture | |
| S) | | | |
| // In case of IA32 this is a workaround for compiler bugs triggered by inli | | | |
| ne | | | |
| // assembly implementation of __TBB_machine_cmpswp8 in linux_ia32.h, which | | | |
| may | | | |
| // lead to incorrect codegen (gcc) or compilation failures (any icc includi | | | |
| ng 12.0.4). | | | |
| | | | |
| // Implementation of atomic operations based on OS provided primitives | | // Implementation of atomic operations based on OS provided primitives | |
| #include <libkern/OSAtomic.h> | | #include <libkern/OSAtomic.h> | |
| | | | |
| static inline int64_t __TBB_machine_cmpswp8_OsX(volatile void *ptr, int64_t
value, int64_t comparand) | | static inline int64_t __TBB_machine_cmpswp8_OsX(volatile void *ptr, int64_t
value, int64_t comparand) | |
| { | | { | |
|
| __TBB_ASSERT( !((uintptr_t)ptr&0x7), "address not properly aligned for
Mac OS atomics"); | | __TBB_ASSERT( tbb::internal::is_aligned(ptr,8), "address not properly a
ligned for Mac OS atomics"); | |
| int64_t* address = (int64_t*)ptr; | | int64_t* address = (int64_t*)ptr; | |
| while( !OSAtomicCompareAndSwap64Barrier(comparand, value, address) ){ | | while( !OSAtomicCompareAndSwap64Barrier(comparand, value, address) ){ | |
| #if __TBB_WORDSIZE==8 | | #if __TBB_WORDSIZE==8 | |
| int64_t snapshot = *address; | | int64_t snapshot = *address; | |
| #else | | #else | |
| int64_t snapshot = OSAtomicAdd64( 0, address ); | | int64_t snapshot = OSAtomicAdd64( 0, address ); | |
| #endif | | #endif | |
| if( snapshot!=comparand ) return snapshot; | | if( snapshot!=comparand ) return snapshot; | |
| } | | } | |
| return comparand; | | return comparand; | |
| } | | } | |
| | | | |
| #define __TBB_machine_cmpswp8 __TBB_machine_cmpswp8_OsX | | #define __TBB_machine_cmpswp8 __TBB_machine_cmpswp8_OsX | |
| | | | |
|
| #endif /* __TBB_UnknownArchitecture || (__TBB_WORDSIZE==4 && !TBB_USE_ICC_B
UILTINS) */ | | #endif /* __TBB_UnknownArchitecture */ | |
| | | | |
| #if __TBB_UnknownArchitecture | | #if __TBB_UnknownArchitecture | |
| | | | |
| #ifndef __TBB_WORDSIZE | | #ifndef __TBB_WORDSIZE | |
| #define __TBB_WORDSIZE 4 | | #define __TBB_WORDSIZE 4 | |
| #endif | | #endif | |
| | | | |
| #ifdef __TBB_BIG_ENDIAN | | #ifdef __TBB_BIG_ENDIAN | |
| // Already determined based on hardware architecture. | | // Already determined based on hardware architecture. | |
| #elif __BIG_ENDIAN__ | | #elif __BIG_ENDIAN__ | |
| | | | |
| skipping to change at line 114 | | skipping to change at line 110 | |
| fence usages where a more lightweight synchronization means (or none at
all) | | fence usages where a more lightweight synchronization means (or none at
all) | |
| could suffice. Thus if you use this header to enable TBB on a new platf
orm, | | could suffice. Thus if you use this header to enable TBB on a new platf
orm, | |
| consider forking it and relaxing below helpers as appropriate. **/ | | consider forking it and relaxing below helpers as appropriate. **/ | |
| #define __TBB_control_consistency_helper() OSMemoryBarrier() | | #define __TBB_control_consistency_helper() OSMemoryBarrier() | |
| #define __TBB_acquire_consistency_helper() OSMemoryBarrier() | | #define __TBB_acquire_consistency_helper() OSMemoryBarrier() | |
| #define __TBB_release_consistency_helper() OSMemoryBarrier() | | #define __TBB_release_consistency_helper() OSMemoryBarrier() | |
| #define __TBB_full_memory_fence() OSMemoryBarrier() | | #define __TBB_full_memory_fence() OSMemoryBarrier() | |
| | | | |
| static inline int32_t __TBB_machine_cmpswp4(volatile void *ptr, int32_t val
ue, int32_t comparand) | | static inline int32_t __TBB_machine_cmpswp4(volatile void *ptr, int32_t val
ue, int32_t comparand) | |
| { | | { | |
|
| __TBB_ASSERT( !((uintptr_t)ptr&0x3), "address not properly aligned for
Mac OS atomics"); | | __TBB_ASSERT( tbb::internal::is_aligned(ptr,4), "address not properly a
ligned for Mac OS atomics"); | |
| int32_t* address = (int32_t*)ptr; | | int32_t* address = (int32_t*)ptr; | |
| while( !OSAtomicCompareAndSwap32Barrier(comparand, value, address) ){ | | while( !OSAtomicCompareAndSwap32Barrier(comparand, value, address) ){ | |
| int32_t snapshot = *address; | | int32_t snapshot = *address; | |
| if( snapshot!=comparand ) return snapshot; | | if( snapshot!=comparand ) return snapshot; | |
| } | | } | |
| return comparand; | | return comparand; | |
| } | | } | |
| | | | |
| static inline int32_t __TBB_machine_fetchadd4(volatile void *ptr, int32_t a
ddend) | | static inline int32_t __TBB_machine_fetchadd4(volatile void *ptr, int32_t a
ddend) | |
| { | | { | |
|
| __TBB_ASSERT( !((uintptr_t)ptr&0x3), "address not properly aligned for
Mac OS atomics"); | | __TBB_ASSERT( tbb::internal::is_aligned(ptr,4), "address not properly a
ligned for Mac OS atomics"); | |
| return OSAtomicAdd32Barrier(addend, (int32_t*)ptr) - addend; | | return OSAtomicAdd32Barrier(addend, (int32_t*)ptr) - addend; | |
| } | | } | |
| | | | |
| static inline int64_t __TBB_machine_fetchadd8(volatile void *ptr, int64_t a
ddend) | | static inline int64_t __TBB_machine_fetchadd8(volatile void *ptr, int64_t a
ddend) | |
| { | | { | |
|
| __TBB_ASSERT( !((uintptr_t)ptr&0x7), "address not properly aligned for
Mac OS atomics"); | | __TBB_ASSERT( tbb::internal::is_aligned(ptr,8), "address not properly a
ligned for Mac OS atomics"); | |
| return OSAtomicAdd64Barrier(addend, (int64_t*)ptr) - addend; | | return OSAtomicAdd64Barrier(addend, (int64_t*)ptr) - addend; | |
| } | | } | |
| | | | |
| #define __TBB_USE_GENERIC_PART_WORD_CAS 1 | | #define __TBB_USE_GENERIC_PART_WORD_CAS 1 | |
| #define __TBB_USE_GENERIC_PART_WORD_FETCH_ADD 1 | | #define __TBB_USE_GENERIC_PART_WORD_FETCH_ADD 1 | |
| #define __TBB_USE_GENERIC_FETCH_STORE 1 | | #define __TBB_USE_GENERIC_FETCH_STORE 1 | |
| #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | | #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | |
| #define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | | #define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | |
| #if __TBB_WORDSIZE == 4 | | #if __TBB_WORDSIZE == 4 | |
| #define __TBB_USE_GENERIC_DWORD_LOAD_STORE 1 | | #define __TBB_USE_GENERIC_DWORD_LOAD_STORE 1 | |
| | | | |
End of changes. 7 change blocks. |
| 15 lines changed or deleted | | 7 lines changed or added | |
|
| parallel_scan.h | | parallel_scan.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 59 | | skipping to change at line 59 | |
| }; | | }; | |
| | | | |
| //! @cond INTERNAL | | //! @cond INTERNAL | |
| namespace internal { | | namespace internal { | |
| | | | |
| //! Performs final scan for a leaf | | //! Performs final scan for a leaf | |
| /** @ingroup algorithms */ | | /** @ingroup algorithms */ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| class final_sum: public task { | | class final_sum: public task { | |
| public: | | public: | |
|
| Body body; | | Body my_body; | |
| private: | | private: | |
|
| aligned_space<Range,1> range; | | aligned_space<Range,1> my_range; | |
| //! Where to put result of last subrange, or NULL if not last subra
nge. | | //! Where to put result of last subrange, or NULL if not last subra
nge. | |
|
| Body* stuff_last; | | Body* my_stuff_last; | |
| public: | | public: | |
| final_sum( Body& body_ ) : | | final_sum( Body& body_ ) : | |
|
| body(body_,split()) | | my_body(body_,split()) | |
| { | | { | |
|
| poison_pointer(stuff_last); | | poison_pointer(my_stuff_last); | |
| } | | } | |
| ~final_sum() { | | ~final_sum() { | |
|
| range.begin()->~Range(); | | my_range.begin()->~Range(); | |
| } | | } | |
| void finish_construction( const Range& range_, Body* stuff_last_ )
{ | | void finish_construction( const Range& range_, Body* stuff_last_ )
{ | |
|
| new( range.begin() ) Range(range_); | | new( my_range.begin() ) Range(range_); | |
| stuff_last = stuff_last_; | | my_stuff_last = stuff_last_; | |
| } | | } | |
| private: | | private: | |
| /*override*/ task* execute() { | | /*override*/ task* execute() { | |
|
| body( *range.begin(), final_scan_tag() ); | | my_body( *my_range.begin(), final_scan_tag() ); | |
| if( stuff_last ) | | if( my_stuff_last ) | |
| stuff_last->assign(body); | | my_stuff_last->assign(my_body); | |
| return NULL; | | return NULL; | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! Split work to be done in the scan. | | //! Split work to be done in the scan. | |
| /** @ingroup algorithms */ | | /** @ingroup algorithms */ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| class sum_node: public task { | | class sum_node: public task { | |
| typedef final_sum<Range,Body> final_sum_type; | | typedef final_sum<Range,Body> final_sum_type; | |
| public: | | public: | |
|
| final_sum_type *incoming; | | final_sum_type *my_incoming; | |
| final_sum_type *body; | | final_sum_type *my_body; | |
| Body *stuff_last; | | Body *my_stuff_last; | |
| private: | | private: | |
|
| final_sum_type *left_sum; | | final_sum_type *my_left_sum; | |
| sum_node *left; | | sum_node *my_left; | |
| sum_node *right; | | sum_node *my_right; | |
| bool left_is_final; | | bool my_left_is_final; | |
| Range range; | | Range my_range; | |
| sum_node( const Range range_, bool left_is_final_ ) : | | sum_node( const Range range_, bool left_is_final_ ) : | |
|
| left_sum(NULL), | | my_left_sum(NULL), | |
| left(NULL), | | my_left(NULL), | |
| right(NULL), | | my_right(NULL), | |
| left_is_final(left_is_final_), | | my_left_is_final(left_is_final_), | |
| range(range_) | | my_range(range_) | |
| { | | { | |
| // Poison fields that will be set by second pass. | | // Poison fields that will be set by second pass. | |
|
| poison_pointer(body); | | poison_pointer(my_body); | |
| poison_pointer(incoming); | | poison_pointer(my_incoming); | |
| } | | } | |
| task* create_child( const Range& range_, final_sum_type& f, sum_nod
e* n, final_sum_type* incoming_, Body* stuff_last_ ) { | | task* create_child( const Range& range_, final_sum_type& f, sum_nod
e* n, final_sum_type* incoming_, Body* stuff_last_ ) { | |
| if( !n ) { | | if( !n ) { | |
| f.recycle_as_child_of( *this ); | | f.recycle_as_child_of( *this ); | |
| f.finish_construction( range_, stuff_last_ ); | | f.finish_construction( range_, stuff_last_ ); | |
| return &f; | | return &f; | |
| } else { | | } else { | |
|
| n->body = &f; | | n->my_body = &f; | |
| n->incoming = incoming_; | | n->my_incoming = incoming_; | |
| n->stuff_last = stuff_last_; | | n->my_stuff_last = stuff_last_; | |
| return n; | | return n; | |
| } | | } | |
| } | | } | |
| /*override*/ task* execute() { | | /*override*/ task* execute() { | |
|
| if( body ) { | | if( my_body ) { | |
| if( incoming ) | | if( my_incoming ) | |
| left_sum->body.reverse_join( incoming->body ); | | my_left_sum->my_body.reverse_join( my_incoming->my_body | |
| | | ); | |
| recycle_as_continuation(); | | recycle_as_continuation(); | |
| sum_node& c = *this; | | sum_node& c = *this; | |
|
| task* b = c.create_child(Range(range,split()),*left_sum,rig | | task* b = c.create_child(Range(my_range,split()),*my_left_s | |
| ht,left_sum,stuff_last); | | um,my_right,my_left_sum,my_stuff_last); | |
| task* a = left_is_final ? NULL : c.create_child(range,*body | | task* a = my_left_is_final ? NULL : c.create_child(my_range | |
| ,left,incoming,NULL); | | ,*my_body,my_left,my_incoming,NULL); | |
| set_ref_count( (a!=NULL)+(b!=NULL) ); | | set_ref_count( (a!=NULL)+(b!=NULL) ); | |
|
| body = NULL; | | my_body = NULL; | |
| if( a ) spawn(*b); | | if( a ) spawn(*b); | |
| else a = b; | | else a = b; | |
| return a; | | return a; | |
| } else { | | } else { | |
| return NULL; | | return NULL; | |
| } | | } | |
| } | | } | |
| template<typename Range_,typename Body_,typename Partitioner_> | | template<typename Range_,typename Body_,typename Partitioner_> | |
| friend class start_scan; | | friend class start_scan; | |
| | | | |
| template<typename Range_,typename Body_> | | template<typename Range_,typename Body_> | |
| friend class finish_scan; | | friend class finish_scan; | |
| }; | | }; | |
| | | | |
| //! Combine partial results | | //! Combine partial results | |
| /** @ingroup algorithms */ | | /** @ingroup algorithms */ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| class finish_scan: public task { | | class finish_scan: public task { | |
| typedef sum_node<Range,Body> sum_node_type; | | typedef sum_node<Range,Body> sum_node_type; | |
| typedef final_sum<Range,Body> final_sum_type; | | typedef final_sum<Range,Body> final_sum_type; | |
|
| final_sum_type** const sum; | | final_sum_type** const my_sum; | |
| sum_node_type*& return_slot; | | sum_node_type*& my_return_slot; | |
| public: | | public: | |
|
| final_sum_type* right_zombie; | | final_sum_type* my_right_zombie; | |
| sum_node_type& result; | | sum_node_type& my_result; | |
| | | | |
| /*override*/ task* execute() { | | /*override*/ task* execute() { | |
|
| __TBB_ASSERT( result.ref_count()==(result.left!=NULL)+(result.r | | __TBB_ASSERT( my_result.ref_count()==(my_result.my_left!=NULL)+ | |
| ight!=NULL), NULL ); | | (my_result.my_right!=NULL), NULL ); | |
| if( result.left ) | | if( my_result.my_left ) | |
| result.left_is_final = false; | | my_result.my_left_is_final = false; | |
| if( right_zombie && sum ) | | if( my_right_zombie && my_sum ) | |
| ((*sum)->body).reverse_join(result.left_sum->body); | | ((*my_sum)->my_body).reverse_join(my_result.my_left_sum->my | |
| __TBB_ASSERT( !return_slot, NULL ); | | _body); | |
| if( right_zombie || result.right ) { | | __TBB_ASSERT( !my_return_slot, NULL ); | |
| return_slot = &result; | | if( my_right_zombie || my_result.my_right ) { | |
| | | my_return_slot = &my_result; | |
| } else { | | } else { | |
|
| destroy( result ); | | destroy( my_result ); | |
| | | } | |
| | | if( my_right_zombie && !my_sum && !my_result.my_right ) { | |
| | | destroy(*my_right_zombie); | |
| | | my_right_zombie = NULL; | |
| } | | } | |
|
| if( right_zombie && !sum && !result.right ) destroy(*right_zomb
ie); | | | |
| return NULL; | | return NULL; | |
| } | | } | |
| | | | |
| finish_scan( sum_node_type*& return_slot_, final_sum_type** sum_, s
um_node_type& result_ ) : | | finish_scan( sum_node_type*& return_slot_, final_sum_type** sum_, s
um_node_type& result_ ) : | |
|
| sum(sum_), | | my_sum(sum_), | |
| return_slot(return_slot_), | | my_return_slot(return_slot_), | |
| right_zombie(NULL), | | my_right_zombie(NULL), | |
| result(result_) | | my_result(result_) | |
| { | | { | |
|
| __TBB_ASSERT( !return_slot, NULL ); | | __TBB_ASSERT( !my_return_slot, NULL ); | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! Initial task to split the work | | //! Initial task to split the work | |
| /** @ingroup algorithms */ | | /** @ingroup algorithms */ | |
| template<typename Range, typename Body, typename Partitioner=simple_par
titioner> | | template<typename Range, typename Body, typename Partitioner=simple_par
titioner> | |
| class start_scan: public task { | | class start_scan: public task { | |
| typedef sum_node<Range,Body> sum_node_type; | | typedef sum_node<Range,Body> sum_node_type; | |
| typedef final_sum<Range,Body> final_sum_type; | | typedef final_sum<Range,Body> final_sum_type; | |
|
| final_sum_type* body; | | final_sum_type* my_body; | |
| /** Non-null if caller is requesting total. */ | | /** Non-null if caller is requesting total. */ | |
|
| final_sum_type** sum; | | final_sum_type** my_sum; | |
| sum_node_type** return_slot; | | sum_node_type** my_return_slot; | |
| /** Null if computing root. */ | | /** Null if computing root. */ | |
|
| sum_node_type* parent_sum; | | sum_node_type* my_parent_sum; | |
| bool is_final; | | bool my_is_final; | |
| bool is_right_child; | | bool my_is_right_child; | |
| Range range; | | Range my_range; | |
| typename Partitioner::partition_type partition; | | typename Partitioner::partition_type my_partition; | |
| /*override*/ task* execute(); | | /*override*/ task* execute(); | |
| public: | | public: | |
| start_scan( sum_node_type*& return_slot_, start_scan& parent_, sum_
node_type* parent_sum_ ) : | | start_scan( sum_node_type*& return_slot_, start_scan& parent_, sum_
node_type* parent_sum_ ) : | |
|
| body(parent_.body), | | my_body(parent_.my_body), | |
| sum(parent_.sum), | | my_sum(parent_.my_sum), | |
| return_slot(&return_slot_), | | my_return_slot(&return_slot_), | |
| parent_sum(parent_sum_), | | my_parent_sum(parent_sum_), | |
| is_final(parent_.is_final), | | my_is_final(parent_.my_is_final), | |
| is_right_child(false), | | my_is_right_child(false), | |
| range(parent_.range,split()), | | my_range(parent_.my_range,split()), | |
| partition(parent_.partition,split()) | | my_partition(parent_.my_partition,split()) | |
| { | | { | |
|
| __TBB_ASSERT( !*return_slot, NULL ); | | __TBB_ASSERT( !*my_return_slot, NULL ); | |
| } | | } | |
| | | | |
| start_scan( sum_node_type*& return_slot_, const Range& range_, fina
l_sum_type& body_, const Partitioner& partitioner_) : | | start_scan( sum_node_type*& return_slot_, const Range& range_, fina
l_sum_type& body_, const Partitioner& partitioner_) : | |
|
| body(&body_), | | my_body(&body_), | |
| sum(NULL), | | my_sum(NULL), | |
| return_slot(&return_slot_), | | my_return_slot(&return_slot_), | |
| parent_sum(NULL), | | my_parent_sum(NULL), | |
| is_final(true), | | my_is_final(true), | |
| is_right_child(false), | | my_is_right_child(false), | |
| range(range_), | | my_range(range_), | |
| partition(partitioner_) | | my_partition(partitioner_) | |
| { | | { | |
|
| __TBB_ASSERT( !*return_slot, NULL ); | | __TBB_ASSERT( !*my_return_slot, NULL ); | |
| } | | } | |
| | | | |
| static void run( const Range& range_, Body& body_, const Partitione
r& partitioner_ ) { | | static void run( const Range& range_, Body& body_, const Partitione
r& partitioner_ ) { | |
| if( !range_.empty() ) { | | if( !range_.empty() ) { | |
| typedef internal::start_scan<Range,Body,Partitioner> start_
pass1_type; | | typedef internal::start_scan<Range,Body,Partitioner> start_
pass1_type; | |
| internal::sum_node<Range,Body>* root = NULL; | | internal::sum_node<Range,Body>* root = NULL; | |
| typedef internal::final_sum<Range,Body> final_sum_type; | | typedef internal::final_sum<Range,Body> final_sum_type; | |
| final_sum_type* temp_body = new(task::allocate_root()) fina
l_sum_type( body_ ); | | final_sum_type* temp_body = new(task::allocate_root()) fina
l_sum_type( body_ ); | |
| start_pass1_type& pass1 = *new(task::allocate_root()) start
_pass1_type( | | start_pass1_type& pass1 = *new(task::allocate_root()) start
_pass1_type( | |
|
| /*return_slot=*/root, | | /*my_return_slot=*/root, | |
| range_, | | range_, | |
| *temp_body, | | *temp_body, | |
| partitioner_ ); | | partitioner_ ); | |
| task::spawn_root_and_wait( pass1 ); | | task::spawn_root_and_wait( pass1 ); | |
| if( root ) { | | if( root ) { | |
|
| root->body = temp_body; | | root->my_body = temp_body; | |
| root->incoming = NULL; | | root->my_incoming = NULL; | |
| root->stuff_last = &body_; | | root->my_stuff_last = &body_; | |
| task::spawn_root_and_wait( *root ); | | task::spawn_root_and_wait( *root ); | |
| } else { | | } else { | |
|
| body_.assign(temp_body->body); | | body_.assign(temp_body->my_body); | |
| temp_body->finish_construction( range_, NULL ); | | temp_body->finish_construction( range_, NULL ); | |
| temp_body->destroy(*temp_body); | | temp_body->destroy(*temp_body); | |
| } | | } | |
| } | | } | |
| } | | } | |
| }; | | }; | |
| | | | |
| template<typename Range, typename Body, typename Partitioner> | | template<typename Range, typename Body, typename Partitioner> | |
| task* start_scan<Range,Body,Partitioner>::execute() { | | task* start_scan<Range,Body,Partitioner>::execute() { | |
| typedef internal::finish_scan<Range,Body> finish_pass1_type; | | typedef internal::finish_scan<Range,Body> finish_pass1_type; | |
|
| finish_pass1_type* p = parent_sum ? static_cast<finish_pass1_type*>
( parent() ) : NULL; | | finish_pass1_type* p = my_parent_sum ? static_cast<finish_pass1_typ
e*>( parent() ) : NULL; | |
| // Inspecting p->result.left_sum would ordinarily be a race conditi
on. | | // Inspecting p->result.left_sum would ordinarily be a race conditi
on. | |
| // But we inspect it only if we are not a stolen task, in which cas
e we | | // But we inspect it only if we are not a stolen task, in which cas
e we | |
| // know that task assigning to p->result.left_sum has completed. | | // know that task assigning to p->result.left_sum has completed. | |
|
| bool treat_as_stolen = is_right_child && (is_stolen_task() || body!
=p->result.left_sum); | | bool treat_as_stolen = my_is_right_child && (is_stolen_task() || my
_body!=p->my_result.my_left_sum); | |
| if( treat_as_stolen ) { | | if( treat_as_stolen ) { | |
| // Invocation is for right child that has been really stolen or
needs to be virtually stolen | | // Invocation is for right child that has been really stolen or
needs to be virtually stolen | |
|
| p->right_zombie = body = new( allocate_root() ) final_sum_type( | | p->my_right_zombie = my_body = new( allocate_root() ) final_sum | |
| body->body); | | _type(my_body->my_body); | |
| is_final = false; | | my_is_final = false; | |
| } | | } | |
| task* next_task = NULL; | | task* next_task = NULL; | |
|
| if( (is_right_child && !treat_as_stolen) || !range.is_divisible() | | | if( (my_is_right_child && !treat_as_stolen) || !my_range.is_divisib | |
| | partition.should_execute_range(*this) ) { | | le() || my_partition.should_execute_range(*this) ) { | |
| if( is_final ) | | if( my_is_final ) | |
| (body->body)( range, final_scan_tag() ); | | (my_body->my_body)( my_range, final_scan_tag() ); | |
| else if( sum ) | | else if( my_sum ) | |
| (body->body)( range, pre_scan_tag() ); | | (my_body->my_body)( my_range, pre_scan_tag() ); | |
| if( sum ) | | if( my_sum ) | |
| *sum = body; | | *my_sum = my_body; | |
| __TBB_ASSERT( !*return_slot, NULL ); | | __TBB_ASSERT( !*my_return_slot, NULL ); | |
| } else { | | } else { | |
| sum_node_type* result; | | sum_node_type* result; | |
|
| if( parent_sum ) | | if( my_parent_sum ) | |
| result = new(allocate_additional_child_of(*parent_sum)) sum | | result = new(allocate_additional_child_of(*my_parent_sum)) | |
| _node_type(range,/*left_is_final=*/is_final); | | sum_node_type(my_range,/*my_left_is_final=*/my_is_final); | |
| else | | else | |
|
| result = new(task::allocate_root()) sum_node_type(range,/*l | | result = new(task::allocate_root()) sum_node_type(my_range, | |
| eft_is_final=*/is_final); | | /*my_left_is_final=*/my_is_final); | |
| finish_pass1_type& c = *new( allocate_continuation()) finish_pa | | finish_pass1_type& c = *new( allocate_continuation()) finish_pa | |
| ss1_type(*return_slot,sum,*result); | | ss1_type(*my_return_slot,my_sum,*result); | |
| // Split off right child | | // Split off right child | |
|
| start_scan& b = *new( c.allocate_child() ) start_scan( /*return | | start_scan& b = *new( c.allocate_child() ) start_scan( /*my_ret | |
| _slot=*/result->right, *this, result ); | | urn_slot=*/result->my_right, *this, result ); | |
| b.is_right_child = true; | | b.my_is_right_child = true; | |
| // Left child is recycling of *this. Must recycle this before
spawning b, | | // Left child is recycling of *this. Must recycle this before
spawning b, | |
| // otherwise b might complete and decrement c.ref_count() to ze
ro, which | | // otherwise b might complete and decrement c.ref_count() to ze
ro, which | |
| // would cause c.execute() to run prematurely. | | // would cause c.execute() to run prematurely. | |
| recycle_as_child_of(c); | | recycle_as_child_of(c); | |
| c.set_ref_count(2); | | c.set_ref_count(2); | |
| c.spawn(b); | | c.spawn(b); | |
|
| sum = &result->left_sum; | | my_sum = &result->my_left_sum; | |
| return_slot = &result->left; | | my_return_slot = &result->my_left; | |
| is_right_child = false; | | my_is_right_child = false; | |
| next_task = this; | | next_task = this; | |
|
| parent_sum = result; | | my_parent_sum = result; | |
| __TBB_ASSERT( !*return_slot, NULL ); | | __TBB_ASSERT( !*my_return_slot, NULL ); | |
| } | | } | |
| return next_task; | | return next_task; | |
| } | | } | |
| } // namespace internal | | } // namespace internal | |
| //! @endcond | | //! @endcond | |
| | | | |
| // Requirements on Range concept are documented in blocked_range.h | | // Requirements on Range concept are documented in blocked_range.h | |
| | | | |
| /** \page parallel_scan_body_req Requirements on parallel_scan body | | /** \page parallel_scan_body_req Requirements on parallel_scan body | |
| Class \c Body implementing the concept of parallel_scan body must defin
e: | | Class \c Body implementing the concept of parallel_scan body must defin
e: | |
| | | | |
End of changes. 43 change blocks. |
| 118 lines changed or deleted | | 123 lines changed or added | |
|
| task_scheduler_init.h | | task_scheduler_init.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 67 | | skipping to change at line 67 | |
| created, the scheduler will be initialized automatically with default s
ettings, | | created, the scheduler will be initialized automatically with default s
ettings, | |
| and will persist until this thread exits. Default concurrency level is
defined | | and will persist until this thread exits. Default concurrency level is
defined | |
| as described in task_scheduler_init::initialize(). | | as described in task_scheduler_init::initialize(). | |
| @ingroup task_scheduling */ | | @ingroup task_scheduling */ | |
| class task_scheduler_init: internal::no_copy { | | class task_scheduler_init: internal::no_copy { | |
| enum ExceptionPropagationMode { | | enum ExceptionPropagationMode { | |
| propagation_mode_exact = 1u, | | propagation_mode_exact = 1u, | |
| propagation_mode_captured = 2u, | | propagation_mode_captured = 2u, | |
| propagation_mode_mask = propagation_mode_exact | propagation_mode_c
aptured | | propagation_mode_mask = propagation_mode_exact | propagation_mode_c
aptured | |
| }; | | }; | |
|
| | | #if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE | |
| | | enum { | |
| | | wait_workers_in_terminate_flag = 128u | |
| | | }; | |
| | | #endif | |
| | | | |
| /** NULL if not currently initialized. */ | | /** NULL if not currently initialized. */ | |
| internal::scheduler* my_scheduler; | | internal::scheduler* my_scheduler; | |
| public: | | public: | |
| | | | |
| //! Typedef for number of threads that is automatic. | | //! Typedef for number of threads that is automatic. | |
| static const int automatic = -1; | | static const int automatic = -1; | |
| | | | |
| //! Argument to initialize() or constructor that causes initialization
to be deferred. | | //! Argument to initialize() or constructor that causes initialization
to be deferred. | |
| static const int deferred = -2; | | static const int deferred = -2; | |
| | | | |
| skipping to change at line 100 | | skipping to change at line 105 | |
| void __TBB_EXPORTED_METHOD initialize( int number_of_threads=automatic
); | | void __TBB_EXPORTED_METHOD initialize( int number_of_threads=automatic
); | |
| | | | |
| //! The overloaded method with stack size parameter | | //! The overloaded method with stack size parameter | |
| /** Overloading is necessary to preserve ABI compatibility */ | | /** Overloading is necessary to preserve ABI compatibility */ | |
| void __TBB_EXPORTED_METHOD initialize( int number_of_threads, stack_siz
e_type thread_stack_size ); | | void __TBB_EXPORTED_METHOD initialize( int number_of_threads, stack_siz
e_type thread_stack_size ); | |
| | | | |
| //! Inverse of method initialize. | | //! Inverse of method initialize. | |
| void __TBB_EXPORTED_METHOD terminate(); | | void __TBB_EXPORTED_METHOD terminate(); | |
| | | | |
| //! Shorthand for default constructor followed by call to initialize(nu
mber_of_threads). | | //! Shorthand for default constructor followed by call to initialize(nu
mber_of_threads). | |
|
| task_scheduler_init( int number_of_threads=automatic, stack_size_type t | | #if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE | |
| hread_stack_size=0 ) : my_scheduler(NULL) { | | task_scheduler_init( int number_of_threads=automatic, stack_size_type t | |
| | | hread_stack_size=0, bool wait_workers_in_terminate = false ) | |
| | | #else | |
| | | task_scheduler_init( int number_of_threads=automatic, stack_size_type t | |
| | | hread_stack_size=0 ) | |
| | | #endif | |
| | | : my_scheduler(NULL) { | |
| // Two lowest order bits of the stack size argument may be taken to
communicate | | // Two lowest order bits of the stack size argument may be taken to
communicate | |
| // default exception propagation mode of the client to be used when
the | | // default exception propagation mode of the client to be used when
the | |
| // client manually creates tasks in the master thread and does not
use | | // client manually creates tasks in the master thread and does not
use | |
| // explicit task group context object. This is necessary because ne
wer | | // explicit task group context object. This is necessary because ne
wer | |
| // TBB binaries with exact propagation enabled by default may be us
ed | | // TBB binaries with exact propagation enabled by default may be us
ed | |
| // by older clients that expect tbb::captured_exception wrapper. | | // by older clients that expect tbb::captured_exception wrapper. | |
| // All zeros mean old client - no preference. | | // All zeros mean old client - no preference. | |
| __TBB_ASSERT( !(thread_stack_size & propagation_mode_mask), "Reques
ted stack size is not aligned" ); | | __TBB_ASSERT( !(thread_stack_size & propagation_mode_mask), "Reques
ted stack size is not aligned" ); | |
| #if TBB_USE_EXCEPTIONS | | #if TBB_USE_EXCEPTIONS | |
| thread_stack_size |= TBB_USE_CAPTURED_EXCEPTION ? propagation_mode_
captured : propagation_mode_exact; | | thread_stack_size |= TBB_USE_CAPTURED_EXCEPTION ? propagation_mode_
captured : propagation_mode_exact; | |
| #endif /* TBB_USE_EXCEPTIONS */ | | #endif /* TBB_USE_EXCEPTIONS */ | |
|
| | | #if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE | |
| | | if (wait_workers_in_terminate) | |
| | | my_scheduler = (internal::scheduler*)wait_workers_in_terminate_ | |
| | | flag; | |
| | | #endif | |
| initialize( number_of_threads, thread_stack_size ); | | initialize( number_of_threads, thread_stack_size ); | |
| } | | } | |
| | | | |
| //! Destroy scheduler for this thread if thread has no other live task_
scheduler_inits. | | //! Destroy scheduler for this thread if thread has no other live task_
scheduler_inits. | |
| ~task_scheduler_init() { | | ~task_scheduler_init() { | |
| if( my_scheduler ) | | if( my_scheduler ) | |
| terminate(); | | terminate(); | |
| internal::poison_pointer( my_scheduler ); | | internal::poison_pointer( my_scheduler ); | |
| } | | } | |
| //! Returns the number of threads TBB scheduler would create if initial
ized by default. | | //! Returns the number of threads TBB scheduler would create if initial
ized by default. | |
| | | | |
End of changes. 4 change blocks. |
| 3 lines changed or deleted | | 19 lines changed or added | |
|
| tbb_config.h | | tbb_config.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 49 | | skipping to change at line 49 | |
| | | | |
| #define __TBB_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC
_PATCHLEVEL__) | | #define __TBB_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC
_PATCHLEVEL__) | |
| | | | |
| #if __clang__ | | #if __clang__ | |
| #define __TBB_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__
* 100 + __clang_patchlevel__) | | #define __TBB_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__
* 100 + __clang_patchlevel__) | |
| #endif | | #endif | |
| | | | |
| /** Presence of compiler features **/ | | /** Presence of compiler features **/ | |
| | | | |
| #if __INTEL_COMPILER == 9999 && __INTEL_COMPILER_BUILD_DATE == 20110811 | | #if __INTEL_COMPILER == 9999 && __INTEL_COMPILER_BUILD_DATE == 20110811 | |
|
| /* Intel Composer XE 2011 Update 6 incorrectly sets __INTEL_COMPILER. Fix i
t. */ | | /* Intel(R) Composer XE 2011 Update 6 incorrectly sets __INTEL_COMPILER. Fi
x it. */ | |
| #undef __INTEL_COMPILER | | #undef __INTEL_COMPILER | |
| #define __INTEL_COMPILER 1210 | | #define __INTEL_COMPILER 1210 | |
| #endif | | #endif | |
| | | | |
| #if (__TBB_GCC_VERSION >= 40400) && !defined(__INTEL_COMPILER) | | #if (__TBB_GCC_VERSION >= 40400) && !defined(__INTEL_COMPILER) | |
| /** warning suppression pragmas available in GCC since 4.4 **/ | | /** warning suppression pragmas available in GCC since 4.4 **/ | |
| #define __TBB_GCC_WARNING_SUPPRESSION_PRESENT 1 | | #define __TBB_GCC_WARNING_SUPPRESSION_PRESENT 1 | |
| #endif | | #endif | |
| | | | |
| /* Select particular features of C++11 based on compiler version. | | /* Select particular features of C++11 based on compiler version. | |
| | | | |
| skipping to change at line 74 | | skipping to change at line 74 | |
| compilers they mimic (GCC, MSVC). | | compilers they mimic (GCC, MSVC). | |
| | | | |
| TODO: The following conditions should be extended when new compilers/run
times | | TODO: The following conditions should be extended when new compilers/run
times | |
| support added. | | support added. | |
| */ | | */ | |
| | | | |
| #if __INTEL_COMPILER | | #if __INTEL_COMPILER | |
| /** On Windows environment when using Intel C++ compiler with Visual St
udio 2010*, | | /** On Windows environment when using Intel C++ compiler with Visual St
udio 2010*, | |
| the C++0x features supported by Visual C++ 2010 are enabled by defa
ult | | the C++0x features supported by Visual C++ 2010 are enabled by defa
ult | |
| TODO: find a way to get know if c++0x mode is specified in command
line on windows **/ | | TODO: find a way to get know if c++0x mode is specified in command
line on windows **/ | |
|
| #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __GXX_EXPERIMENTAL_CXX0X | | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __GXX_EXPERIMENTAL_CX | |
| __ && __VARIADIC_TEMPLATES | | X0X__ && __VARIADIC_TEMPLATES | |
| #define __TBB_CPP11_RVALUE_REF_PRESENT (__GXX_EXPERIMENTAL_CXX0 | | #define __TBB_CPP11_RVALUE_REF_PRESENT (__GXX_EXPERIMENTAL_C | |
| X__ || _MSC_VER >= 1600) && (__INTEL_COMPILER >= 1200) | | XX0X__ || _MSC_VER >= 1600) && (__INTEL_COMPILER >= 1200) | |
| #if _MSC_VER >= 1600 | | #if _MSC_VER >= 1600 | |
|
| #define __TBB_EXCEPTION_PTR_PRESENT __INTEL_COMPILER > 1300 | | #define __TBB_EXCEPTION_PTR_PRESENT __INTEL_COMPILER > 13 | |
| \ | | 00 \ | |
| /*ICC 12.1 Upd 10 and 13 | | /*ICC 12.1 Upd 10 and | |
| beta Upd 2 fixed exception_ptr linking issue*/ \ | | 13 beta Upd 2 fixed exception_ptr linking issue*/ \ | |
| || (__INTEL_COMPILER == | | || (__INTEL_COMPILER | |
| 1300 && __INTEL_COMPILER_BUILD_DATE >= 20120530) \ | | == 1300 && __INTEL_COMPILER_BUILD_DATE >= 20120530) \ | |
| || (__INTEL_COMPILER == | | || (__INTEL_COMPILER | |
| 1210 && __INTEL_COMPILER_BUILD_DATE >= 20120410) | | == 1210 && __INTEL_COMPILER_BUILD_DATE >= 20120410) | |
| /** libstc++ that comes with GCC 4.6 use C++ features not yet supported
by current ICC (12.1)**/ | | /** libstc++ that comes with GCC 4.6 use C++ features not yet supported
by current ICC (12.1)**/ | |
| #elif (__TBB_GCC_VERSION >= 40404) && (__TBB_GCC_VERSION < 40600) | | #elif (__TBB_GCC_VERSION >= 40404) && (__TBB_GCC_VERSION < 40600) | |
| #define __TBB_EXCEPTION_PTR_PRESENT __GXX_EXPERIMENTAL_CXX0X
__ && __INTEL_COMPILER >= 1200 | | #define __TBB_EXCEPTION_PTR_PRESENT __GXX_EXPERIMENTAL_CXX0X
__ && __INTEL_COMPILER >= 1200 | |
| #else | | #else | |
|
| #define __TBB_EXCEPTION_PTR_PRESENT 0 | | #define __TBB_EXCEPTION_PTR_PRESENT 0 | |
| #endif | | #endif | |
|
| #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700 || (__ | | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700 || | |
| GXX_EXPERIMENTAL_CXX0X__ && __TBB_GCC_VERSION >= 40600)) | | (__GXX_EXPERIMENTAL_CXX0X__ && __TBB_GCC_VERSION >= 40600)) | |
| #define __TBB_STATIC_ASSERT_PRESENT __GXX_EXPERIMENTAL_CXX0X | | #define __TBB_STATIC_ASSERT_PRESENT __GXX_EXPERIMENTAL_CX | |
| __ || (_MSC_VER >= 1600) | | X0X__ || (_MSC_VER >= 1600) | |
| #define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) || (( | | #define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) || | |
| __GXX_EXPERIMENTAL_CXX0X__) && (__TBB_GCC_VERSION >= 40300)) | | ((__GXX_EXPERIMENTAL_CXX0X__) && (__TBB_GCC_VERSION >= 40300)) | |
| /** TODO: re-check for compiler version greater than 12.1 if it support
s initializer lists**/ | | /** TODO: re-check for compiler version greater than 12.1 if it support
s initializer lists**/ | |
|
| #define __TBB_INITIALIZER_LISTS_PRESENT 0 | | #define __TBB_INITIALIZER_LISTS_PRESENT 0 | |
| | | #define __TBB_CONSTEXPR_PRESENT 0 | |
| | | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT 0 | |
| #elif __clang__ | | #elif __clang__ | |
| //TODO: these options need to be rechecked | | //TODO: these options need to be rechecked | |
|
| #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT (__GXX_EXPERIMENTAL_CXX0 | | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT (__GXX_EXPERIMENTAL_C | |
| X__ && __TBB_CLANG_VERSION >= 20900) | | XX0X__ && __TBB_CLANG_VERSION >= 20900) | |
| #define __TBB_CPP11_RVALUE_REF_PRESENT (__GXX_EXPERIMENTAL_CXX0 | | #define __TBB_CPP11_RVALUE_REF_PRESENT (__GXX_EXPERIMENTAL_C | |
| X__ && __TBB_CLANG_VERSION >= 20900) | | XX0X__ && __TBB_CLANG_VERSION >= 20900) | |
| #define __TBB_EXCEPTION_PTR_PRESENT __GXX_EXPERIMENTAL_CXX0X | | #define __TBB_EXCEPTION_PTR_PRESENT __GXX_EXPERIMENTAL_CX | |
| __ | | X0X__ | |
| #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 | | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_C | |
| X__ && __TBB_CLANG_VERSION > 30100)// TODO: check version | | XX0X__ && __TBB_CLANG_VERSION > 30100)// TODO: check version | |
| #define __TBB_STATIC_ASSERT_PRESENT (__GXX_EXPERIMENTAL_CXX0 | | #define __TBB_STATIC_ASSERT_PRESENT (__GXX_EXPERIMENTAL_C | |
| X__ && __TBB_CLANG_VERSION >= 20900) | | XX0X__ && __TBB_CLANG_VERSION >= 20900) | |
| #define __TBB_CPP11_TUPLE_PRESENT ((__GXX_EXPERIMENTAL_CXX | | #define __TBB_CPP11_TUPLE_PRESENT ((__GXX_EXPERIMENTAL_ | |
| 0X__) && (__TBB_GCC_VERSION >= 40300)) | | CXX0X__) && (__TBB_GCC_VERSION >= 40300)) | |
| #define __TBB_INITIALIZER_LISTS_PRESENT 0 | | #define __TBB_INITIALIZER_LISTS_PRESENT 0 | |
| | | #define __TBB_CONSTEXPR_PRESENT (__GXX_EXPERIMENTAL_C | |
| | | XX0X__ && __TBB_CLANG_VERSION > 30100) | |
| | | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT 0 | |
| #elif __GNUC__ | | #elif __GNUC__ | |
|
| #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __GXX_EXPERIMENTAL_CXX0X | | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __GXX_EXPERIMENTAL_CX | |
| __ | | X0X__ | |
| #define __TBB_CPP11_RVALUE_REF_PRESENT __GXX_EXPERIMENTAL_CXX0X | | #define __TBB_CPP11_RVALUE_REF_PRESENT __GXX_EXPERIMENTAL_CX | |
| __ | | X0X__ | |
| /** __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 here is a substitution for _GLIB
CXX_ATOMIC_BUILTINS_4, which is a prerequisite | | /** __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 here is a substitution for _GLIB
CXX_ATOMIC_BUILTINS_4, which is a prerequisite | |
| for exception_ptr but cannot be used in this file because it is def
ined in a header, not by the compiler. | | for exception_ptr but cannot be used in this file because it is def
ined in a header, not by the compiler. | |
| If the compiler has no atomic intrinsics, the C++ library should no
t expect those as well. **/ | | If the compiler has no atomic intrinsics, the C++ library should no
t expect those as well. **/ | |
|
| #define __TBB_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 | | #define __TBB_EXCEPTION_PTR_PRESENT ((__GXX_EXPERIMENTAL_ | |
| X__ && (__TBB_GCC_VERSION >= 40404) && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | | CXX0X__) && (__TBB_GCC_VERSION >= 40404) && __GCC_HAVE_SYNC_COMPARE_AND_SWA | |
| #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 | | P_4) | |
| X__ && __TBB_GCC_VERSION >= 40600) | | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT ((__GXX_EXPERIMENTAL_ | |
| #define __TBB_STATIC_ASSERT_PRESENT ((__TBB_GCC_VERSION >= 4 | | CXX0X__) && (__TBB_GCC_VERSION >= 40600)) | |
| 0300) && (__GXX_EXPERIMENTAL_CXX0X__)) | | #define __TBB_STATIC_ASSERT_PRESENT ((__GXX_EXPERIMENTAL_ | |
| #define __TBB_CPP11_TUPLE_PRESENT ((__GXX_EXPERIMENTAL_CXX | | CXX0X__) && (__TBB_GCC_VERSION >= 40300)) | |
| 0X__) && (__TBB_GCC_VERSION >= 40300)) | | #define __TBB_CPP11_TUPLE_PRESENT ((__GXX_EXPERIMENTAL_ | |
| #define __TBB_INITIALIZER_LISTS_PRESENT ((__GXX_EXPERIMENTAL_CXX | | CXX0X__) && (__TBB_GCC_VERSION >= 40300)) | |
| 0X__) && (__TBB_GCC_VERSION >= 40400)) | | #define __TBB_INITIALIZER_LISTS_PRESENT ((__GXX_EXPERIMENTAL_ | |
| | | CXX0X__) && (__TBB_GCC_VERSION >= 40400)) | |
| | | /** gcc seems have to support constexpr from 4.4 but tests in (test_ato | |
| | | mic) seeming reasonable fail to compile prior 4.6**/ | |
| | | #define __TBB_CONSTEXPR_PRESENT ((__GXX_EXPERIMENTAL_ | |
| | | CXX0X__) && (__TBB_GCC_VERSION >= 40400)) | |
| | | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT ((__GXX_EXPERIMENTAL_ | |
| | | CXX0X__) && (__TBB_GCC_VERSION >= 40400)) | |
| #elif _MSC_VER | | #elif _MSC_VER | |
|
| #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | |
| #define __TBB_CPP11_RVALUE_REF_PRESENT 0 | | #define __TBB_CPP11_RVALUE_REF_PRESENT 0 | |
| #define __TBB_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1600) | | #define __TBB_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1600) | |
| #define __TBB_STATIC_ASSERT_PRESENT (_MSC_VER >= 1600) | | #define __TBB_STATIC_ASSERT_PRESENT (_MSC_VER >= 1600) | |
| #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700) | | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700) | |
| #define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) | | #define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) | |
| #define __TBB_INITIALIZER_LISTS_PRESENT 0 | | #define __TBB_INITIALIZER_LISTS_PRESENT 0 | |
| #else | | #define __TBB_CONSTEXPR_PRESENT 0 | |
| #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT 0 | |
| #define __TBB_CPP11_RVALUE_REF_PRESENT 0 | | #else | |
| #define __TBB_EXCEPTION_PTR_PRESENT 0 | | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | |
| #define __TBB_STATIC_ASSERT_PRESENT 0 | | #define __TBB_CPP11_RVALUE_REF_PRESENT 0 | |
| #define __TBB_MAKE_EXCEPTION_PTR_PRESENT 0 | | #define __TBB_EXCEPTION_PTR_PRESENT 0 | |
| #define __TBB_CPP11_TUPLE_PRESENT 0 | | #define __TBB_STATIC_ASSERT_PRESENT 0 | |
| #define __TBB_INITIALIZER_LISTS_PRESENT 0 | | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT 0 | |
| | | #define __TBB_CPP11_TUPLE_PRESENT 0 | |
| | | #define __TBB_INITIALIZER_LISTS_PRESENT 0 | |
| | | #define __TBB_CONSTEXPR_PRESENT 0 | |
| | | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT 0 | |
| #endif | | #endif | |
| | | | |
| //TODO: not clear how exactly this macro affects exception_ptr - investigat
e | | //TODO: not clear how exactly this macro affects exception_ptr - investigat
e | |
| // On linux ICC fails to find existing std::exception_ptr in libstdc++ with
out this define | | // On linux ICC fails to find existing std::exception_ptr in libstdc++ with
out this define | |
| #if __INTEL_COMPILER && __GNUC__ && __TBB_EXCEPTION_PTR_PRESENT && !defined
(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | | #if __INTEL_COMPILER && __GNUC__ && __TBB_EXCEPTION_PTR_PRESENT && !defined
(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | |
| #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 | | #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 | |
| #endif | | #endif | |
| | | | |
| // Work around a bug in MinGW32 | | // Work around a bug in MinGW32 | |
| #if __MINGW32__ && __TBB_EXCEPTION_PTR_PRESENT && !defined(_GLIBCXX_ATOMIC_
BUILTINS_4) | | #if __MINGW32__ && __TBB_EXCEPTION_PTR_PRESENT && !defined(_GLIBCXX_ATOMIC_
BUILTINS_4) | |
| | | | |
| skipping to change at line 306 | | skipping to change at line 317 | |
| #endif | | #endif | |
| | | | |
| #ifndef __TBB_TASK_PRIORITY | | #ifndef __TBB_TASK_PRIORITY | |
| #define __TBB_TASK_PRIORITY __TBB_TASK_GROUP_CONTEXT | | #define __TBB_TASK_PRIORITY __TBB_TASK_GROUP_CONTEXT | |
| #endif /* __TBB_TASK_PRIORITY */ | | #endif /* __TBB_TASK_PRIORITY */ | |
| | | | |
| #if __TBB_TASK_PRIORITY && !__TBB_TASK_GROUP_CONTEXT | | #if __TBB_TASK_PRIORITY && !__TBB_TASK_GROUP_CONTEXT | |
| #error __TBB_TASK_PRIORITY requires __TBB_TASK_GROUP_CONTEXT to be enab
led | | #error __TBB_TASK_PRIORITY requires __TBB_TASK_GROUP_CONTEXT to be enab
led | |
| #endif | | #endif | |
| | | | |
|
| | | #if TBB_PREVIEW_WAITING_FOR_WORKERS || __TBB_BUILD | |
| | | #define __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE 1 | |
| | | #endif | |
| | | | |
| #if !defined(__TBB_SURVIVE_THREAD_SWITCH) && \ | | #if !defined(__TBB_SURVIVE_THREAD_SWITCH) && \ | |
| (_WIN32 || _WIN64 || __APPLE__ || (__linux__ && !__ANDROID__)) | | (_WIN32 || _WIN64 || __APPLE__ || (__linux__ && !__ANDROID__)) | |
| #define __TBB_SURVIVE_THREAD_SWITCH 1 | | #define __TBB_SURVIVE_THREAD_SWITCH 1 | |
| #endif /* __TBB_SURVIVE_THREAD_SWITCH */ | | #endif /* __TBB_SURVIVE_THREAD_SWITCH */ | |
| | | | |
| #ifndef __TBB_DEFAULT_PARTITIONER | | #ifndef __TBB_DEFAULT_PARTITIONER | |
| #if TBB_DEPRECATED | | #if TBB_DEPRECATED | |
| /** Default partitioner for parallel loop templates in TBB 1.0-2.1 */ | | /** Default partitioner for parallel loop templates in TBB 1.0-2.1 */ | |
| #define __TBB_DEFAULT_PARTITIONER tbb::simple_partitioner | | #define __TBB_DEFAULT_PARTITIONER tbb::simple_partitioner | |
| #else | | #else | |
| | | | |
| skipping to change at line 331 | | skipping to change at line 346 | |
| #ifdef _VARIADIC_MAX | | #ifdef _VARIADIC_MAX | |
| #define __TBB_VARIADIC_MAX _VARIADIC_MAX | | #define __TBB_VARIADIC_MAX _VARIADIC_MAX | |
| #else | | #else | |
| #if _MSC_VER >= 1700 | | #if _MSC_VER >= 1700 | |
| #define __TBB_VARIADIC_MAX 5 /* current VS11 setting, may change. */ | | #define __TBB_VARIADIC_MAX 5 /* current VS11 setting, may change. */ | |
| #else | | #else | |
| #define __TBB_VARIADIC_MAX 10 | | #define __TBB_VARIADIC_MAX 10 | |
| #endif | | #endif | |
| #endif | | #endif | |
| | | | |
|
| | | // Define preprocessor symbols used to determine architecture | |
| | | #if _WIN32||_WIN64 | |
| | | # if defined(_M_X64)||defined(__x86_64__) // the latter for MinGW suppor | |
| | | t | |
| | | # define __TBB_x86_64 1 | |
| | | # elif defined(_M_IA64) | |
| | | # define __TBB_ipf 1 | |
| | | # elif defined(_M_IX86)||defined(__i386__) // the latter for MinGW suppor | |
| | | t | |
| | | # define __TBB_x86_32 1 | |
| | | # endif | |
| | | #else /* Assume generic Unix */ | |
| | | # if !__linux__ && !__APPLE__ | |
| | | # define __TBB_generic_os 1 | |
| | | # endif | |
| | | # if __x86_64__ | |
| | | # define __TBB_x86_64 1 | |
| | | # elif __ia64__ | |
| | | # define __TBB_ipf 1 | |
| | | # elif __i386__||__i386 // __i386 is for Sun OS | |
| | | # define __TBB_x86_32 1 | |
| | | # else | |
| | | # define __TBB_generic_arch 1 | |
| | | # endif | |
| | | #endif | |
| /** Macros of the form __TBB_XXX_BROKEN denote known issues that are caused
by | | /** Macros of the form __TBB_XXX_BROKEN denote known issues that are caused
by | |
| the bugs in compilers, standard or OS specific libraries. They should b
e | | the bugs in compilers, standard or OS specific libraries. They should b
e | |
| removed as soon as the corresponding bugs are fixed or the buggy OS/com
piler | | removed as soon as the corresponding bugs are fixed or the buggy OS/com
piler | |
| versions go out of the support list. | | versions go out of the support list. | |
| **/ | | **/ | |
| | | | |
| #if __ANDROID__ && __TBB_GCC_VERSION <= 40403 && !__GCC_HAVE_SYNC_COMPARE_A
ND_SWAP_8 | | #if __ANDROID__ && __TBB_GCC_VERSION <= 40403 && !__GCC_HAVE_SYNC_COMPARE_A
ND_SWAP_8 | |
| /** Necessary because on Android 8-byte CAS and F&A are not available f
or some processor architectures, | | /** Necessary because on Android 8-byte CAS and F&A are not available f
or some processor architectures, | |
| but no mandatory warning message appears from GCC 4.4.3. Instead, o
nly a linkage error occurs when | | but no mandatory warning message appears from GCC 4.4.3. Instead, o
nly a linkage error occurs when | |
| these atomic operations are used (such as in unit test test_atomic.
exe). **/ | | these atomic operations are used (such as in unit test test_atomic.
exe). **/ | |
| | | | |
| skipping to change at line 443 | | skipping to change at line 481 | |
| #if !defined(__EXCEPTIONS) && __GNUC__==4 && (__GNUC_MINOR__==4 ||__GNUC_MI
NOR__==5 || (__INTEL_COMPILER==1300 && __TBB_GCC_VERSION>=40600 && __TBB_GC
C_VERSION<=40700)) && defined(__GXX_EXPERIMENTAL_CXX0X__) | | #if !defined(__EXCEPTIONS) && __GNUC__==4 && (__GNUC_MINOR__==4 ||__GNUC_MI
NOR__==5 || (__INTEL_COMPILER==1300 && __TBB_GCC_VERSION>=40600 && __TBB_GC
C_VERSION<=40700)) && defined(__GXX_EXPERIMENTAL_CXX0X__) | |
| /* There is an issue for specific GCC toolchain when C++11 is enabled | | /* There is an issue for specific GCC toolchain when C++11 is enabled | |
| and exceptions are disabled: | | and exceptions are disabled: | |
| exceprion_ptr.h/nested_exception.h are using throw unconditionally. | | exceprion_ptr.h/nested_exception.h are using throw unconditionally. | |
| */ | | */ | |
| #define __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 1 | | #define __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 1 | |
| #else | | #else | |
| #define __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 0 | | #define __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 0 | |
| #endif | | #endif | |
| | | | |
|
| | | #if __TBB_x86_32 && (__linux__ || __APPLE__ || _WIN32 || __sun) && ((defin | |
| | | ed(__INTEL_COMPILER) && (__INTEL_COMPILER <= 1300)) || (__GNUC__==3 && __GN | |
| | | UC_MINOR__==3 ) || defined(__SUNPRO_CC)) | |
| | | // Some compilers for IA-32 fail to provide 8-byte alignment of objects | |
| | | on the stack, | |
| | | // even if the object specifies 8-byte alignment. On such platforms, t | |
| | | he IA-32 implementation | |
| | | // of 64 bit atomics (e.g. atomic<long long>) use different tactics dep | |
| | | ending upon | |
| | | // whether the object is properly aligned or not. | |
| | | #define __TBB_FORCE_64BIT_ALIGNMENT_BROKEN 1 | |
| | | #else | |
| | | #define __TBB_FORCE_64BIT_ALIGNMENT_BROKEN 0 | |
| | | #endif | |
| | | | |
| | | #if (__TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT && (__TBB_GCC_VERSION < 40700 | |
| | | ) && (!defined(__INTEL_COMPILER) && !defined (__clang__))) | |
| | | #define __TBB_ZERO_INIT_WITH_DEFAULTED_CTOR_BROKEN 1 | |
| | | #endif | |
| | | /** End of __TBB_XXX_BROKEN macro section **/ | |
| | | | |
| | | #define __TBB_ATOMIC_CTORS (__TBB_CONSTEXPR_PRESENT && __TBB_DEFAULTED_ | |
| | | AND_DELETED_FUNC_PRESENT && (!__TBB_ZERO_INIT_WITH_DEFAULTED_CTOR_BROKEN)) | |
| | | | |
| #endif /* __TBB_tbb_config_H */ | | #endif /* __TBB_tbb_config_H */ | |
| | | | |
End of changes. 14 change blocks. |
| 64 lines changed or deleted | | 133 lines changed or added | |
|
| tbb_machine.h | | tbb_machine.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 176 | | skipping to change at line 176 | |
| inline static word fetch_store ( volatile void* location, word value ); | | inline static word fetch_store ( volatile void* location, word value ); | |
| }; | | }; | |
| | | | |
| template<> struct atomic_selector<8> { | | template<> struct atomic_selector<8> { | |
| typedef int64_t word; | | typedef int64_t word; | |
| inline static word fetch_store ( volatile void* location, word value ); | | inline static word fetch_store ( volatile void* location, word value ); | |
| }; | | }; | |
| | | | |
| }} // namespaces internal, tbb | | }} // namespaces internal, tbb | |
| | | | |
|
| | | #define __TBB_MACHINE_DEFINE_STORE8_GENERIC_FENCED(M) | |
| | | \ | |
| | | inline void __TBB_machine_generic_store8##M(volatile void *ptr, int64_t | |
| | | value) { \ | |
| | | for(;;) { | |
| | | \ | |
| | | int64_t result = *(int64_t *)ptr; | |
| | | \ | |
| | | if( __TBB_machine_cmpswp8##M(ptr,value,result)==result ) break; | |
| | | \ | |
| | | } | |
| | | \ | |
| | | } | |
| | | \ | |
| | | | |
| | | #define __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(M) | |
| | | \ | |
| | | inline int64_t __TBB_machine_generic_load8##M(const volatile void *ptr) | |
| | | { \ | |
| | | /* Comparand and new value may be anything, they only must be equal | |
| | | , and */ \ | |
| | | /* the value should have a low probability to be actually found in | |
| | | 'location'.*/ \ | |
| | | const int64_t anyvalue = 2305843009213693951LL; | |
| | | \ | |
| | | return __TBB_machine_cmpswp8##M(const_cast<volatile void *>(ptr),an | |
| | | yvalue,anyvalue); \ | |
| | | } | |
| | | \ | |
| | | | |
| #if _WIN32||_WIN64 | | #if _WIN32||_WIN64 | |
| | | | |
| #ifdef _MANAGED | | #ifdef _MANAGED | |
| #pragma managed(push, off) | | #pragma managed(push, off) | |
| #endif | | #endif | |
| | | | |
| #if __MINGW64__ || __MINGW32__ | | #if __MINGW64__ || __MINGW32__ | |
| extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void
); | | extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void
); | |
| #define __TBB_Yield() SwitchToThread() | | #define __TBB_Yield() SwitchToThread() | |
| #if (TBB_USE_GCC_BUILTINS && __TBB_GCC_BUILTIN_ATOMICS_PRESENT) | | #if (TBB_USE_GCC_BUILTINS && __TBB_GCC_BUILTIN_ATOMICS_PRESENT) | |
| | | | |
| skipping to change at line 544 | | skipping to change at line 560 | |
| | | | |
| __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE(1) | | __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE(1) | |
| __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE(2) | | __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE(2) | |
| __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE(4) | | __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE(4) | |
| __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE(8) | | __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE(8) | |
| | | | |
| #undef __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE | | #undef __TBB_MACHINE_DEFINE_ATOMIC_SELECTOR_FETCH_STORE | |
| #endif /* __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE */ | | #endif /* __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE */ | |
| | | | |
| #if __TBB_USE_GENERIC_DWORD_LOAD_STORE | | #if __TBB_USE_GENERIC_DWORD_LOAD_STORE | |
|
| inline void __TBB_machine_store8 (volatile void *ptr, int64_t value) { | | /*TODO: find a more elegant way to handle function names difference*/ | |
| for(;;) { | | #if ! __TBB_USE_FENCED_ATOMICS | |
| int64_t result = *(int64_t *)ptr; | | /* This name forwarding is needed for generic implementation of | |
| if( __TBB_machine_cmpswp8(ptr,value,result)==result ) break; | | * load8/store8 defined below (via macro) to pick the right CAS functio | |
| } | | n*/ | |
| } | | #define __TBB_machine_cmpswp8full_fence __TBB_machine_cmpswp8 | |
| | | #endif | |
| | | __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(full_fence) | |
| | | __TBB_MACHINE_DEFINE_STORE8_GENERIC_FENCED(full_fence) | |
| | | | |
|
| inline int64_t __TBB_machine_load8 (const volatile void *ptr) { | | #if ! __TBB_USE_FENCED_ATOMICS | |
| // Comparand and new value may be anything, they only must be equal, an | | #undef __TBB_machine_cmpswp8full_fence | |
| d | | #endif | |
| // the value should have a low probability to be actually found in 'loc | | | |
| ation'. | | #define __TBB_machine_store8 tbb::internal::__TBB_machine_generic_store8ful | |
| const int64_t anyvalue = 2305843009213693951LL; | | l_fence | |
| return __TBB_machine_cmpswp8(const_cast<volatile void *>(ptr),anyvalue, | | #define __TBB_machine_load8 tbb::internal::__TBB_machine_generic_load8full | |
| anyvalue); | | _fence | |
| } | | | |
| #endif /* __TBB_USE_GENERIC_DWORD_LOAD_STORE */ | | #endif /* __TBB_USE_GENERIC_DWORD_LOAD_STORE */ | |
| | | | |
| #if __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE | | #if __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE | |
| /** Fenced operations use volatile qualifier to prevent compiler from optim
izing | | /** Fenced operations use volatile qualifier to prevent compiler from optim
izing | |
| them out, and on on architectures with weak memory ordering to induce c
ompiler | | them out, and on on architectures with weak memory ordering to induce c
ompiler | |
| to generate code with appropriate acquire/release semantics. | | to generate code with appropriate acquire/release semantics. | |
| On architectures like IA32, Intel64 (and likely and Sparc TSO) volatile
has | | On architectures like IA32, Intel64 (and likely and Sparc TSO) volatile
has | |
| no effect on code gen, and consistency helpers serve as a compiler fenc
e (the | | no effect on code gen, and consistency helpers serve as a compiler fenc
e (the | |
| latter being true for IA64/gcc as well to fix a bug in some gcc version
s). **/ | | latter being true for IA64/gcc as well to fix a bug in some gcc version
s). **/ | |
| template <typename T, size_t S> | | template <typename T, size_t S> | |
| | | | |
End of changes. 4 change blocks. |
| 16 lines changed or deleted | | 48 lines changed or added | |
|
| tbb_stddef.h | | tbb_stddef.h | |
| /* | | /* | |
|
| Copyright 2005-2012 Intel Corporation. All Rights Reserved. | | Copyright 2005-2013 Intel Corporation. All Rights Reserved. | |
| | | | |
| This file is part of Threading Building Blocks. | | This file is part of Threading Building Blocks. | |
| | | | |
| Threading Building Blocks is free software; you can redistribute it | | Threading Building Blocks is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU General Public License | | and/or modify it under the terms of the GNU General Public License | |
| version 2 as published by the Free Software Foundation. | | version 2 as published by the Free Software Foundation. | |
| | | | |
| Threading Building Blocks is distributed in the hope that it will be | | Threading Building Blocks is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty | | useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | |
| skipping to change at line 37 | | skipping to change at line 37 | |
| */ | | */ | |
| | | | |
| #ifndef __TBB_tbb_stddef_H | | #ifndef __TBB_tbb_stddef_H | |
| #define __TBB_tbb_stddef_H | | #define __TBB_tbb_stddef_H | |
| | | | |
| // Marketing-driven product version | | // Marketing-driven product version | |
| #define TBB_VERSION_MAJOR 4 | | #define TBB_VERSION_MAJOR 4 | |
| #define TBB_VERSION_MINOR 1 | | #define TBB_VERSION_MINOR 1 | |
| | | | |
| // Engineering-focused interface version | | // Engineering-focused interface version | |
|
| #define TBB_INTERFACE_VERSION 6101 | | #define TBB_INTERFACE_VERSION 6102 | |
| #define TBB_INTERFACE_VERSION_MAJOR TBB_INTERFACE_VERSION/1000 | | #define TBB_INTERFACE_VERSION_MAJOR TBB_INTERFACE_VERSION/1000 | |
| | | | |
| // The oldest major interface version still supported | | // The oldest major interface version still supported | |
| // To be used in SONAME, manifests, etc. | | // To be used in SONAME, manifests, etc. | |
| #define TBB_COMPATIBLE_INTERFACE_VERSION 2 | | #define TBB_COMPATIBLE_INTERFACE_VERSION 2 | |
| | | | |
| #define __TBB_STRING_AUX(x) #x | | #define __TBB_STRING_AUX(x) #x | |
| #define __TBB_STRING(x) __TBB_STRING_AUX(x) | | #define __TBB_STRING(x) __TBB_STRING_AUX(x) | |
| | | | |
| // We do not need defines below for resource processing on windows | | // We do not need defines below for resource processing on windows | |
| | | | |
| skipping to change at line 102 | | skipping to change at line 102 | |
| TBB defines a set of minimal requirements each concept must conform to.
Here is | | TBB defines a set of minimal requirements each concept must conform to.
Here is | |
| the list of different concepts hyperlinked to the corresponding require
ments specifications: | | the list of different concepts hyperlinked to the corresponding require
ments specifications: | |
| - \subpage range_req | | - \subpage range_req | |
| - \subpage parallel_do_body_req | | - \subpage parallel_do_body_req | |
| - \subpage parallel_for_body_req | | - \subpage parallel_for_body_req | |
| - \subpage parallel_reduce_body_req | | - \subpage parallel_reduce_body_req | |
| - \subpage parallel_scan_body_req | | - \subpage parallel_scan_body_req | |
| - \subpage parallel_sort_iter_req | | - \subpage parallel_sort_iter_req | |
| **/ | | **/ | |
| | | | |
|
| // Define preprocessor symbols used to determine architecture | | | |
| #if _WIN32||_WIN64 | | | |
| # if defined(_M_X64)||defined(__x86_64__) // the latter for MinGW suppor | | | |
| t | | | |
| # define __TBB_x86_64 1 | | | |
| # elif defined(_M_IA64) | | | |
| # define __TBB_ipf 1 | | | |
| # elif defined(_M_IX86)||defined(__i386__) // the latter for MinGW suppor | | | |
| t | | | |
| # define __TBB_x86_32 1 | | | |
| # endif | | | |
| #else /* Assume generic Unix */ | | | |
| # if !__linux__ && !__APPLE__ | | | |
| # define __TBB_generic_os 1 | | | |
| # endif | | | |
| # if __x86_64__ | | | |
| # define __TBB_x86_64 1 | | | |
| # elif __ia64__ | | | |
| # define __TBB_ipf 1 | | | |
| # elif __i386__||__i386 // __i386 is for Sun OS | | | |
| # define __TBB_x86_32 1 | | | |
| # else | | | |
| # define __TBB_generic_arch 1 | | | |
| # endif | | | |
| #endif | | | |
| | | | |
| // tbb_config.h should be included the first since it contains macro defini
tions used in other headers | | // tbb_config.h should be included the first since it contains macro defini
tions used in other headers | |
| #include "tbb_config.h" | | #include "tbb_config.h" | |
| | | | |
| #if _MSC_VER >=1400 | | #if _MSC_VER >=1400 | |
| #define __TBB_EXPORTED_FUNC __cdecl | | #define __TBB_EXPORTED_FUNC __cdecl | |
| #define __TBB_EXPORTED_METHOD __thiscall | | #define __TBB_EXPORTED_METHOD __thiscall | |
| #else | | #else | |
| #define __TBB_EXPORTED_FUNC | | #define __TBB_EXPORTED_FUNC | |
| #define __TBB_EXPORTED_METHOD | | #define __TBB_EXPORTED_METHOD | |
| #endif | | #endif | |
| | | | |
| skipping to change at line 383 | | skipping to change at line 359 | |
| | | | |
| //! A function to select either 32-bit or 64-bit value, depending on machin
e word size. | | //! A function to select either 32-bit or 64-bit value, depending on machin
e word size. | |
| inline size_t size_t_select( unsigned u, unsigned long long ull ) { | | inline size_t size_t_select( unsigned u, unsigned long long ull ) { | |
| /* Explicit cast of the arguments to size_t is done to avoid compiler w
arnings | | /* Explicit cast of the arguments to size_t is done to avoid compiler w
arnings | |
| (e.g. by Clang and MSVC) about possible truncation. The value of the
right size, | | (e.g. by Clang and MSVC) about possible truncation. The value of the
right size, | |
| which is selected by ?:, is anyway not truncated or promoted. | | which is selected by ?:, is anyway not truncated or promoted. | |
| MSVC still warns if this trick is applied directly to constants, hen
ce this function. */ | | MSVC still warns if this trick is applied directly to constants, hen
ce this function. */ | |
| return (sizeof(size_t)==sizeof(u)) ? size_t(u) : size_t(ull); | | return (sizeof(size_t)==sizeof(u)) ? size_t(u) : size_t(ull); | |
| } | | } | |
| | | | |
|
| | | template<typename T> | |
| | | static inline bool is_aligned(T* pointer, uintptr_t alignment) { | |
| | | return 0==((uintptr_t)pointer & (alignment-1)); | |
| | | } | |
| | | | |
| // Struct to be used as a version tag for inline functions. | | // Struct to be used as a version tag for inline functions. | |
| /** Version tag can be necessary to prevent loader on Linux from using the
wrong | | /** Version tag can be necessary to prevent loader on Linux from using the
wrong | |
| symbol in debug builds (when inline functions are compiled as out-of-li
ne). **/ | | symbol in debug builds (when inline functions are compiled as out-of-li
ne). **/ | |
| struct version_tag_v3 {}; | | struct version_tag_v3 {}; | |
| | | | |
| typedef version_tag_v3 version_tag; | | typedef version_tag_v3 version_tag; | |
| | | | |
| } // internal | | } // internal | |
| //! @endcond | | //! @endcond | |
| | | | |
| } // tbb | | } // tbb | |
| | | | |
|
| | | namespace tbb { namespace internal { | |
| | | template <bool condition> | |
| | | struct STATIC_ASSERTION_FAILED; | |
| | | | |
| | | template <> | |
| | | struct STATIC_ASSERTION_FAILED<false> { enum {value=1};}; | |
| | | | |
| | | template<> | |
| | | struct STATIC_ASSERTION_FAILED<true>; //intentionally left undefined to cau | |
| | | se compile time error | |
| | | }} // namespace tbb { namespace internal { | |
| | | | |
| | | #if __TBB_STATIC_ASSERT_PRESENT | |
| | | #define __TBB_STATIC_ASSERT(condition,msg) static_assert(condition,msg) | |
| | | #else | |
| | | //please note condition is intentionally inverted to get a bit more underst | |
| | | andable error msg | |
| | | #define __TBB_STATIC_ASSERT_IMPL1(condition,msg,line) \ | |
| | | enum {static_assert_on_line_##line = tbb::internal::STATIC_ASSERTION_FA | |
| | | ILED<!(condition)>::value} | |
| | | | |
| | | #define __TBB_STATIC_ASSERT_IMPL(condition,msg,line) __TBB_STATIC_ASSERT_IM | |
| | | PL1(condition,msg,line) | |
| | | //! Verify at compile time that passed in condition is hold | |
| | | #define __TBB_STATIC_ASSERT(condition,msg) __TBB_STATIC_ASSERT_IMPL(conditi | |
| | | on,msg,__LINE__) | |
| | | #endif | |
| | | | |
| #endif /* RC_INVOKED */ | | #endif /* RC_INVOKED */ | |
| #endif /* __TBB_tbb_stddef_H */ | | #endif /* __TBB_tbb_stddef_H */ | |
| | | | |
End of changes. 5 change blocks. |
| 28 lines changed or deleted | | 35 lines changed or added | |
|