| _concurrent_unordered_impl.h | | _concurrent_unordered_impl.h | |
| | | | |
| skipping to change at line 48 | | skipping to change at line 48 | |
| #include "../tbb_stddef.h" | | #include "../tbb_stddef.h" | |
| | | | |
| #if !TBB_USE_EXCEPTIONS && _MSC_VER | | #if !TBB_USE_EXCEPTIONS && _MSC_VER | |
| // Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers | | // Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers | |
| #pragma warning (push) | | #pragma warning (push) | |
| #pragma warning (disable: 4530) | | #pragma warning (disable: 4530) | |
| #endif | | #endif | |
| | | | |
| #include <iterator> | | #include <iterator> | |
| #include <utility> // Need std::pair | | #include <utility> // Need std::pair | |
|
| #include <functional> | | #include <functional> // Need std::equal_to (in ../concurrent_unordered_*
.h) | |
| #include <string> // For tbb_hasher | | #include <string> // For tbb_hasher | |
| #include <cstring> // Need std::memset | | #include <cstring> // Need std::memset | |
| | | | |
| #if !TBB_USE_EXCEPTIONS && _MSC_VER | | #if !TBB_USE_EXCEPTIONS && _MSC_VER | |
| #pragma warning (pop) | | #pragma warning (pop) | |
| #endif | | #endif | |
| | | | |
| #include "../atomic.h" | | #include "../atomic.h" | |
| #include "../tbb_exception.h" | | #include "../tbb_exception.h" | |
| #include "../tbb_allocator.h" | | #include "../tbb_allocator.h" | |
|
| | | #include "tbb/atomic.h" | |
| | | | |
| namespace tbb { | | namespace tbb { | |
| namespace interface5 { | | namespace interface5 { | |
| //! @cond INTERNAL | | //! @cond INTERNAL | |
| namespace internal { | | namespace internal { | |
| | | | |
| template <typename T, typename Allocator> | | template <typename T, typename Allocator> | |
| class split_ordered_list; | | class split_ordered_list; | |
| template <typename Traits> | | template <typename Traits> | |
| class concurrent_unordered_base; | | class concurrent_unordered_base; | |
| | | | |
| skipping to change at line 233 | | skipping to change at line 234 | |
| | | | |
| // Return the order key (needed for hashing) | | // Return the order key (needed for hashing) | |
| sokey_t get_order_key() const { // TODO: remove | | sokey_t get_order_key() const { // TODO: remove | |
| return my_order_key; | | return my_order_key; | |
| } | | } | |
| | | | |
| // Inserts the new element in the list in an atomic fashion | | // Inserts the new element in the list in an atomic fashion | |
| nodeptr_t atomic_set_next(nodeptr_t new_node, nodeptr_t current_nod
e) | | nodeptr_t atomic_set_next(nodeptr_t new_node, nodeptr_t current_nod
e) | |
| { | | { | |
| // Try to change the next pointer on the current element to a n
ew element, only if it still points to the cached next | | // Try to change the next pointer on the current element to a n
ew element, only if it still points to the cached next | |
|
| nodeptr_t exchange_node = (nodeptr_t) __TBB_CompareAndSwapW((vo
id *) &my_next, (uintptr_t)new_node, (uintptr_t)current_node); | | nodeptr_t exchange_node = tbb::internal::as_atomic(my_next).com
pare_and_swap(new_node, current_node); | |
| | | | |
| if (exchange_node == current_node) // TODO: why this branch? | | if (exchange_node == current_node) // TODO: why this branch? | |
| { | | { | |
| // Operation succeeded, return the new node | | // Operation succeeded, return the new node | |
| return new_node; | | return new_node; | |
| } | | } | |
| else | | else | |
| { | | { | |
| // Operation failed, return the "interfering" node | | // Operation failed, return the "interfering" node | |
| return exchange_node; | | return exchange_node; | |
| | | | |
| skipping to change at line 1293 | | skipping to change at line 1294 | |
| // Create a dummy first node in this bucket | | // Create a dummy first node in this bucket | |
| raw_iterator dummy_node = my_solist.insert_dummy(parent, split_orde
r_key_dummy(bucket)); | | raw_iterator dummy_node = my_solist.insert_dummy(parent, split_orde
r_key_dummy(bucket)); | |
| set_bucket(bucket, dummy_node); | | set_bucket(bucket, dummy_node); | |
| } | | } | |
| | | | |
| void adjust_table_size(size_type total_elements, size_type current_size
) | | void adjust_table_size(size_type total_elements, size_type current_size
) | |
| { | | { | |
| // Grow the table by a factor of 2 if possible and needed | | // Grow the table by a factor of 2 if possible and needed | |
| if ( ((float) total_elements / (float) current_size) > my_maximum_b
ucket_size ) | | if ( ((float) total_elements / (float) current_size) > my_maximum_b
ucket_size ) | |
| { | | { | |
|
| // Double the size of the hash only if size has not changed inb | | // Double the size of the hash only if size has not changed in | |
| etween loads | | between loads | |
| __TBB_CompareAndSwapW((uintptr_t*)&my_number_of_buckets, uintpt | | my_number_of_buckets.compare_and_swap(2u*current_size, current_ | |
| r_t(2u*current_size), uintptr_t(current_size) ); | | size); | |
| //Simple "my_number_of_buckets.compare_and_swap( current_size<<
1, current_size );" does not work for VC8 | | //Simple "my_number_of_buckets.compare_and_swap( current_size<<
1, current_size );" does not work for VC8 | |
| //due to overzealous compiler warnings in /Wp64 mode | | //due to overzealous compiler warnings in /Wp64 mode | |
| } | | } | |
| } | | } | |
| | | | |
| size_type get_parent(size_type bucket) const | | size_type get_parent(size_type bucket) const | |
| { | | { | |
| // Unsets bucket's most significant turned-on bit | | // Unsets bucket's most significant turned-on bit | |
| size_type msb = __TBB_Log2((uintptr_t)bucket); | | size_type msb = __TBB_Log2((uintptr_t)bucket); | |
| return bucket & ~(size_type(1) << msb); | | return bucket & ~(size_type(1) << msb); | |
| | | | |
| skipping to change at line 1339 | | skipping to change at line 1340 | |
| | | | |
| void set_bucket(size_type bucket, raw_iterator dummy_head) { | | void set_bucket(size_type bucket, raw_iterator dummy_head) { | |
| size_type segment = segment_index_of(bucket); | | size_type segment = segment_index_of(bucket); | |
| bucket -= segment_base(segment); | | bucket -= segment_base(segment); | |
| | | | |
| if (my_buckets[segment] == NULL) { | | if (my_buckets[segment] == NULL) { | |
| size_type sz = segment_size(segment); | | size_type sz = segment_size(segment); | |
| raw_iterator * new_segment = my_allocator.allocate(sz); | | raw_iterator * new_segment = my_allocator.allocate(sz); | |
| std::memset(new_segment, 0, sz*sizeof(raw_iterator)); | | std::memset(new_segment, 0, sz*sizeof(raw_iterator)); | |
| | | | |
|
| if (__TBB_CompareAndSwapW((void *) &my_buckets[segment], (uintp
tr_t)new_segment, 0) != 0) | | if (my_buckets[segment].compare_and_swap( new_segment, NULL) !=
NULL) | |
| my_allocator.deallocate(new_segment, sz); | | my_allocator.deallocate(new_segment, sz); | |
| } | | } | |
| | | | |
| my_buckets[segment][bucket] = dummy_head; | | my_buckets[segment][bucket] = dummy_head; | |
| } | | } | |
| | | | |
| bool is_initialized(size_type bucket) const { | | bool is_initialized(size_type bucket) const { | |
| size_type segment = segment_index_of(bucket); | | size_type segment = segment_index_of(bucket); | |
| bucket -= segment_base(segment); | | bucket -= segment_base(segment); | |
| | | | |
| | | | |
End of changes. 5 change blocks. |
| 7 lines changed or deleted | | 8 lines changed or added | |
|
| atomic.h | | atomic.h | |
| | | | |
| skipping to change at line 32 | | skipping to change at line 32 | |
| this file and link it with other files to produce an executable, this | | this file and link it with other files to produce an executable, this | |
| file does not by itself cause the resulting executable to be covered by | | file does not by itself cause the resulting executable to be covered by | |
| the GNU General Public License. This exception does not however | | the GNU General Public License. This exception does not however | |
| invalidate any other reasons why the executable file might be covered b
y | | invalidate any other reasons why the executable file might be covered b
y | |
| the GNU General Public License. | | the GNU General Public License. | |
| */ | | */ | |
| | | | |
| #ifndef __TBB_atomic_H | | #ifndef __TBB_atomic_H | |
| #define __TBB_atomic_H | | #define __TBB_atomic_H | |
| | | | |
|
| #include "tbb_stddef.h" | | | |
| #include <cstddef> | | #include <cstddef> | |
| | | | |
| #if _MSC_VER | | #if _MSC_VER | |
| #define __TBB_LONG_LONG __int64 | | #define __TBB_LONG_LONG __int64 | |
| #else | | #else | |
| #define __TBB_LONG_LONG long long | | #define __TBB_LONG_LONG long long | |
| #endif /* _MSC_VER */ | | #endif /* _MSC_VER */ | |
| | | | |
| #include "tbb_machine.h" | | #include "tbb_machine.h" | |
| | | | |
| #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |
| // Workaround for overzealous compiler warnings | | // Workaround for overzealous compiler warnings | |
| #pragma warning (push) | | #pragma warning (push) | |
|
| #pragma warning (disable: 4244 4267) | | #pragma warning (disable: 4244 4267 4512) | |
| #endif | | #endif | |
| | | | |
| namespace tbb { | | namespace tbb { | |
| | | | |
| //! Specifies memory semantics. | | //! Specifies memory semantics. | |
| enum memory_semantics { | | enum memory_semantics { | |
| //! Sequential consistency | | //! Sequential consistency | |
| full_fence, | | full_fence, | |
| //! Acquire | | //! Acquire | |
| acquire, | | acquire, | |
| | | | |
| skipping to change at line 243 | | skipping to change at line 242 | |
| template<typename value_type> | | template<typename value_type> | |
| union converter { | | union converter { | |
| typedef typename atomic_rep<sizeof(value_type)>::word bits_type; | | typedef typename atomic_rep<sizeof(value_type)>::word bits_type; | |
| converter(){} | | converter(){} | |
| converter(value_type a_value) : value(a_value) {} | | converter(value_type a_value) : value(a_value) {} | |
| value_type value; | | value_type value; | |
| bits_type bits; | | bits_type bits; | |
| }; | | }; | |
| | | | |
| template<typename value_t> | | 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){ | | static typename converter<value_t>::bits_type to_bits(value_t value){ | |
| return converter<value_t>(value).bits; | | return converter<value_t>(value).bits; | |
| } | | } | |
| template<typename value_t> | | template<typename value_t> | |
| static value_t to_value(typename converter<value_t>::bits_type bits){ | | static value_t to_value(typename converter<value_t>::bits_type bits){ | |
| converter<value_t> u; | | converter<value_t> u; | |
| u.bits = bits; | | u.bits = bits; | |
| return u.value; | | 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> | | template<typename value_t> | |
|
| static typename ptr_converter<value_t*>::bits_ptr_type to_bits_ptr(valu | | union ptr_converter; //Primary template declared, but never | |
| e_t* value){ | | defined. | |
| //TODO: try to use cast to void* and second cast to required pointe | | | |
| r type; | | template<typename value_t> | |
| //Once (and if) union converter goes away - check if strict aliasin | | union ptr_converter<value_t *> { | |
| g warning | | ptr_converter(){} | |
| //suppression is still needed once. | | ptr_converter(value_t* a_value) : value(a_value) {} | |
| | | value_t* value; | |
| | | uintptr_t bits; | |
| | | }; | |
| | | //TODO: check if making to_bits accepting reference (thus unifying it w | |
| | | ith to_bits_ref) | |
| | | //does not hurt performance | |
| | | template<typename value_t> | |
| | | static typename converter<value_t>::bits_type & to_bits_ref(value_t& va | |
| | | lue){ | |
| //TODO: this #ifdef is temporary workaround, as union conversion se
ems to fail | | //TODO: this #ifdef is temporary workaround, as union conversion se
ems to fail | |
| //on suncc for 64 bit types for 32 bit target | | //on suncc for 64 bit types for 32 bit target | |
| #if !__SUNPRO_CC | | #if !__SUNPRO_CC | |
|
| return ptr_converter<value_t*>(value).bits; | | return *(typename converter<value_t>::bits_type*)ptr_converter<
value_t*>(&value).bits; | |
| #else | | #else | |
|
| return typename ptr_converter<value_t*>::bits_ptr_type (value); | | return *(typename converter<value_t>::bits_type*)(&value); | |
| #endif | | #endif | |
| } | | } | |
| | | | |
| public: | | public: | |
| typedef T value_type; | | typedef T value_type; | |
| | | | |
| #if __TBB_ATOMIC_CTORS | | #if __TBB_ATOMIC_CTORS | |
| atomic_impl() = default ; | | atomic_impl() = default ; | |
| constexpr atomic_impl(value_type value):my_storage(value){} | | constexpr atomic_impl(value_type value):my_storage(value){} | |
| #endif | | #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 ) { | |
|
| return to_value<value_type>(internal::atomic_traits<sizeof(value_ | | return to_value<value_type>( | |
| type),M>::fetch_and_store(&my_storage.my_value,to_bits(value))); | | internal::atomic_traits<sizeof(value_type),M>::fetch_and_ | |
| | | store( &my_storage.my_value, to_bits(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 ) { | |
|
| return to_value<value_type>(internal::atomic_traits<sizeof(value_ty | | return to_value<value_type>( | |
| pe),M>::compare_and_swap(&my_storage.my_value,to_bits(value),to_bits(compar | | internal::atomic_traits<sizeof(value_type),M>::compare_and_ | |
| and))); | | swap( &my_storage.my_value, to_bits(value), to_bits(comparand) ) | |
| | | ); | |
| } | | } | |
| | | | |
| 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 | |
|
| return to_value<value_type>(__TBB_load_with_acquire(*to_bits_ptr(& | | return to_value<value_type>( | |
| my_storage.my_value))); | | __TBB_load_with_acquire( to_bits_ref(my_storage.my_value) ) | |
| | | ); | |
| } | | } | |
| | | | |
| template<memory_semantics M> | | template<memory_semantics M> | |
| value_type load () const { | | value_type load () const { | |
|
| return to_value<value_type>(internal::atomic_load_store_traits<M>:: | | return to_value<value_type>( | |
| load(*to_bits_ptr(&my_storage.my_value))); | | internal::atomic_load_store_traits<M>::load( to_bits_ref(my | |
| | | _storage.my_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 ) { | |
|
| internal::atomic_load_store_traits<M>::store( *to_bits_ptr(&my_stor
age.my_value), to_bits(value)); | | internal::atomic_load_store_traits<M>::store( to_bits_ref(my_storag
e.my_value), to_bits(value)); | |
| } | | } | |
| | | | |
| 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 ) { | |
|
| __TBB_store_with_release(*to_bits_ptr(&my_storage.my_value),to_bits | | //TODO: unify with store<release> | |
| (rhs)); | | __TBB_store_with_release( to_bits_ref(my_storage.my_value), to_bits | |
| | | (rhs) ); | |
| 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> { | |
| | | | |
| skipping to change at line 424 | | skipping to change at line 427 | |
| 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;} | |
| }; | | }; | |
| | | | |
| #if __TBB_ATOMIC_CTORS | | #if __TBB_ATOMIC_CTORS | |
| #define __TBB_DECL_ATOMIC(T)
\ | | #define __TBB_DECL_ATOMIC(T)
\ | |
| template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<
T,T,char> { \ | | template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<
T,T,char> { \ | |
|
| atomic() = default;
\ | | atomic() = default;
\ | |
| constexpr atomic(T arg): internal::atomic_impl_with_arithmetic<
T,T,char>(arg) {} \ | | constexpr atomic(T arg): internal::atomic_impl_with_arithmetic<
T,T,char>(arg) {} \ | |
|
\ | |
\ | |
| T operator=( T rhs ) {return store_with_release(rhs);}
\ | | T operator=( T rhs ) {return store_with_release(rhs);}
\ | |
| atomic<T>& operator=( const atomic<T>& rhs ) {store_with_releas
e(rhs); return *this;} \ | | atomic<T>& operator=( const atomic<T>& rhs ) {store_with_releas
e(rhs); return *this;} \ | |
| }; | | }; | |
| #else | | #else | |
| #define __TBB_DECL_ATOMIC(T)
\ | | #define __TBB_DECL_ATOMIC(T)
\ | |
| template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<
T,T,char> { \ | | template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<
T,T,char> { \ | |
| T operator=( T rhs ) {return store_with_release(rhs);}
\ | | T operator=( T rhs ) {return store_with_release(rhs);}
\ | |
| atomic<T>& operator=( const atomic<T>& rhs ) {store_with_releas
e(rhs); return *this;} \ | | atomic<T>& operator=( const atomic<T>& rhs ) {store_with_releas
e(rhs); return *this;} \ | |
| | | | |
| skipping to change at line 457 | | skipping to change at line 460 | |
| | | | |
| #if _MSC_VER && !_WIN64 | | #if _MSC_VER && !_WIN64 | |
| #if __TBB_ATOMIC_CTORS | | #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,
char> { \ | | template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T,
char> { \ | |
|
| atomic() = default ;
\ | | atomic() = default ;
\ | |
| constexpr atomic(T arg): internal::atomic_impl_with_arithmetic<T,T,
char>(arg) {} \ | | constexpr atomic(T arg): internal::atomic_impl_with_arithmetic<T,T,
char>(arg) {} \ | |
| T operator=( U rhs ) {return store_with_release(T(rhs));}
\ | | 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 | | #else | |
| #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,
char> { \ | | template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T,
char> { \ | |
| T operator=( U rhs ) {return store_with_release(T(rhs));}
\ | | 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;} \ | |
| }; | | }; | |
| | | | |
End of changes. 15 change blocks. |
| 42 lines changed or deleted | | 40 lines changed or added | |
|
| concurrent_hash_map.h | | concurrent_hash_map.h | |
| | | | |
| skipping to change at line 79 | | skipping to change at line 79 | |
| static bool equal( const Key& a, const Key& b ) { return a == b; } | | static bool equal( const Key& a, const Key& b ) { return a == b; } | |
| }; | | }; | |
| | | | |
| namespace interface5 { | | namespace interface5 { | |
| | | | |
| template<typename Key, typename T, typename HashCompare = tbb_hash_comp
are<Key>, typename A = tbb_allocator<std::pair<Key, T> > > | | template<typename Key, typename T, typename HashCompare = tbb_hash_comp
are<Key>, typename A = tbb_allocator<std::pair<Key, T> > > | |
| class concurrent_hash_map; | | class concurrent_hash_map; | |
| | | | |
| //! @cond INTERNAL | | //! @cond INTERNAL | |
| namespace internal { | | namespace internal { | |
|
| | | using namespace tbb::internal; | |
| | | | |
| //! Type of a hash code. | | //! Type of a hash code. | |
| typedef size_t hashcode_t; | | typedef size_t hashcode_t; | |
| //! Node base type | | //! Node base type | |
| struct hash_map_node_base : tbb::internal::no_copy { | | struct hash_map_node_base : tbb::internal::no_copy { | |
| //! Mutex type | | //! Mutex type | |
| typedef spin_rw_mutex mutex_t; | | typedef spin_rw_mutex mutex_t; | |
| //! Scoped lock type for mutex | | //! Scoped lock type for mutex | |
| typedef mutex_t::scoped_lock scoped_t; | | typedef mutex_t::scoped_lock scoped_t; | |
| //! Next node in chain | | //! Next node in chain | |
| | | | |
| skipping to change at line 287 | | skipping to change at line 288 | |
| } | | } | |
| | | | |
| //! Insert a node and check for load factor. @return segment index
to enable. | | //! Insert a node and check for load factor. @return segment index
to enable. | |
| segment_index_t insert_new_node( bucket *b, node_base *n, hashcode_
t mask ) { | | segment_index_t insert_new_node( bucket *b, node_base *n, hashcode_
t mask ) { | |
| size_type sz = ++my_size; // prefix form is to enforce allocati
on after the first item inserted | | size_type sz = ++my_size; // prefix form is to enforce allocati
on after the first item inserted | |
| add_to_bucket( b, n ); | | add_to_bucket( b, n ); | |
| // check load factor | | // check load factor | |
| if( sz >= mask ) { // TODO: add custom load_factor | | if( sz >= mask ) { // TODO: add custom load_factor | |
| segment_index_t new_seg = __TBB_Log2( mask+1 ); //optimized
segment_index_of | | segment_index_t new_seg = __TBB_Log2( mask+1 ); //optimized
segment_index_of | |
| __TBB_ASSERT( is_valid(my_table[new_seg-1]), "new allocatio
ns must not publish new mask until segment has allocated"); | | __TBB_ASSERT( is_valid(my_table[new_seg-1]), "new allocatio
ns must not publish new mask until segment has allocated"); | |
|
| | | static const segment_ptr_t is_allocating = (segment_ptr_t)2
; | |
| if( !itt_hide_load_word(my_table[new_seg]) | | if( !itt_hide_load_word(my_table[new_seg]) | |
|
| && __TBB_CompareAndSwapW(&my_table[new_seg], 2, 0) == 0 ) | | && as_atomic(my_table[new_seg]).compare_and_swap(is_alloc
ating, NULL) == NULL ) | |
| return new_seg; // The value must be processed | | return new_seg; // The value must be processed | |
| } | | } | |
| return 0; | | return 0; | |
| } | | } | |
| | | | |
| //! Prepare enough segments for number of buckets | | //! Prepare enough segments for number of buckets | |
| void reserve(size_type buckets) { | | void reserve(size_type buckets) { | |
| if( !buckets-- ) return; | | if( !buckets-- ) return; | |
| bool is_initial = !my_size; | | bool is_initial = !my_size; | |
| for( size_type m = my_mask; buckets > m; m = my_mask ) | | for( size_type m = my_mask; buckets > m; m = my_mask ) | |
| | | | |
End of changes. 3 change blocks. |
| 1 lines changed or deleted | | 3 lines changed or added | |
|
| gcc_armv7.h | | gcc_armv7.h | |
| | | | |
| skipping to change at line 30 | | skipping to change at line 30 | |
| library without restriction. Specifically, if other files instantiate | | library without restriction. Specifically, if other files instantiate | |
| templates or use macros or inline functions from this file, or you comp
ile | | templates or use macros or inline functions from this file, or you comp
ile | |
| this file and link it with other files to produce an executable, this | | this file and link it with other files to produce an executable, this | |
| file does not by itself cause the resulting executable to be covered by | | file does not by itself cause the resulting executable to be covered by | |
| the GNU General Public License. This exception does not however | | the GNU General Public License. This exception does not however | |
| invalidate any other reasons why the executable file might be covered b
y | | invalidate any other reasons why the executable file might be covered b
y | |
| the GNU General Public License. | | the GNU General Public License. | |
| */ | | */ | |
| | | | |
| /* | | /* | |
|
| This is the TBB implementation for the ARMv7-a architecture. | | Platform isolation layer for the ARMv7-a architecture. | |
| */ | | */ | |
| | | | |
| #ifndef __TBB_machine_H | | #ifndef __TBB_machine_H | |
| #error Do not include this file directly; include tbb_machine.h instead | | #error Do not include this file directly; include tbb_machine.h instead | |
| #endif | | #endif | |
| | | | |
| //TODO: is ARMv7 is the only version ever to support? | | //TODO: is ARMv7 is the only version ever to support? | |
| #if !(__ARM_ARCH_7A__) | | #if !(__ARM_ARCH_7A__) | |
| #error compilation requires an ARMv7-a architecture. | | #error compilation requires an ARMv7-a architecture. | |
| #endif | | #endif | |
| | | | |
| #include <sys/param.h> | | #include <sys/param.h> | |
| #include <unistd.h> | | #include <unistd.h> | |
| | | | |
| #define __TBB_WORDSIZE 4 | | #define __TBB_WORDSIZE 4 | |
| | | | |
|
| #ifndef __BYTE_ORDER__ | | // Traditionally ARM is little-endian. | |
| // Hopefully endianness can be validly determined at runtime. | | // Note that, since only the layout of aligned 32-bit words is of interest, | |
| // This may silently fail in some embedded systems with page-specific e | | // any apparent PDP-endianness of 32-bit words at half-word alignment or | |
| ndianness. | | // any little-endian ordering of big-endian 32-bit words in 64-bit quantiti | |
| #elif __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ | | es | |
| #define __TBB_BIG_ENDIAN 1 | | // may be disregarded for this setting. | |
| #elif __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ | | #if __BIG_ENDIAN__ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_B | |
| #define __TBB_BIG_ENDIAN 0 | | IG_ENDIAN__) | |
| | | #define __TBB_ENDIANNESS __TBB_ENDIAN_BIG | |
| | | #elif __LITTLE_ENDIAN__ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__==__OR | |
| | | DER_LITTLE_ENDIAN__) | |
| | | #define __TBB_ENDIANNESS __TBB_ENDIAN_LITTLE | |
| | | #elif defined(__BYTE_ORDER__) | |
| | | #define __TBB_ENDIANNESS __TBB_ENDIAN_UNSUPPORTED | |
| #else | | #else | |
|
| #define __TBB_BIG_ENDIAN -1 // not currently supported | | #define __TBB_ENDIANNESS __TBB_ENDIAN_DETECT | |
| #endif | | #endif | |
| | | | |
| #define __TBB_compiler_fence() __asm__ __volatile__("": : :"memory") | | #define __TBB_compiler_fence() __asm__ __volatile__("": : :"memory") | |
| #define __TBB_control_consistency_helper() __TBB_compiler_fence() | | #define __TBB_control_consistency_helper() __TBB_compiler_fence() | |
| | | | |
| #define __TBB_armv7_inner_shareable_barrier() __asm__ __volatile__("dmb ish
": : :"memory") | | #define __TBB_armv7_inner_shareable_barrier() __asm__ __volatile__("dmb ish
": : :"memory") | |
| #define __TBB_acquire_consistency_helper() __TBB_armv7_inner_shareable_barr
ier() | | #define __TBB_acquire_consistency_helper() __TBB_armv7_inner_shareable_barr
ier() | |
| #define __TBB_release_consistency_helper() __TBB_armv7_inner_shareable_barr
ier() | | #define __TBB_release_consistency_helper() __TBB_armv7_inner_shareable_barr
ier() | |
| #define __TBB_full_memory_fence() __TBB_armv7_inner_shareable_barrier() | | #define __TBB_full_memory_fence() __TBB_armv7_inner_shareable_barrier() | |
| | | | |
| | | | |
End of changes. 3 change blocks. |
| 10 lines changed or deleted | | 16 lines changed or added | |
|
| gcc_generic.h | | gcc_generic.h | |
| | | | |
| skipping to change at line 49 | | skipping to change at line 49 | |
| | | | |
| #if __TBB_GCC_64BIT_ATOMIC_BUILTINS_BROKEN | | #if __TBB_GCC_64BIT_ATOMIC_BUILTINS_BROKEN | |
| #define __TBB_64BIT_ATOMICS 0 | | #define __TBB_64BIT_ATOMICS 0 | |
| #endif | | #endif | |
| | | | |
| /** FPU control setting not available for non-Intel architectures on Androi
d **/ | | /** FPU control setting not available for non-Intel architectures on Androi
d **/ | |
| #if __ANDROID__ && __TBB_generic_arch | | #if __ANDROID__ && __TBB_generic_arch | |
| #define __TBB_CPU_CTL_ENV_PRESENT 0 | | #define __TBB_CPU_CTL_ENV_PRESENT 0 | |
| #endif | | #endif | |
| | | | |
|
| #ifdef __BYTE_ORDER__ | | // __BYTE_ORDER__ is used in accordance with http://gcc.gnu.org/onlinedocs/ | |
| #if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ | | cpp/Common-Predefined-Macros.html, | |
| #define __TBB_BIG_ENDIAN 1 | | // but __BIG_ENDIAN__ or __LITTLE_ENDIAN__ may be more commonly found inste | |
| #elif __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ | | ad. | |
| #define __TBB_BIG_ENDIAN 0 | | #if __BIG_ENDIAN__ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_B | |
| #elif __BYTE_ORDER__==__ORDER_PDP_ENDIAN__ | | IG_ENDIAN__) | |
| #define __TBB_BIG_ENDIAN -1 // not currently supported | | #define __TBB_ENDIANNESS __TBB_ENDIAN_BIG | |
| #endif | | #elif __LITTLE_ENDIAN__ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__==__OR | |
| | | DER_LITTLE_ENDIAN__) | |
| | | #define __TBB_ENDIANNESS __TBB_ENDIAN_LITTLE | |
| | | #elif defined(__BYTE_ORDER__) | |
| | | #define __TBB_ENDIANNESS __TBB_ENDIAN_UNSUPPORTED | |
| | | #else | |
| | | #define __TBB_ENDIANNESS __TBB_ENDIAN_DETECT | |
| #endif | | #endif | |
| | | | |
| /** As this generic implementation has absolutely no information about unde
rlying | | /** As this generic implementation has absolutely no information about unde
rlying | |
| hardware, its performance most likely will be sub-optimal because of fu
ll memory | | hardware, its performance most likely will be sub-optimal because of fu
ll memory | |
| 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_acquire_consistency_helper() __sync_synchronize() | | #define __TBB_acquire_consistency_helper() __sync_synchronize() | |
| #define __TBB_release_consistency_helper() __sync_synchronize() | | #define __TBB_release_consistency_helper() __sync_synchronize() | |
| #define __TBB_full_memory_fence() __sync_synchronize() | | #define __TBB_full_memory_fence() __sync_synchronize() | |
| | | | |
| skipping to change at line 111 | | skipping to change at line 113 | |
| } | | } | |
| | | | |
| typedef unsigned char __TBB_Flag; | | typedef unsigned char __TBB_Flag; | |
| | | | |
| typedef __TBB_atomic __TBB_Flag __TBB_atomic_flag; | | typedef __TBB_atomic __TBB_Flag __TBB_atomic_flag; | |
| | | | |
| inline bool __TBB_machine_try_lock_byte( __TBB_atomic_flag &flag ) { | | inline bool __TBB_machine_try_lock_byte( __TBB_atomic_flag &flag ) { | |
| return __sync_lock_test_and_set(&flag,1)==0; | | return __sync_lock_test_and_set(&flag,1)==0; | |
| } | | } | |
| | | | |
|
| inline void __TBB_machine_unlock_byte( __TBB_atomic_flag &flag , __TBB_Flag
) { | | inline void __TBB_machine_unlock_byte( __TBB_atomic_flag &flag ) { | |
| __sync_lock_release(&flag); | | __sync_lock_release(&flag); | |
| } | | } | |
| | | | |
| // 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_TryLockByte __TBB_machine_try_lock_byte | | #define __TBB_TryLockByte __TBB_machine_try_lock_byte | |
| #define __TBB_UnlockByte __TBB_machine_unlock_byte | | #define __TBB_UnlockByte __TBB_machine_unlock_byte | |
| | | | |
| | | | |
End of changes. 2 change blocks. |
| 9 lines changed or deleted | | 15 lines changed or added | |
|
| memory_pool.h | | memory_pool.h | |
| | | | |
| skipping to change at line 40 | | skipping to change at line 40 | |
| #define __TBB_memory_pool_H | | #define __TBB_memory_pool_H | |
| | | | |
| #if !TBB_PREVIEW_MEMORY_POOL | | #if !TBB_PREVIEW_MEMORY_POOL | |
| #error Set TBB_PREVIEW_MEMORY_POOL to include memory_pool.h | | #error Set TBB_PREVIEW_MEMORY_POOL to include memory_pool.h | |
| #endif | | #endif | |
| /** @file */ | | /** @file */ | |
| | | | |
| #include "scalable_allocator.h" | | #include "scalable_allocator.h" | |
| #include "tbb_stddef.h" | | #include "tbb_stddef.h" | |
| #include "tbb_machine.h" // TODO: avoid linkage with libtbb on IA-64 | | #include "tbb_machine.h" // TODO: avoid linkage with libtbb on IA-64 | |
|
| | | #include "tbb/atomic.h" // for as_atomic | |
| #include <new> // std::bad_alloc | | #include <new> // std::bad_alloc | |
| #if __TBB_CPP11_RVALUE_REF_PRESENT && !__TBB_CPP11_STD_FORWARD_BROKEN | | #if __TBB_CPP11_RVALUE_REF_PRESENT && !__TBB_CPP11_STD_FORWARD_BROKEN | |
| #include <utility> // std::forward | | #include <utility> // std::forward | |
| #endif | | #endif | |
| | | | |
| #if __TBB_EXTRA_DEBUG | | #if __TBB_EXTRA_DEBUG | |
| #define __TBBMALLOC_ASSERT ASSERT | | #define __TBBMALLOC_ASSERT ASSERT | |
| #else | | #else | |
| #define __TBBMALLOC_ASSERT(a,b) ((void)0) | | #define __TBBMALLOC_ASSERT(a,b) ((void)0) | |
| #endif | | #endif | |
| | | | |
| skipping to change at line 265 | | skipping to change at line 266 | |
| #if _MSC_VER==1700 && !defined(__INTEL_COMPILER) | | #if _MSC_VER==1700 && !defined(__INTEL_COMPILER) | |
| #pragma warning (pop) | | #pragma warning (pop) | |
| #endif | | #endif | |
| inline fixed_pool::fixed_pool(void *buf, size_t size) : my_buffer(buf), my_
size(size) { | | inline fixed_pool::fixed_pool(void *buf, size_t size) : my_buffer(buf), my_
size(size) { | |
| rml::MemPoolPolicy args(allocate_request, 0, size, /*fixedPool=*/true); | | rml::MemPoolPolicy args(allocate_request, 0, size, /*fixedPool=*/true); | |
| rml::MemPoolError res = rml::pool_create_v1(intptr_t(this), &args, &my_
pool); | | rml::MemPoolError res = rml::pool_create_v1(intptr_t(this), &args, &my_
pool); | |
| if( res!=rml::POOL_OK ) __TBB_THROW(std::bad_alloc()); | | if( res!=rml::POOL_OK ) __TBB_THROW(std::bad_alloc()); | |
| } | | } | |
| inline void *fixed_pool::allocate_request(intptr_t pool_id, size_t & bytes)
{ | | inline void *fixed_pool::allocate_request(intptr_t pool_id, size_t & bytes)
{ | |
| fixed_pool &self = *reinterpret_cast<fixed_pool*>(pool_id); | | fixed_pool &self = *reinterpret_cast<fixed_pool*>(pool_id); | |
|
| if( !__TBB_CompareAndSwapW(&self.my_size, 0, (bytes=self.my_size)) ) | | if( !tbb::internal::as_atomic(self.my_size).compare_and_swap(0, (bytes=
self.my_size)) ) | |
| return 0; // all the memory was given already | | return 0; // all the memory was given already | |
| return self.my_buffer; | | return self.my_buffer; | |
| } | | } | |
| | | | |
| } //namespace interface6 | | } //namespace interface6 | |
| using interface6::memory_pool_allocator; | | using interface6::memory_pool_allocator; | |
| using interface6::memory_pool; | | using interface6::memory_pool; | |
| using interface6::fixed_pool; | | using interface6::fixed_pool; | |
| } //namespace tbb | | } //namespace tbb | |
| | | | |
| | | | |
End of changes. 2 change blocks. |
| 1 lines changed or deleted | | 2 lines changed or added | |
|
| tbb_config.h | | tbb_config.h | |
| | | | |
| skipping to change at line 75 | | skipping to change at line 75 | |
| 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__ && __VARIADIC_TEMPLATES ) | | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT ( __VARIADIC_TEMPLATE
S && (__GXX_EXPERIMENTAL_CXX0X__ || _MSC_VER) ) | |
| #define __TBB_CPP11_RVALUE_REF_PRESENT ( (__GXX_EXPERIMENTAL
_CXX0X__ || _MSC_VER >= 1600) && (__INTEL_COMPILER >= 1200) ) | | #define __TBB_CPP11_RVALUE_REF_PRESENT ( (__GXX_EXPERIMENTAL
_CXX0X__ || _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 >
1300 \ | |
| /*ICC 12.1 Upd 10 and
13 beta Upd 2 fixed exception_ptr linking issue*/ \ | | /*ICC 12.1 Upd 10 and
13 beta Upd 2 fixed exception_ptr linking issue*/ \ | |
| || (__INTEL_COMPILER
== 1300 && __INTEL_COMPILER_BUILD_DATE >= 20120530) \ | | || (__INTEL_COMPILER
== 1300 && __INTEL_COMPILER_BUILD_DATE >= 20120530) \ | |
| || (__INTEL_COMPILER
== 1210 && __INTEL_COMPILER_BUILD_DATE >= 20120410) ) | | || (__INTEL_COMPILER
== 1210 && __INTEL_COMPILER_BUILD_DATE >= 20120410) ) | |
| /** libstc++ that comes with GCC 4.6 use C++11 features not supported b
y ICC 12.1. | | /** libstc++ that comes with GCC 4.6 use C++11 features not supported b
y ICC 12.1. | |
| * Because of that ICC 12.1 does not support C++11 mode with with gcc 4
.6. (or higher) | | * Because of that ICC 12.1 does not support C++11 mode with with gcc 4
.6. (or higher) | |
| * , and therefore does not define __GXX_EXPERIMENTAL_CXX0X__ macro**/ | | * , and therefore does not define __GXX_EXPERIMENTAL_CXX0X__ macro**/ | |
| #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_CXX
0X__ && __INTEL_COMPILER >= 1200 ) | | #define __TBB_EXCEPTION_PTR_PRESENT ( __GXX_EXPERIMENTAL_
CXX0X__ && __INTEL_COMPILER >= 1200 ) | |
| #elif (__TBB_GCC_VERSION >= 40600) | | #elif (__TBB_GCC_VERSION >= 40600) | |
|
| #define __TBB_EXCEPTION_PTR_PRESENT ( __GXX_EXPERIMENTAL_CXX
0X__ && __INTEL_COMPILER >= 1300 ) | | #define __TBB_EXCEPTION_PTR_PRESENT ( __GXX_EXPERIMENTAL_
CXX0X__ && __INTEL_COMPILER >= 1300 ) | |
| #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 ||
(__GXX_EXPERIMENTAL_CXX0X__ && __TBB_GCC_VERSION >= 40600)) | | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700 ||
(__GXX_EXPERIMENTAL_CXX0X__ && __TBB_GCC_VERSION >= 40600)) | |
| #define __TBB_STATIC_ASSERT_PRESENT ( __GXX_EXPERIMENTAL_
CXX0X__ || (_MSC_VER >= 1600) ) | | #define __TBB_STATIC_ASSERT_PRESENT ( __GXX_EXPERIMENTAL_
CXX0X__ || (_MSC_VER >= 1600) ) | |
| #define __TBB_CPP11_TUPLE_PRESENT ( (_MSC_VER >= 1600)
|| ((__GXX_EXPERIMENTAL_CXX0X__) && (__TBB_GCC_VERSION >= 40300)) ) | | #define __TBB_CPP11_TUPLE_PRESENT ( (_MSC_VER >= 1600)
|| ((__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_CONSTEXPR_PRESENT 0 | |
| #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT 0 | | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT 0 | |
| | | | |
End of changes. 3 change blocks. |
| 3 lines changed or deleted | | 3 lines changed or added | |
|
| tbb_machine.h | | tbb_machine.h | |
| | | | |
| skipping to change at line 61 | | skipping to change at line 61 | |
| further. | | further. | |
| Note that these generic implementations may be sub-optimal for a partic
ular | | Note that these generic implementations may be sub-optimal for a partic
ular | |
| architecture, and thus should be relied upon only after careful evaluat
ion | | architecture, and thus should be relied upon only after careful evaluat
ion | |
| or as the last resort. | | or as the last resort. | |
| | | | |
| Additionally __TBB_64BIT_ATOMICS can be set to 0 on a 32-bit architectu
re to | | Additionally __TBB_64BIT_ATOMICS can be set to 0 on a 32-bit architectu
re to | |
| indicate that the port is not going to support double word atomics. It
may also | | indicate that the port is not going to support double word atomics. It
may also | |
| be set to 1 explicitly, though normally this is not necessary as tbb_ma
chine.h | | be set to 1 explicitly, though normally this is not necessary as tbb_ma
chine.h | |
| will set it automatically. | | will set it automatically. | |
| | | | |
|
| __TBB_BIG_ENDIAN macro can be defined by the implementation as well. | | __TBB_ENDIANNESS macro can be defined by the implementation as well. | |
| It is used only if the __TBB_USE_GENERIC_PART_WORD_CAS is set. | | It is used only if __TBB_USE_GENERIC_PART_WORD_CAS is set (or for testi | |
| Possible values are: | | ng), | |
| - 1 if the system is big endian, | | and must specify the layout of aligned 16-bit and 32-bit data anywhere | |
| - 0 if it is little endian, | | within a process | |
| - or -1 to explicitly state that __TBB_USE_GENERIC_PART_WORD_CAS ca | | (while the details of unaligned 16-bit or 32-bit data or of 64-bit data | |
| n not be used. | | are irrelevant). | |
| -1 should be used when it is known in advance that endianness can chang | | The layout must be the same at all relevant memory locations within the | |
| e in run time | | current process; | |
| or it is not simple big or little but something more complex. | | in case of page-specific endianness, one endianness must be kept "out o | |
| The system will try to detect it in run time if it is not set(in assump | | f sight". | |
| tion that it | | Possible settings, reflecting hardware and possibly O.S. convention, ar | |
| is either a big or little one). | | e: | |
| | | - __TBB_ENDIAN_BIG for big-endian data, | |
| | | - __TBB_ENDIAN_LITTLE for little-endian data, | |
| | | - __TBB_ENDIAN_DETECT for run-time detection iff exactly one of the ab | |
| | | ove, | |
| | | - __TBB_ENDIAN_UNSUPPORTED to prevent undefined behavior if none of th | |
| | | e above. | |
| | | | |
| Prerequisites for each architecture port | | Prerequisites for each architecture port | |
| ---------------------------------------- | | ---------------------------------------- | |
| The following functions and macros have no generic implementation. Ther
efore they must be | | The following functions and macros have no generic implementation. Ther
efore they must be | |
| implemented in each machine architecture specific header either as a co
nventional | | implemented in each machine architecture specific header either as a co
nventional | |
| function or as a functional macro. | | function or as a functional macro. | |
| | | | |
| __TBB_WORDSIZE | | __TBB_WORDSIZE | |
| This is the size of machine word in bytes, i.e. for 32 bit systems
it | | This is the size of machine word in bytes, i.e. for 32 bit systems
it | |
| should be defined to 4. | | should be defined to 4. | |
| | | | |
| skipping to change at line 192 | | skipping to change at line 193 | |
| }
\ | | }
\ | |
| | | | |
| #define __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(M)
\ | | #define __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(M)
\ | |
| inline int64_t __TBB_machine_generic_load8##M(const volatile void *ptr)
{ \ | | 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 */ \ | | /* 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'.*/ \ | | /* the value should have a low probability to be actually found in
'location'.*/ \ | |
| const int64_t anyvalue = 2305843009213693951LL;
\ | | const int64_t anyvalue = 2305843009213693951LL;
\ | |
| return __TBB_machine_cmpswp8##M(const_cast<volatile void *>(ptr),an
yvalue,anyvalue); \ | | return __TBB_machine_cmpswp8##M(const_cast<volatile void *>(ptr),an
yvalue,anyvalue); \ | |
| }
\ | | }
\ | |
| | | | |
|
| | | // The set of allowed values for __TBB_ENDIANNESS (see above for details) | |
| | | #define __TBB_ENDIAN_UNSUPPORTED -1 | |
| | | #define __TBB_ENDIAN_LITTLE 0 | |
| | | #define __TBB_ENDIAN_BIG 1 | |
| | | #define __TBB_ENDIAN_DETECT 2 | |
| | | | |
| #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 403 | | skipping to change at line 410 | |
| } | | } | |
| | | | |
| //! Spin UNTIL the value of the variable is equal to a given value | | //! Spin UNTIL the value of the variable is equal to a given value | |
| /** T and U should be comparable types. */ | | /** T and U should be comparable types. */ | |
| template<typename T, typename U> | | template<typename T, typename U> | |
| void spin_wait_until_eq( const volatile T& location, const U value ) { | | void spin_wait_until_eq( const volatile T& location, const U value ) { | |
| atomic_backoff backoff; | | atomic_backoff backoff; | |
| while( location!=value ) backoff.pause(); | | while( location!=value ) backoff.pause(); | |
| } | | } | |
| | | | |
|
| #if (__TBB_USE_GENERIC_PART_WORD_CAS && ( __TBB_BIG_ENDIAN==-1)) | | /////////////////////////////////////////////////////////////////////////// | |
| #error generic implementation of part-word CAS was explicitly disabled | | ///// | |
| for this configuration | | // Generic compare-and-swap applied to only a part of a machine word. | |
| | | // | |
| | | #ifndef __TBB_ENDIANNESS | |
| | | #define __TBB_ENDIANNESS __TBB_ENDIAN_DETECT | |
| | | #endif | |
| | | | |
| | | #if __TBB_USE_GENERIC_PART_WORD_CAS && __TBB_ENDIANNESS==__TBB_ENDIAN_UNSUP | |
| | | PORTED | |
| | | #error Generic implementation of part-word CAS may not be used with __TBB_E | |
| | | NDIAN_UNSUPPORTED | |
| #endif | | #endif | |
| | | | |
|
| #if (__TBB_BIG_ENDIAN!=-1) | | #if __TBB_ENDIANNESS!=__TBB_ENDIAN_UNSUPPORTED | |
| // there are following restrictions/limitations for this operation: | | // | |
| // - T should be unsigned, otherwise sign propagation will break correctne | | // This function is the only use of __TBB_ENDIANNESS. | |
| ss of bit manipulations. | | // The following restrictions/limitations apply for this operation: | |
| // - T should be integer type of at most 4 bytes, for the casts and calcul | | // - T must be an integer type of at most 4 bytes for the casts and calcul | |
| ations to work. | | ations to work | |
| // (Together, these rules limit applicability of Masked CAS to uint8_t | | // - T must also be less than 4 bytes to avoid compiler warnings when comp | |
| and uint16_t only, | | uting mask | |
| // as it does nothing useful for 4 bytes). | | // (and for the operation to be useful at all, so no workaround is app | |
| // - The operation assumes that the architecture consistently uses either | | lied) | |
| little-endian or big-endian: | | // - the architecture must consistently use either little-endian or big-en | |
| // it does not support mixed-endian or page-specific bi-endian archite | | dian (same for all locations) | |
| ctures. | | | |
| // This function is the only use of __TBB_BIG_ENDIAN. | | | |
| // | | // | |
|
| //TODO: add static_assert for the requirements stated above | | // TODO: static_assert for the type requirements stated above | |
| //TODO: check if it works with signed types | | | |
| template<typename T> | | template<typename T> | |
| inline T __TBB_MaskedCompareAndSwap (volatile T * const ptr, const T value,
const T comparand ) { | | inline T __TBB_MaskedCompareAndSwap (volatile T * const ptr, const T value,
const T comparand ) { | |
| struct endianness{ static bool is_big_endian(){ | | struct endianness{ static bool is_big_endian(){ | |
|
| #ifndef __TBB_BIG_ENDIAN | | #if __TBB_ENDIANNESS==__TBB_ENDIAN_DETECT | |
| const uint32_t probe = 0x03020100; | | const uint32_t probe = 0x03020100; | |
| return (((const char*)(&probe))[0]==0x03); | | return (((const char*)(&probe))[0]==0x03); | |
|
| #elif (__TBB_BIG_ENDIAN==0) || (__TBB_BIG_ENDIAN==1) | | #elif __TBB_ENDIANNESS==__TBB_ENDIAN_BIG || __TBB_ENDIANNESS==__TBB | |
| return __TBB_BIG_ENDIAN; | | _ENDIAN_LITTLE | |
| | | return __TBB_ENDIANNESS==__TBB_ENDIAN_BIG; | |
| #else | | #else | |
|
| #error unexpected value of __TBB_BIG_ENDIAN | | #error Unexpected value of __TBB_ENDIANNESS | |
| #endif | | #endif | |
| }}; | | }}; | |
| | | | |
| const uint32_t byte_offset = (uint32_t) ((uintptr_t)ptr & 0x
3); | | const uint32_t byte_offset = (uint32_t) ((uintptr_t)ptr & 0x
3); | |
| volatile uint32_t * const aligned_ptr = (uint32_t*)((uintptr_t)ptr - by
te_offset ); | | volatile uint32_t * const aligned_ptr = (uint32_t*)((uintptr_t)ptr - by
te_offset ); | |
| | | | |
| // location of T within uint32_t for a C++ shift operation | | // location of T within uint32_t for a C++ shift operation | |
| const uint32_t bits_to_shift = 8*(endianness::is_big_endian() ? (4
- sizeof(T) - (byte_offset)) : byte_offset); | | const uint32_t bits_to_shift = 8*(endianness::is_big_endian() ? (4
- sizeof(T) - (byte_offset)) : byte_offset); | |
| const uint32_t mask = (((uint32_t)1<<(sizeof(T)*8)) - 1 )<
<bits_to_shift; | | const uint32_t mask = (((uint32_t)1<<(sizeof(T)*8)) - 1 )<
<bits_to_shift; | |
|
| | | // for signed T, any sign extension bits in cast value/comparand are im
mediately clipped by mask | |
| const uint32_t shifted_comparand = ((uint32_t)comparand << bits_to_shif
t)&mask; | | const uint32_t shifted_comparand = ((uint32_t)comparand << bits_to_shif
t)&mask; | |
| const uint32_t shifted_value = ((uint32_t)value << bits_to_shif
t)&mask; | | const uint32_t shifted_value = ((uint32_t)value << bits_to_shif
t)&mask; | |
| | | | |
| for(atomic_backoff b;;b.pause()) { | | for(atomic_backoff b;;b.pause()) { | |
|
| const uint32_t surroundings = *aligned_ptr & ~mask ; // reload the
aligned_ptr value which might change during the pause | | const uint32_t surroundings = *aligned_ptr & ~mask ; // may have c
hanged during the pause | |
| const uint32_t big_comparand = surroundings | shifted_comparand ; | | const uint32_t big_comparand = surroundings | shifted_comparand ; | |
| const uint32_t big_value = surroundings | shifted_value ; | | const uint32_t big_value = surroundings | shifted_value ; | |
| // __TBB_machine_cmpswp4 presumed to have full fence. | | // __TBB_machine_cmpswp4 presumed to have full fence. | |
| // Cast shuts up /Wp64 warning | | // Cast shuts up /Wp64 warning | |
| const uint32_t big_result = (uint32_t)__TBB_machine_cmpswp4( aligne
d_ptr, big_value, big_comparand ); | | const uint32_t big_result = (uint32_t)__TBB_machine_cmpswp4( aligne
d_ptr, big_value, big_comparand ); | |
| if( big_result == big_comparand // CAS succeeded | | if( big_result == big_comparand // CAS succeeded | |
| || ((big_result ^ big_comparand) & mask) != 0) // CAS failed an
d the bits of interest have changed | | || ((big_result ^ big_comparand) & mask) != 0) // CAS failed an
d the bits of interest have changed | |
| { | | { | |
| return T((big_result & mask) >> bits_to_shift); | | return T((big_result & mask) >> bits_to_shift); | |
| } | | } | |
| else continue; // CAS failed bu
t the bits of interest were not changed | | else continue; // CAS failed bu
t the bits of interest were not changed | |
| } | | } | |
| } | | } | |
|
| #endif //__TBB_BIG_ENDIAN!=-1 | | #endif // __TBB_ENDIANNESS!=__TBB_ENDIAN_UNSUPPORTED | |
| | | /////////////////////////////////////////////////////////////////////////// | |
| | | ///// | |
| | | | |
| template<size_t S, typename T> | | template<size_t S, typename T> | |
| inline T __TBB_CompareAndSwapGeneric (volatile void *ptr, T value, T compar
and ); | | inline T __TBB_CompareAndSwapGeneric (volatile void *ptr, T value, T compar
and ); | |
| | | | |
| template<> | | template<> | |
| inline uint8_t __TBB_CompareAndSwapGeneric <1,uint8_t> (volatile void *ptr,
uint8_t value, uint8_t comparand ) { | | inline uint8_t __TBB_CompareAndSwapGeneric <1,uint8_t> (volatile void *ptr,
uint8_t value, uint8_t comparand ) { | |
| #if __TBB_USE_GENERIC_PART_WORD_CAS | | #if __TBB_USE_GENERIC_PART_WORD_CAS | |
| return __TBB_MaskedCompareAndSwap<uint8_t>((volatile uint8_t *)ptr,valu
e,comparand); | | return __TBB_MaskedCompareAndSwap<uint8_t>((volatile uint8_t *)ptr,valu
e,comparand); | |
| #else | | #else | |
| return __TBB_machine_cmpswp1(ptr,value,comparand); | | return __TBB_machine_cmpswp1(ptr,value,comparand); | |
| #endif | | #endif | |
| | | | |
| skipping to change at line 907 | | skipping to change at line 922 | |
| tbb::internal::atomic_backoff b; | | tbb::internal::atomic_backoff b; | |
| do { | | do { | |
| b.pause(); | | b.pause(); | |
| } while ( !__TBB_TryLockByte(flag) ); | | } while ( !__TBB_TryLockByte(flag) ); | |
| } | | } | |
| return 0; | | return 0; | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #ifndef __TBB_UnlockByte | | #ifndef __TBB_UnlockByte | |
|
| #define __TBB_UnlockByte __TBB_store_with_release | | #define __TBB_UnlockByte(addr) __TBB_store_with_release((addr),0) | |
| #endif | | #endif | |
| | | | |
| #ifndef __TBB_ReverseByte | | #ifndef __TBB_ReverseByte | |
| inline unsigned char __TBB_ReverseByte(unsigned char src) { | | inline unsigned char __TBB_ReverseByte(unsigned char src) { | |
| return tbb::internal::reverse<unsigned char>::byte_table[src]; | | return tbb::internal::reverse<unsigned char>::byte_table[src]; | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| template<typename T> | | template<typename T> | |
| T __TBB_ReverseBits(T src) { | | T __TBB_ReverseBits(T src) { | |
| | | | |
End of changes. 12 change blocks. |
| 39 lines changed or deleted | | 62 lines changed or added | |
|