_concurrent_queue_internal.h   _concurrent_queue_internal.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 38 skipping to change at line 38
#ifndef __TBB_concurrent_queue_internal_H #ifndef __TBB_concurrent_queue_internal_H
#define __TBB_concurrent_queue_internal_H #define __TBB_concurrent_queue_internal_H
#include "tbb_stddef.h" #include "tbb_stddef.h"
#include "tbb_machine.h" #include "tbb_machine.h"
#include "atomic.h" #include "atomic.h"
#include "spin_mutex.h" #include "spin_mutex.h"
#include "cache_aligned_allocator.h" #include "cache_aligned_allocator.h"
#include "tbb_exception.h" #include "tbb_exception.h"
#include <iterator>
#include <new> #include <new>
#if !TBB_USE_EXCEPTIONS && _MSC_VER
// Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers
#pragma warning (push)
#pragma warning (disable: 4530)
#endif
#include <iterator>
#if !TBB_USE_EXCEPTIONS && _MSC_VER
#pragma warning (pop)
#endif
namespace tbb { namespace tbb {
#if !__TBB_TEMPLATE_FRIENDS_BROKEN #if !__TBB_TEMPLATE_FRIENDS_BROKEN
// forward declaration // forward declaration
namespace strict_ppl { namespace strict_ppl {
template<typename T, typename A> class concurrent_queue; template<typename T, typename A> class concurrent_queue;
} }
template<typename T, typename A> class concurrent_bounded_queue; template<typename T, typename A> class concurrent_bounded_queue;
skipping to change at line 67 skipping to change at line 78
//! For internal use only. //! For internal use only.
namespace strict_ppl { namespace strict_ppl {
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
using namespace tbb::internal; using namespace tbb::internal;
typedef size_t ticket; typedef size_t ticket;
static void* invalid_page;
template<typename T> class micro_queue ; template<typename T> class micro_queue ;
template<typename T> class micro_queue_pop_finalizer ; template<typename T> class micro_queue_pop_finalizer ;
template<typename T> class concurrent_queue_base_v3; template<typename T> class concurrent_queue_base_v3;
//! parts of concurrent_queue_rep that do not have references to micro_queu e //! parts of concurrent_queue_rep that do not have references to micro_queu e
/** /**
* For internal use only. * For internal use only.
*/ */
struct concurrent_queue_rep_base : no_copy { struct concurrent_queue_rep_base : no_copy {
template<typename T> friend class micro_queue; template<typename T> friend class micro_queue;
skipping to change at line 112 skipping to change at line 121
//! Size of an item //! Size of an item
size_t item_size; size_t item_size;
//! number of invalid entries in the queue //! number of invalid entries in the queue
atomic<size_t> n_invalid_entries; atomic<size_t> n_invalid_entries;
char pad3[NFS_MaxLineSize-sizeof(size_t)-sizeof(size_t)-sizeof(atomic<s ize_t>)]; char pad3[NFS_MaxLineSize-sizeof(size_t)-sizeof(size_t)-sizeof(atomic<s ize_t>)];
} ; } ;
inline bool is_valid_page(const concurrent_queue_rep_base::page* p) {
return uintptr_t(p)>1;
}
//! Abstract class to define interface for page allocation/deallocation //! Abstract class to define interface for page allocation/deallocation
/** /**
* For internal use only. * For internal use only.
*/ */
class concurrent_queue_page_allocator class concurrent_queue_page_allocator
{ {
template<typename T> friend class micro_queue ; template<typename T> friend class micro_queue ;
template<typename T> friend class micro_queue_pop_finalizer ; template<typename T> friend class micro_queue_pop_finalizer ;
protected: protected:
virtual ~concurrent_queue_page_allocator() {} virtual ~concurrent_queue_page_allocator() {}
skipping to change at line 148 skipping to change at line 161
typedef concurrent_queue_rep_base::page page; typedef concurrent_queue_rep_base::page page;
//! Class used to ensure exception-safety of method "pop" //! Class used to ensure exception-safety of method "pop"
class destroyer: no_copy { class destroyer: no_copy {
T& my_value; T& my_value;
public: public:
destroyer( T& value ) : my_value(value) {} destroyer( T& value ) : my_value(value) {}
~destroyer() {my_value.~T();} ~destroyer() {my_value.~T();}
}; };
T& get_ref( page& page, size_t index ) {
return static_cast<T*>(static_cast<void*>(&page+1))[index];
}
void copy_item( page& dst, size_t index, const void* src ) { void copy_item( page& dst, size_t index, const void* src ) {
new( &get_ref(dst,index) ) T(*static_cast<const T*>(src)); new( &get_ref(dst,index) ) T(*static_cast<const T*>(src));
} }
void copy_item( page& dst, size_t dindex, const page& src, size_t sinde x ) { void copy_item( page& dst, size_t dindex, const page& src, size_t sinde x ) {
new( &get_ref(dst,dindex) ) T( static_cast<const T*>(static_cast<co nst void*>(&src+1))[sindex] ); new( &get_ref(dst,dindex) ) T( get_ref(const_cast<page&>(src),sinde x) );
} }
void assign_and_destroy_item( void* dst, page& src, size_t index ) { void assign_and_destroy_item( void* dst, page& src, size_t index ) {
T& from = get_ref(src,index); T& from = get_ref(src,index);
destroyer d(from); destroyer d(from);
*static_cast<T*>(dst) = from; *static_cast<T*>(dst) = from;
} }
void spin_wait_until_my_turn( atomic<ticket>& counter, ticket k, concur rent_queue_rep_base& rb ) const ; void spin_wait_until_my_turn( atomic<ticket>& counter, ticket k, concur rent_queue_rep_base& rb ) const ;
public: public:
friend class micro_queue_pop_finalizer<T>; friend class micro_queue_pop_finalizer<T>;
struct padded_page: page {
//! Not defined anywhere - exists to quiet warnings.
padded_page();
//! Not defined anywhere - exists to quiet warnings.
void operator=( const padded_page& );
//! Must be last field.
T last;
};
static T& get_ref( page& p, size_t index ) {
return (&static_cast<padded_page*>(static_cast<void*>(&p))->last)[i
ndex];
}
atomic<page*> head_page; atomic<page*> head_page;
atomic<ticket> head_counter; atomic<ticket> head_counter;
atomic<page*> tail_page; atomic<page*> tail_page;
atomic<ticket> tail_counter; atomic<ticket> tail_counter;
spin_mutex page_mutex; spin_mutex page_mutex;
void push( const void* item, ticket k, concurrent_queue_base_v3<T>& bas e ) ; void push( const void* item, ticket k, concurrent_queue_base_v3<T>& bas e ) ;
bool pop( void* dst, ticket k, concurrent_queue_base_v3<T>& base ) ; bool pop( void* dst, ticket k, concurrent_queue_base_v3<T>& base ) ;
micro_queue& assign( const micro_queue& src, concurrent_queue_base_v3<T >& base ) ; micro_queue& assign( const micro_queue& src, concurrent_queue_base_v3<T >& base ) ;
page* make_copy( concurrent_queue_base_v3<T>& base, const page* src_pag e, size_t begin_in_page, size_t end_in_page, ticket& g_index ) ; page* make_copy( concurrent_queue_base_v3<T>& base, const page* src_pag e, size_t begin_in_page, size_t end_in_page, ticket& g_index ) ;
void make_invalid( ticket k ) ; void invalidate_page_and_rethrow( ticket k ) ;
}; };
template<typename T> template<typename T>
void micro_queue<T>::spin_wait_until_my_turn( atomic<ticket>& counter, tick et k, concurrent_queue_rep_base& rb ) const { void micro_queue<T>::spin_wait_until_my_turn( atomic<ticket>& counter, tick et k, concurrent_queue_rep_base& rb ) const {
atomic_backoff backoff; atomic_backoff backoff;
do { do {
backoff.pause(); backoff.pause();
if( counter&0x1 ) { if( counter&1 ) {
++rb.n_invalid_entries; ++rb.n_invalid_entries;
throw_bad_last_alloc_exception_v4(); throw_exception( eid_bad_last_alloc );
} }
} while( counter!=k ) ; } while( counter!=k ) ;
} }
template<typename T> template<typename T>
void micro_queue<T>::push( const void* item, ticket k, concurrent_queue_bas e_v3<T>& base ) { void micro_queue<T>::push( const void* item, ticket k, concurrent_queue_bas e_v3<T>& base ) {
k &= -concurrent_queue_rep_base::n_queue; k &= -concurrent_queue_rep_base::n_queue;
page* p = NULL; page* p = NULL;
size_t index = k/concurrent_queue_rep_base::n_queue & (base.my_rep->ite ms_per_page-1); size_t index = k/concurrent_queue_rep_base::n_queue & (base.my_rep->ite ms_per_page-1);
if( !index ) { if( !index ) {
try { __TBB_TRY {
concurrent_queue_page_allocator& pa = base; concurrent_queue_page_allocator& pa = base;
p = pa.allocate_page(); p = pa.allocate_page();
} catch (...) { } __TBB_CATCH (...) {
++base.my_rep->n_invalid_entries; ++base.my_rep->n_invalid_entries;
make_invalid( k ); invalidate_page_and_rethrow( k );
} }
p->mask = 0; p->mask = 0;
p->next = NULL; p->next = NULL;
} }
if( tail_counter!=k ) spin_wait_until_my_turn( tail_counter, k, *base.m y_rep ); if( tail_counter!=k ) spin_wait_until_my_turn( tail_counter, k, *base.m y_rep );
if( p ) { if( p ) {
spin_mutex::scoped_lock lock( page_mutex ); spin_mutex::scoped_lock lock( page_mutex );
if( page* q = tail_page ) page* q = tail_page;
if( is_valid_page(q) )
q->next = p; q->next = p;
else else
head_page = p; head_page = p;
tail_page = p; tail_page = p;
} else { } else {
p = tail_page; p = tail_page;
} }
try { __TBB_TRY {
copy_item( *p, index, item ); copy_item( *p, index, item );
// If no exception was thrown, mark item as present. // If no exception was thrown, mark item as present.
p->mask |= uintptr_t(1)<<index; p->mask |= uintptr_t(1)<<index;
tail_counter += concurrent_queue_rep_base::n_queue; tail_counter += concurrent_queue_rep_base::n_queue;
} catch (...) { } __TBB_CATCH (...) {
++base.my_rep->n_invalid_entries; ++base.my_rep->n_invalid_entries;
tail_counter += concurrent_queue_rep_base::n_queue; tail_counter += concurrent_queue_rep_base::n_queue;
throw; __TBB_RETHROW();
} }
} }
template<typename T> template<typename T>
bool micro_queue<T>::pop( void* dst, ticket k, concurrent_queue_base_v3<T>& base ) { bool micro_queue<T>::pop( void* dst, ticket k, concurrent_queue_base_v3<T>& base ) {
k &= -concurrent_queue_rep_base::n_queue; k &= -concurrent_queue_rep_base::n_queue;
if( head_counter!=k ) spin_wait_until_eq( head_counter, k ); if( head_counter!=k ) spin_wait_until_eq( head_counter, k );
if( tail_counter==k ) spin_wait_while_eq( tail_counter, k ); if( tail_counter==k ) spin_wait_while_eq( tail_counter, k );
page& p = *head_page; page& p = *head_page;
__TBB_ASSERT( &p, NULL ); __TBB_ASSERT( &p, NULL );
skipping to change at line 272 skipping to change at line 295
return success; return success;
} }
template<typename T> template<typename T>
micro_queue<T>& micro_queue<T>::assign( const micro_queue<T>& src, concurre nt_queue_base_v3<T>& base ) { micro_queue<T>& micro_queue<T>::assign( const micro_queue<T>& src, concurre nt_queue_base_v3<T>& base ) {
head_counter = src.head_counter; head_counter = src.head_counter;
tail_counter = src.tail_counter; tail_counter = src.tail_counter;
page_mutex = src.page_mutex; page_mutex = src.page_mutex;
const page* srcp = src.head_page; const page* srcp = src.head_page;
if( srcp ) { if( is_valid_page(srcp) ) {
ticket g_index = head_counter; ticket g_index = head_counter;
try { __TBB_TRY {
size_t n_items = (tail_counter-head_counter)/concurrent_queue_ rep_base::n_queue; size_t n_items = (tail_counter-head_counter)/concurrent_queue_ rep_base::n_queue;
size_t index = head_counter/concurrent_queue_rep_base::n_queue & (base.my_rep->items_per_page-1); size_t index = head_counter/concurrent_queue_rep_base::n_queue & (base.my_rep->items_per_page-1);
size_t end_in_first_page = (index+n_items<base.my_rep->items_pe r_page)?(index+n_items):base.my_rep->items_per_page; size_t end_in_first_page = (index+n_items<base.my_rep->items_pe r_page)?(index+n_items):base.my_rep->items_per_page;
head_page = make_copy( base, srcp, index, end_in_first_page, g_ index ); head_page = make_copy( base, srcp, index, end_in_first_page, g_ index );
page* cur_page = head_page; page* cur_page = head_page;
if( srcp != src.tail_page ) { if( srcp != src.tail_page ) {
for( srcp = srcp->next; srcp!=src.tail_page; srcp=srcp->nex t ) { for( srcp = srcp->next; srcp!=src.tail_page; srcp=srcp->nex t ) {
cur_page->next = make_copy( base, srcp, 0, base.my_rep- >items_per_page, g_index ); cur_page->next = make_copy( base, srcp, 0, base.my_rep- >items_per_page, g_index );
skipping to change at line 296 skipping to change at line 319
} }
__TBB_ASSERT( srcp==src.tail_page, NULL ); __TBB_ASSERT( srcp==src.tail_page, NULL );
size_t last_index = tail_counter/concurrent_queue_rep_base: :n_queue & (base.my_rep->items_per_page-1); size_t last_index = tail_counter/concurrent_queue_rep_base: :n_queue & (base.my_rep->items_per_page-1);
if( last_index==0 ) last_index = base.my_rep->items_per_pag e; if( last_index==0 ) last_index = base.my_rep->items_per_pag e;
cur_page->next = make_copy( base, srcp, 0, last_index, g_in dex ); cur_page->next = make_copy( base, srcp, 0, last_index, g_in dex );
cur_page = cur_page->next; cur_page = cur_page->next;
} }
tail_page = cur_page; tail_page = cur_page;
} catch (...) { } __TBB_CATCH (...) {
make_invalid( g_index ); invalidate_page_and_rethrow( g_index );
} }
} else { } else {
head_page = tail_page = NULL; head_page = tail_page = NULL;
} }
return *this; return *this;
} }
template<typename T> template<typename T>
void micro_queue<T>::make_invalid( ticket k ) { void micro_queue<T>::invalidate_page_and_rethrow( ticket k ) {
static page dummy = {static_cast<page*>((void*)1), 0}; // Append an invalid page at address 1 so that no more pushes are allow
// mark it so that no more pushes are allowed. ed.
invalid_page = &dummy; page* invalid_page = (page*)uintptr_t(1);
{ {
spin_mutex::scoped_lock lock( page_mutex ); spin_mutex::scoped_lock lock( page_mutex );
tail_counter = k+concurrent_queue_rep_base::n_queue+1; tail_counter = k+concurrent_queue_rep_base::n_queue+1;
if( page* q = tail_page ) page* q = tail_page;
q->next = static_cast<page*>(invalid_page); if( is_valid_page(q) )
q->next = invalid_page;
else else
head_page = static_cast<page*>(invalid_page); head_page = invalid_page;
tail_page = static_cast<page*>(invalid_page); tail_page = invalid_page;
} }
throw; __TBB_RETHROW();
} }
template<typename T> template<typename T>
concurrent_queue_rep_base::page* micro_queue<T>::make_copy( concurrent_queu e_base_v3<T>& base, const concurrent_queue_rep_base::page* src_page, size_t begin_in_page, size_t end_in_page, ticket& g_index ) { concurrent_queue_rep_base::page* micro_queue<T>::make_copy( concurrent_queu e_base_v3<T>& base, const concurrent_queue_rep_base::page* src_page, size_t begin_in_page, size_t end_in_page, ticket& g_index ) {
concurrent_queue_page_allocator& pa = base; concurrent_queue_page_allocator& pa = base;
page* new_page = pa.allocate_page(); page* new_page = pa.allocate_page();
new_page->next = NULL; new_page->next = NULL;
new_page->mask = src_page->mask; new_page->mask = src_page->mask;
for( ; begin_in_page!=end_in_page; ++begin_in_page, ++g_index ) for( ; begin_in_page!=end_in_page; ++begin_in_page, ++g_index )
if( new_page->mask & uintptr_t(1)<<begin_in_page ) if( new_page->mask & uintptr_t(1)<<begin_in_page )
skipping to change at line 351 skipping to change at line 374
public: public:
micro_queue_pop_finalizer( micro_queue<T>& queue, concurrent_queue_base _v3<T>& b, ticket k, page* p ) : micro_queue_pop_finalizer( micro_queue<T>& queue, concurrent_queue_base _v3<T>& b, ticket k, page* p ) :
my_ticket(k), my_queue(queue), my_page(p), allocator(b) my_ticket(k), my_queue(queue), my_page(p), allocator(b)
{} {}
~micro_queue_pop_finalizer() ; ~micro_queue_pop_finalizer() ;
}; };
template<typename T> template<typename T>
micro_queue_pop_finalizer<T>::~micro_queue_pop_finalizer() { micro_queue_pop_finalizer<T>::~micro_queue_pop_finalizer() {
page* p = my_page; page* p = my_page;
if( p ) { if( is_valid_page(p) ) {
spin_mutex::scoped_lock lock( my_queue.page_mutex ); spin_mutex::scoped_lock lock( my_queue.page_mutex );
page* q = p->next; page* q = p->next;
my_queue.head_page = q; my_queue.head_page = q;
if( !q ) { if( !is_valid_page(q) ) {
my_queue.tail_page = NULL; my_queue.tail_page = NULL;
} }
} }
my_queue.head_counter = my_ticket; my_queue.head_counter = my_ticket;
if( p ) { if( is_valid_page(p) ) {
allocator.deallocate_page( p ); allocator.deallocate_page( p );
} }
} }
#if _MSC_VER && !defined(__INTEL_COMPILER) #if _MSC_VER && !defined(__INTEL_COMPILER)
#pragma warning( pop ) #pragma warning( pop )
#endif // warning 4146 is back #endif // warning 4146 is back
template<typename T> class concurrent_queue_iterator_rep ; template<typename T> class concurrent_queue_iterator_rep ;
template<typename T> class concurrent_queue_iterator_base_v3; template<typename T> class concurrent_queue_iterator_base_v3;
skipping to change at line 410 skipping to change at line 433
friend struct concurrent_queue_rep<T>; friend struct concurrent_queue_rep<T>;
friend class micro_queue<T>; friend class micro_queue<T>;
friend class concurrent_queue_iterator_rep<T>; friend class concurrent_queue_iterator_rep<T>;
friend class concurrent_queue_iterator_base_v3<T>; friend class concurrent_queue_iterator_base_v3<T>;
protected: protected:
typedef typename concurrent_queue_rep<T>::page page; typedef typename concurrent_queue_rep<T>::page page;
private: private:
typedef typename micro_queue<T>::padded_page padded_page;
/* override */ virtual page *allocate_page() { /* override */ virtual page *allocate_page() {
concurrent_queue_rep<T>& r = *my_rep; concurrent_queue_rep<T>& r = *my_rep;
size_t n = sizeof(page) + r.items_per_page*r.item_size; size_t n = sizeof(padded_page) + (r.items_per_page-1)*sizeof(T);
return reinterpret_cast<page*>(allocate_block ( n )); return reinterpret_cast<page*>(allocate_block ( n ));
} }
/* override */ virtual void deallocate_page( concurrent_queue_rep_base: :page *p ) { /* override */ virtual void deallocate_page( concurrent_queue_rep_base: :page *p ) {
concurrent_queue_rep<T>& r = *my_rep; concurrent_queue_rep<T>& r = *my_rep;
size_t n = sizeof(page) + r.items_per_page*r.item_size; size_t n = sizeof(padded_page) + (r.items_per_page-1)*sizeof(T);
deallocate_block( reinterpret_cast<void*>(p), n ); deallocate_block( reinterpret_cast<void*>(p), n );
} }
//! custom allocator //! custom allocator
virtual void *allocate_block( size_t n ) = 0; virtual void *allocate_block( size_t n ) = 0;
//! custom de-allocator //! custom de-allocator
virtual void deallocate_block( void *p, size_t n ) = 0; virtual void deallocate_block( void *p, size_t n ) = 0;
protected: protected:
concurrent_queue_base_v3( size_t item_size ) ; concurrent_queue_base_v3();
/* override */ virtual ~concurrent_queue_base_v3() { /* override */ virtual ~concurrent_queue_base_v3() {
#if __TBB_USE_ASSERT
size_t nq = my_rep->n_queue; size_t nq = my_rep->n_queue;
for( size_t i=0; i<nq; i++ ) for( size_t i=0; i<nq; i++ )
__TBB_ASSERT( my_rep->array[i].tail_page==NULL, "pages were not freed properly" ); __TBB_ASSERT( my_rep->array[i].tail_page==NULL, "pages were not freed properly" );
#endif /* __TBB_USE_ASSERT */
cache_aligned_allocator<concurrent_queue_rep<T> >().deallocate(my_r ep,1); cache_aligned_allocator<concurrent_queue_rep<T> >().deallocate(my_r ep,1);
} }
//! Enqueue item at tail of queue //! Enqueue item at tail of queue
void internal_push( const void* src ) { void internal_push( const void* src ) {
concurrent_queue_rep<T>& r = *my_rep; concurrent_queue_rep<T>& r = *my_rep;
ticket k = r.tail_counter++; ticket k = r.tail_counter++;
r.choose(k).push( src, k, *this ); r.choose(k).push( src, k, *this );
} }
skipping to change at line 459 skipping to change at line 486
//! Get size of queue; result may be invalid if queue is modified concu rrently //! Get size of queue; result may be invalid if queue is modified concu rrently
size_t internal_size() const ; size_t internal_size() const ;
//! check if the queue is empty; thread safe //! check if the queue is empty; thread safe
bool internal_empty() const ; bool internal_empty() const ;
//! free any remaining pages //! free any remaining pages
/* note that the name may be misleading, but it remains so due to a his torical accident. */ /* note that the name may be misleading, but it remains so due to a his torical accident. */
void internal_finish_clear() ; void internal_finish_clear() ;
//! throw an exception //! Obsolete
void internal_throw_exception() const { void internal_throw_exception() const {
throw std::bad_alloc(); throw_exception( eid_bad_alloc );
} }
//! copy internal representation //! copy internal representation
void assign( const concurrent_queue_base_v3& src ) ; void assign( const concurrent_queue_base_v3& src ) ;
}; };
template<typename T> template<typename T>
concurrent_queue_base_v3<T>::concurrent_queue_base_v3( size_t item_size ) { concurrent_queue_base_v3<T>::concurrent_queue_base_v3() {
const size_t item_size = sizeof(T);
my_rep = cache_aligned_allocator<concurrent_queue_rep<T> >().allocate(1 ); my_rep = cache_aligned_allocator<concurrent_queue_rep<T> >().allocate(1 );
__TBB_ASSERT( (size_t)my_rep % NFS_GetLineSize()==0, "alignment error" ); __TBB_ASSERT( (size_t)my_rep % NFS_GetLineSize()==0, "alignment error" );
__TBB_ASSERT( (size_t)&my_rep->head_counter % NFS_GetLineSize()==0, "al ignment error" ); __TBB_ASSERT( (size_t)&my_rep->head_counter % NFS_GetLineSize()==0, "al ignment error" );
__TBB_ASSERT( (size_t)&my_rep->tail_counter % NFS_GetLineSize()==0, "al ignment error" ); __TBB_ASSERT( (size_t)&my_rep->tail_counter % NFS_GetLineSize()==0, "al ignment error" );
__TBB_ASSERT( (size_t)&my_rep->array % NFS_GetLineSize()==0, "alignment error" ); __TBB_ASSERT( (size_t)&my_rep->array % NFS_GetLineSize()==0, "alignment error" );
memset(my_rep,0,sizeof(concurrent_queue_rep<T>)); memset(my_rep,0,sizeof(concurrent_queue_rep<T>));
my_rep->item_size = item_size; my_rep->item_size = item_size;
my_rep->items_per_page = item_size<=8 ? 32 : my_rep->items_per_page = item_size<=8 ? 32 :
item_size<=16 ? 16 : item_size<=16 ? 16 :
item_size<=32 ? 8 : item_size<=32 ? 8 :
skipping to change at line 541 skipping to change at line 569
// if tc!=r.tail_counter, the queue was not empty at some point between the two reads. // if tc!=r.tail_counter, the queue was not empty at some point between the two reads.
return tc==r.tail_counter && tc==hc+r.n_invalid_entries ; return tc==r.tail_counter && tc==hc+r.n_invalid_entries ;
} }
template<typename T> template<typename T>
void concurrent_queue_base_v3<T>::internal_finish_clear() { void concurrent_queue_base_v3<T>::internal_finish_clear() {
concurrent_queue_rep<T>& r = *my_rep; concurrent_queue_rep<T>& r = *my_rep;
size_t nq = r.n_queue; size_t nq = r.n_queue;
for( size_t i=0; i<nq; ++i ) { for( size_t i=0; i<nq; ++i ) {
page* tp = r.array[i].tail_page; page* tp = r.array[i].tail_page;
__TBB_ASSERT( r.array[i].head_page==tp, "at most one page should re if( is_valid_page(tp) ) {
main" ); __TBB_ASSERT( r.array[i].head_page==tp, "at most one page shoul
if( tp!=NULL) { d remain" );
if( tp!=invalid_page ) deallocate_page( tp ); deallocate_page( tp );
r.array[i].tail_page = NULL; r.array[i].tail_page = NULL;
} } else
__TBB_ASSERT( !is_valid_page(r.array[i].head_page), "head page
pointer corrupt?" );
} }
} }
template<typename T> template<typename T>
void concurrent_queue_base_v3<T>::assign( const concurrent_queue_base_v3& s rc ) { void concurrent_queue_base_v3<T>::assign( const concurrent_queue_base_v3& s rc ) {
concurrent_queue_rep<T>& r = *my_rep; concurrent_queue_rep<T>& r = *my_rep;
r.items_per_page = src.my_rep->items_per_page; r.items_per_page = src.my_rep->items_per_page;
// copy concurrent_queue_rep. // copy concurrent_queue_rep.
r.head_counter = src.my_rep->head_counter; r.head_counter = src.my_rep->head_counter;
skipping to change at line 571 skipping to change at line 600
r.array[i].assign( src.my_rep->array[i], *this); r.array[i].assign( src.my_rep->array[i], *this);
__TBB_ASSERT( r.head_counter==src.my_rep->head_counter && r.tail_counte r==src.my_rep->tail_counter, __TBB_ASSERT( r.head_counter==src.my_rep->head_counter && r.tail_counte r==src.my_rep->tail_counter,
"the source concurrent queue should not be concurrently modifie d." ); "the source concurrent queue should not be concurrently modifie d." );
} }
template<typename Container, typename Value> class concurrent_queue_iterato r; template<typename Container, typename Value> class concurrent_queue_iterato r;
template<typename T> template<typename T>
class concurrent_queue_iterator_rep: no_assign { class concurrent_queue_iterator_rep: no_assign {
typedef typename micro_queue<T>::padded_page padded_page;
public: public:
ticket head_counter; ticket head_counter;
const concurrent_queue_base_v3<T>& my_queue; const concurrent_queue_base_v3<T>& my_queue;
typename concurrent_queue_base_v3<T>::page* array[concurrent_queue_rep< T>::n_queue]; typename concurrent_queue_base_v3<T>::page* array[concurrent_queue_rep< T>::n_queue];
concurrent_queue_iterator_rep( const concurrent_queue_base_v3<T>& queue ) : concurrent_queue_iterator_rep( const concurrent_queue_base_v3<T>& queue ) :
head_counter(queue.my_rep->head_counter), head_counter(queue.my_rep->head_counter),
my_queue(queue) my_queue(queue)
{ {
for( size_t k=0; k<concurrent_queue_rep<T>::n_queue; ++k ) for( size_t k=0; k<concurrent_queue_rep<T>::n_queue; ++k )
array[k] = queue.my_rep->array[k].head_page; array[k] = queue.my_rep->array[k].head_page;
} }
//! Set item to point to kth element. Return true if at end of queue o r item is marked valid; false otherwise. //! Set item to point to kth element. Return true if at end of queue o r item is marked valid; false otherwise.
bool get_item( void*& item, size_t k ) ; bool get_item( T*& item, size_t k ) ;
}; };
template<typename T> template<typename T>
bool concurrent_queue_iterator_rep<T>::get_item( void*& item, size_t k ) { bool concurrent_queue_iterator_rep<T>::get_item( T*& item, size_t k ) {
if( k==my_queue.my_rep->tail_counter ) { if( k==my_queue.my_rep->tail_counter ) {
item = NULL; item = NULL;
return true; return true;
} else { } else {
typename concurrent_queue_base_v3<T>::page* p = array[concurrent_qu eue_rep<T>::index(k)]; typename concurrent_queue_base_v3<T>::page* p = array[concurrent_qu eue_rep<T>::index(k)];
__TBB_ASSERT(p,NULL); __TBB_ASSERT(p,NULL);
size_t i = k/concurrent_queue_rep<T>::n_queue & (my_queue.my_rep->i tems_per_page-1); size_t i = k/concurrent_queue_rep<T>::n_queue & (my_queue.my_rep->i tems_per_page-1);
item = static_cast<unsigned char*>(static_cast<void*>(p+1)) + my_qu eue.my_rep->item_size*i; item = &micro_queue<T>::get_ref(*p,i);
return (p->mask & uintptr_t(1)<<i)!=0; return (p->mask & uintptr_t(1)<<i)!=0;
} }
} }
//! Type-independent portion of concurrent_queue_iterator. //! Constness-independent portion of concurrent_queue_iterator.
/** @ingroup containers */ /** @ingroup containers */
template<typename Value> template<typename Value>
class concurrent_queue_iterator_base_v3 : no_assign { class concurrent_queue_iterator_base_v3 : no_assign {
//! Concurrentconcurrent_queue over which we are iterating. //! Concurrentconcurrent_queue over which we are iterating.
/** NULL if one past last element in queue. */ /** NULL if one past last element in queue. */
concurrent_queue_iterator_rep<Value>* my_rep; concurrent_queue_iterator_rep<Value>* my_rep;
template<typename C, typename T, typename U> template<typename C, typename T, typename U>
friend bool operator==( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j ); friend bool operator==( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j );
template<typename C, typename T, typename U> template<typename C, typename T, typename U>
friend bool operator!=( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j ); friend bool operator!=( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j );
protected: protected:
//! Pointer to current item //! Pointer to current item
mutable void* my_item; Value* my_item;
public:
//! Default constructor //! Default constructor
concurrent_queue_iterator_base_v3() : my_rep(NULL), my_item(NULL) { concurrent_queue_iterator_base_v3() : my_rep(NULL), my_item(NULL) {
#if __GNUC__==4&&__GNUC_MINOR__==3 #if __GNUC__==4&&__GNUC_MINOR__==3
// to get around a possible gcc 4.3 bug // to get around a possible gcc 4.3 bug
__asm__ __volatile__("": : :"memory"); __asm__ __volatile__("": : :"memory");
#endif #endif
} }
//! Copy constructor //! Copy constructor
concurrent_queue_iterator_base_v3( const concurrent_queue_iterator_base _v3& i ) : my_rep(NULL), my_item(NULL) { concurrent_queue_iterator_base_v3( const concurrent_queue_iterator_base _v3& i ) : my_rep(NULL), my_item(NULL) {
assign(i); assign(i);
} }
//! Construct iterator pointing to head of queue. //! Construct iterator pointing to head of queue.
concurrent_queue_iterator_base_v3( const concurrent_queue_base_v3<Value >& queue ) ; concurrent_queue_iterator_base_v3( const concurrent_queue_base_v3<Value >& queue ) ;
protected:
//! Assignment //! Assignment
void assign( const concurrent_queue_iterator_base_v3<Value>& other ) ; void assign( const concurrent_queue_iterator_base_v3<Value>& other ) ;
//! Advance iterator one step towards tail of queue. //! Advance iterator one step towards tail of queue.
void advance() ; void advance() ;
//! Destructor //! Destructor
~concurrent_queue_iterator_base_v3() { ~concurrent_queue_iterator_base_v3() {
cache_aligned_allocator<concurrent_queue_iterator_rep<Value> >().de allocate(my_rep, 1); cache_aligned_allocator<concurrent_queue_iterator_rep<Value> >().de allocate(my_rep, 1);
my_rep = NULL; my_rep = NULL;
skipping to change at line 678 skipping to change at line 706
} }
my_item = other.my_item; my_item = other.my_item;
} }
template<typename Value> template<typename Value>
void concurrent_queue_iterator_base_v3<Value>::advance() { void concurrent_queue_iterator_base_v3<Value>::advance() {
__TBB_ASSERT( my_item, "attempt to increment iterator past end of queue " ); __TBB_ASSERT( my_item, "attempt to increment iterator past end of queue " );
size_t k = my_rep->head_counter; size_t k = my_rep->head_counter;
const concurrent_queue_base_v3<Value>& queue = my_rep->my_queue; const concurrent_queue_base_v3<Value>& queue = my_rep->my_queue;
#if TBB_USE_ASSERT #if TBB_USE_ASSERT
void* tmp; Value* tmp;
my_rep->get_item(tmp,k); my_rep->get_item(tmp,k);
__TBB_ASSERT( my_item==tmp, NULL ); __TBB_ASSERT( my_item==tmp, NULL );
#endif /* TBB_USE_ASSERT */ #endif /* TBB_USE_ASSERT */
size_t i = k/concurrent_queue_rep<Value>::n_queue & (queue.my_rep->item s_per_page-1); size_t i = k/concurrent_queue_rep<Value>::n_queue & (queue.my_rep->item s_per_page-1);
if( i==queue.my_rep->items_per_page-1 ) { if( i==queue.my_rep->items_per_page-1 ) {
typename concurrent_queue_base_v3<Value>::page*& root = my_rep->arr ay[concurrent_queue_rep<Value>::index(k)]; typename concurrent_queue_base_v3<Value>::page*& root = my_rep->arr ay[concurrent_queue_rep<Value>::index(k)];
root = root->next; root = root->next;
} }
// advance k // advance k
my_rep->head_counter = ++k; my_rep->head_counter = ++k;
if( !my_rep->get_item(my_item, k) ) advance(); if( !my_rep->get_item(my_item, k) ) advance();
} }
template<typename T> //! Similar to C++0x std::remove_cv
static inline const concurrent_queue_iterator_base_v3<const T>& add_constne /** "tbb_" prefix added to avoid overload confusion with C++0x implementati
ss( const concurrent_queue_iterator_base_v3<T>& q ) ons. */
{ template<typename T> struct tbb_remove_cv {typedef T type;};
return *reinterpret_cast<const concurrent_queue_iterator_base_v3<const template<typename T> struct tbb_remove_cv<const T> {typedef T type;};
T> *>(&q) ; template<typename T> struct tbb_remove_cv<volatile T> {typedef T type;};
} template<typename T> struct tbb_remove_cv<const volatile T> {typedef T type
;};
//! Meets requirements of a forward iterator for STL. //! Meets requirements of a forward iterator for STL.
/** Value is either the T or const T type of the container. /** Value is either the T or const T type of the container.
@ingroup containers */ @ingroup containers */
template<typename Container, typename Value> template<typename Container, typename Value>
class concurrent_queue_iterator: public concurrent_queue_iterator_base_v3<V alue>, class concurrent_queue_iterator: public concurrent_queue_iterator_base_v3<t ypename tbb_remove_cv<Value>::type>,
public std::iterator<std::forward_iterator_tag,Value> { public std::iterator<std::forward_iterator_tag,Value> {
#if !__TBB_TEMPLATE_FRIENDS_BROKEN #if !__TBB_TEMPLATE_FRIENDS_BROKEN
template<typename T, class A> template<typename T, class A>
friend class ::tbb::strict_ppl::concurrent_queue; friend class ::tbb::strict_ppl::concurrent_queue;
#else #else
public: // workaround for MSVC public: // workaround for MSVC
#endif #endif
//! Construct iterator pointing to head of queue. //! Construct iterator pointing to head of queue.
concurrent_queue_iterator( const concurrent_queue_base_v3<Value>& queue ) : concurrent_queue_iterator( const concurrent_queue_base_v3<Value>& queue ) :
concurrent_queue_iterator_base_v3<Value>(queue) concurrent_queue_iterator_base_v3<typename tbb_remove_cv<Value>::ty pe>(queue)
{ {
} }
public: public:
concurrent_queue_iterator() {} concurrent_queue_iterator() {}
//! Copy constructor concurrent_queue_iterator( const concurrent_queue_iterator<Container,ty
concurrent_queue_iterator( const concurrent_queue_iterator<Container,Va pename Container::value_type>& other ) :
lue>& other ) : concurrent_queue_iterator_base_v3<typename tbb_remove_cv<Value>::ty
concurrent_queue_iterator_base_v3<Value>(other) pe>(other)
{ {}
}
template<typename T>
concurrent_queue_iterator( const concurrent_queue_iterator<Container,T>
& other ) :
concurrent_queue_iterator_base_v3<Value>(add_constness(other))
{
}
//! Iterator assignment //! Iterator assignment
concurrent_queue_iterator& operator=( const concurrent_queue_iterator& other ) { concurrent_queue_iterator& operator=( const concurrent_queue_iterator& other ) {
assign(other); assign(other);
return *this; return *this;
} }
//! Reference to current item //! Reference to current item
Value& operator*() const { Value& operator*() const {
return *static_cast<Value*>(this->my_item); return *static_cast<Value*>(this->my_item);
skipping to change at line 810 skipping to change at line 831
//! Capacity of the queue //! Capacity of the queue
ptrdiff_t my_capacity; ptrdiff_t my_capacity;
//! Always a power of 2 //! Always a power of 2
size_t items_per_page; size_t items_per_page;
//! Size of an item //! Size of an item
size_t item_size; size_t item_size;
#if __GNUC__==3&&__GNUC_MINOR__==3
public:
#endif /* __GNUC__==3&&__GNUC_MINOR__==3 */
template<typename T>
struct padded_page: page {
//! Not defined anywhere - exists to quiet warnings.
padded_page();
//! Not defined anywhere - exists to quiet warnings.
void operator=( const padded_page& );
//! Must be last field.
T last;
};
private: private:
virtual void copy_item( page& dst, size_t index, const void* src ) = 0; virtual void copy_item( page& dst, size_t index, const void* src ) = 0;
virtual void assign_and_destroy_item( void* dst, page& src, size_t inde x ) = 0; virtual void assign_and_destroy_item( void* dst, page& src, size_t inde x ) = 0;
protected: protected:
__TBB_EXPORTED_METHOD concurrent_queue_base_v3( size_t item_size ); __TBB_EXPORTED_METHOD concurrent_queue_base_v3( size_t item_size );
virtual __TBB_EXPORTED_METHOD ~concurrent_queue_base_v3(); virtual __TBB_EXPORTED_METHOD ~concurrent_queue_base_v3();
//! Enqueue item at tail of queue //! Enqueue item at tail of queue
void __TBB_EXPORTED_METHOD internal_push( const void* src ); void __TBB_EXPORTED_METHOD internal_push( const void* src );
skipping to change at line 862 skipping to change at line 896
//! copy internal representation //! copy internal representation
void __TBB_EXPORTED_METHOD assign( const concurrent_queue_base_v3& src ) ; void __TBB_EXPORTED_METHOD assign( const concurrent_queue_base_v3& src ) ;
private: private:
virtual void copy_page_item( page& dst, size_t dindex, const page& src, size_t sindex ) = 0; virtual void copy_page_item( page& dst, size_t dindex, const page& src, size_t sindex ) = 0;
}; };
//! Type-independent portion of concurrent_queue_iterator. //! Type-independent portion of concurrent_queue_iterator.
/** @ingroup containers */ /** @ingroup containers */
class concurrent_queue_iterator_base_v3 { class concurrent_queue_iterator_base_v3 {
//! Concurrentconcurrent_queue over which we are iterating. //! concurrent_queue over which we are iterating.
/** NULL if one past last element in queue. */ /** NULL if one past last element in queue. */
concurrent_queue_iterator_rep* my_rep; concurrent_queue_iterator_rep* my_rep;
template<typename C, typename T, typename U> template<typename C, typename T, typename U>
friend bool operator==( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j ); friend bool operator==( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j );
template<typename C, typename T, typename U> template<typename C, typename T, typename U>
friend bool operator!=( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j ); friend bool operator!=( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j );
void initialize( const concurrent_queue_base_v3& queue, size_t offset_o
f_data );
protected: protected:
//! Pointer to current item //! Pointer to current item
mutable void* my_item; void* my_item;
//! Default constructor //! Default constructor
concurrent_queue_iterator_base_v3() : my_rep(NULL), my_item(NULL) {} concurrent_queue_iterator_base_v3() : my_rep(NULL), my_item(NULL) {}
//! Copy constructor //! Copy constructor
concurrent_queue_iterator_base_v3( const concurrent_queue_iterator_base _v3& i ) : my_rep(NULL), my_item(NULL) { concurrent_queue_iterator_base_v3( const concurrent_queue_iterator_base _v3& i ) : my_rep(NULL), my_item(NULL) {
assign(i); assign(i);
} }
//! Construct iterator pointing to head of queue. //! Obsolete entry point for constructing iterator pointing to head of
queue.
/** Does not work correctly for SSE types. */
__TBB_EXPORTED_METHOD concurrent_queue_iterator_base_v3( const concurre nt_queue_base_v3& queue ); __TBB_EXPORTED_METHOD concurrent_queue_iterator_base_v3( const concurre nt_queue_base_v3& queue );
//! Construct iterator pointing to head of queue.
__TBB_EXPORTED_METHOD concurrent_queue_iterator_base_v3( const concurre
nt_queue_base_v3& queue, size_t offset_of_data );
//! Assignment //! Assignment
void __TBB_EXPORTED_METHOD assign( const concurrent_queue_iterator_base _v3& i ); void __TBB_EXPORTED_METHOD assign( const concurrent_queue_iterator_base _v3& i );
//! Advance iterator one step towards tail of queue. //! Advance iterator one step towards tail of queue.
void __TBB_EXPORTED_METHOD advance(); void __TBB_EXPORTED_METHOD advance();
//! Destructor //! Destructor
__TBB_EXPORTED_METHOD ~concurrent_queue_iterator_base_v3(); __TBB_EXPORTED_METHOD ~concurrent_queue_iterator_base_v3();
}; };
skipping to change at line 915 skipping to change at line 956
template<typename T, class A> template<typename T, class A>
friend class ::tbb::concurrent_bounded_queue; friend class ::tbb::concurrent_bounded_queue;
template<typename T, class A> template<typename T, class A>
friend class ::tbb::deprecated::concurrent_queue; friend class ::tbb::deprecated::concurrent_queue;
#else #else
public: // workaround for MSVC public: // workaround for MSVC
#endif #endif
//! Construct iterator pointing to head of queue. //! Construct iterator pointing to head of queue.
concurrent_queue_iterator( const concurrent_queue_base_v3& queue ) : concurrent_queue_iterator( const concurrent_queue_base_v3& queue ) :
concurrent_queue_iterator_base_v3(queue) concurrent_queue_iterator_base_v3(queue,__TBB_offsetof(concurrent_q ueue_base_v3::padded_page<Value>,last))
{ {
} }
public: public:
concurrent_queue_iterator() {} concurrent_queue_iterator() {}
/** If Value==Container::value_type, then this routine is the copy cons tructor. /** If Value==Container::value_type, then this routine is the copy cons tructor.
If Value==const Container::value_type, then this routine is a conve rsion constructor. */ If Value==const Container::value_type, then this routine is a conve rsion constructor. */
concurrent_queue_iterator( const concurrent_queue_iterator<Container,ty pename Container::value_type>& other ) : concurrent_queue_iterator( const concurrent_queue_iterator<Container,ty pename Container::value_type>& other ) :
concurrent_queue_iterator_base_v3(other) concurrent_queue_iterator_base_v3(other)
 End of changes. 59 change blocks. 
80 lines changed or deleted 127 lines changed or added


 _tbb_windef.h   _tbb_windef.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 42 skipping to change at line 42
// Check that the target Windows version has all API calls requried for TBB . // Check that the target Windows version has all API calls requried for TBB .
// Do not increase the version in condition beyond 0x0500 without prior dis cussion! // Do not increase the version in condition beyond 0x0500 without prior dis cussion!
#if defined(_WIN32_WINNT) && _WIN32_WINNT<0x0400 #if defined(_WIN32_WINNT) && _WIN32_WINNT<0x0400
#error TBB is unable to run on old Windows versions; _WIN32_WINNT must be 0 x0400 or greater. #error TBB is unable to run on old Windows versions; _WIN32_WINNT must be 0 x0400 or greater.
#endif #endif
#if !defined(_MT) #if !defined(_MT)
#error TBB requires linkage with multithreaded C/C++ runtime library. \ #error TBB requires linkage with multithreaded C/C++ runtime library. \
Choose multithreaded DLL runtime in project settings, or use /MD[d] compiler switch. Choose multithreaded DLL runtime in project settings, or use /MD[d] compiler switch.
#elif !defined(_DLL)
#pragma message("Warning: Using TBB together with static C/C++ runtime libr
ary is not recommended. " \
"Consider switching your project to multithreaded DLL runti
me used by TBB.")
#endif #endif
// Workaround for the problem with MVSC headers failing to define namespace std // Workaround for the problem with MVSC headers failing to define namespace std
namespace std { namespace std {
using ::size_t; using ::ptrdiff_t; using ::size_t; using ::ptrdiff_t;
} }
#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)
 End of changes. 2 change blocks. 
6 lines changed or deleted 1 lines changed or added


 aligned_space.h   aligned_space.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 atomic.h   atomic.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 blocked_range.h   blocked_range.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 60 skipping to change at line 60
//! Type of a value //! Type of a value
/** Called a const_iterator for sake of algorithms that need to treat a blocked_range /** Called a const_iterator for sake of algorithms that need to treat a blocked_range
as an STL container. */ as an STL container. */
typedef Value const_iterator; typedef Value const_iterator;
//! Type for size of a range //! Type for size of a range
typedef std::size_t size_type; typedef std::size_t size_type;
//! Construct range with default-constructed values for begin and end. //! Construct range with default-constructed values for begin and end.
/** Requires that Value have a default constructor. */ /** Requires that Value have a default constructor. */
blocked_range() : my_begin(), my_end() {} blocked_range() : my_end(), my_begin() {}
//! Construct range over half-open interval [begin,end), with the given grainsize. //! Construct range over half-open interval [begin,end), with the given grainsize.
blocked_range( Value begin_, Value end_, size_type grainsize_=1 ) : blocked_range( Value begin_, Value end_, size_type grainsize_=1 ) :
my_end(end_), my_begin(begin_), my_grainsize(grainsize_) my_end(end_), my_begin(begin_), my_grainsize(grainsize_)
{ {
__TBB_ASSERT( my_grainsize>0, "grainsize must be positive" ); __TBB_ASSERT( my_grainsize>0, "grainsize must be positive" );
} }
//! Beginning of range. //! Beginning of range.
const_iterator begin() const {return my_begin;} const_iterator begin() const {return my_begin;}
skipping to change at line 111 skipping to change at line 111
my_begin(do_split(r)), my_begin(do_split(r)),
my_grainsize(r.my_grainsize) my_grainsize(r.my_grainsize)
{} {}
private: private:
/** NOTE: my_end MUST be declared before my_begin, otherwise the forkin g constructor will break. */ /** NOTE: my_end MUST be declared before my_begin, otherwise the forkin g constructor will break. */
Value my_end; Value my_end;
Value my_begin; Value my_begin;
size_type my_grainsize; size_type my_grainsize;
//! Auxilary function used by forking constructor. //! Auxiliary function used by forking constructor.
/** Using this function lets us not require that Value support assignme nt or default construction. */ /** Using this function lets us not require that Value support assignme nt or default construction. */
static Value do_split( blocked_range& r ) { static Value do_split( blocked_range& r ) {
__TBB_ASSERT( r.is_divisible(), "cannot split blocked_range that is not divisible" ); __TBB_ASSERT( r.is_divisible(), "cannot split blocked_range that is not divisible" );
Value middle = r.my_begin + (r.my_end-r.my_begin)/2u; Value middle = r.my_begin + (r.my_end-r.my_begin)/2u;
r.my_end = middle; r.my_end = middle;
return middle; return middle;
} }
template<typename RowValue, typename ColValue> template<typename RowValue, typename ColValue>
friend class blocked_range2d; friend class blocked_range2d;
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 blocked_range2d.h   blocked_range2d.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 blocked_range3d.h   blocked_range3d.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 cache_aligned_allocator.h   cache_aligned_allocator.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 39 skipping to change at line 39
#ifndef __TBB_cache_aligned_allocator_H #ifndef __TBB_cache_aligned_allocator_H
#define __TBB_cache_aligned_allocator_H #define __TBB_cache_aligned_allocator_H
#include <new> #include <new>
#include "tbb_stddef.h" #include "tbb_stddef.h"
namespace tbb { namespace tbb {
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
//! Compile-time constant that is upper bound on cache line/sector size
.
/** It should be used only in situations where having a compile-time up
per
bound is more useful than a run-time exact answer.
@ingroup memory_allocation */
const size_t NFS_MaxLineSize = 128;
//! Cache/sector line size. //! Cache/sector line size.
/** @ingroup memory_allocation */ /** @ingroup memory_allocation */
size_t __TBB_EXPORTED_FUNC NFS_GetLineSize(); size_t __TBB_EXPORTED_FUNC NFS_GetLineSize();
//! Allocate memory on cache/sector line boundary. //! Allocate memory on cache/sector line boundary.
/** @ingroup memory_allocation */ /** @ingroup memory_allocation */
void* __TBB_EXPORTED_FUNC NFS_Allocate( size_t n_element, size_t elemen t_size, void* hint ); void* __TBB_EXPORTED_FUNC NFS_Allocate( size_t n_element, size_t elemen t_size, void* hint );
//! Free memory allocated by NFS_Allocate. //! Free memory allocated by NFS_Allocate.
/** Freeing a NULL pointer is allowed, but has no effect. /** Freeing a NULL pointer is allowed, but has no effect.
skipping to change at line 108 skipping to change at line 102
void deallocate( pointer p, size_type ) { void deallocate( pointer p, size_type ) {
internal::NFS_Free(p); internal::NFS_Free(p);
} }
//! Largest value for which method allocate might succeed. //! Largest value for which method allocate might succeed.
size_type max_size() const throw() { size_type max_size() const throw() {
return (~size_t(0)-internal::NFS_MaxLineSize)/sizeof(value_type); return (~size_t(0)-internal::NFS_MaxLineSize)/sizeof(value_type);
} }
//! Copy-construct value at location pointed to by p. //! Copy-construct value at location pointed to by p.
void construct( pointer p, const value_type& value ) {new(static_cast<v oid*>(p)) value_type(value);} void construct( pointer p, const value_type& value ) {::new((void*)(p)) value_type(value);}
//! Destroy value at location pointed to by p. //! Destroy value at location pointed to by p.
void destroy( pointer p ) {p->~value_type();} void destroy( pointer p ) {p->~value_type();}
}; };
#if _MSC_VER && !defined(__INTEL_COMPILER) #if _MSC_VER && !defined(__INTEL_COMPILER)
#pragma warning (pop) #pragma warning (pop)
#endif // warning 4100 is back #endif // warning 4100 is back
//! Analogous to std::allocator<void>, as defined in ISO C++ Standard, Sect ion 20.4.1 //! Analogous to std::allocator<void>, as defined in ISO C++ Standard, Sect ion 20.4.1
 End of changes. 3 change blocks. 
10 lines changed or deleted 2 lines changed or added


 combinable.h   combinable.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 70 skipping to change at line 70
combinable(const combinable& other) : my_ets(other.my_ets) { } combinable(const combinable& other) : my_ets(other.my_ets) { }
combinable & operator=( const combinable & other) { my_ets = other. my_ets; return *this; } combinable & operator=( const combinable & other) { my_ets = other. my_ets; return *this; }
void clear() { my_ets.clear(); } void clear() { my_ets.clear(); }
T& local() { return my_ets.local(); } T& local() { return my_ets.local(); }
T& local(bool & exists) { return my_ets.local(exists); } T& local(bool & exists) { return my_ets.local(exists); }
template< typename FCombine> // combine_func_t has signature T(T,T) or T(const T&, const T&)
T combine(FCombine fcombine) { return my_ets.combine(fcombine); } template <typename combine_func_t>
T combine(combine_func_t f_combine) { return my_ets.combine(f_combi
ne); }
template<typename FCombine> // combine_func_t has signature void(T) or void(const T&)
void combine_each(FCombine fcombine) { my_ets.combine_each(fcombine template <typename combine_func_t>
); } void combine_each(combine_func_t f_combine) { my_ets.combine_each(f
_combine); }
}; };
} // namespace tbb } // namespace tbb
#endif /* __TBB_combinable_H */ #endif /* __TBB_combinable_H */
 End of changes. 3 change blocks. 
6 lines changed or deleted 9 lines changed or added


 concurrent_hash_map.h   concurrent_hash_map.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 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_concurrent_hash_map_H #ifndef __TBB_concurrent_hash_map_H
#define __TBB_concurrent_hash_map_H #define __TBB_concurrent_hash_map_H
#include <stdexcept> #include "tbb_stddef.h"
#if !TBB_USE_EXCEPTIONS && _MSC_VER
// Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers
#pragma warning (push)
#pragma warning (disable: 4530)
#endif
#include <iterator> #include <iterator>
#include <utility> // Need std::pair #include <utility> // Need std::pair
#include <cstring> // Need std::memset #include <cstring> // Need std::memset
#include <string>
#include "tbb_stddef.h" #if !TBB_USE_EXCEPTIONS && _MSC_VER
#pragma warning (pop)
#endif
#include "cache_aligned_allocator.h" #include "cache_aligned_allocator.h"
#include "tbb_allocator.h" #include "tbb_allocator.h"
#include "spin_rw_mutex.h" #include "spin_rw_mutex.h"
#include "atomic.h" #include "atomic.h"
#include "aligned_space.h" #include "aligned_space.h"
#include "tbb_exception.h"
#include "_concurrent_unordered_internal.h" // Need tbb_hasher
#if TBB_USE_PERFORMANCE_WARNINGS #if TBB_USE_PERFORMANCE_WARNINGS
#include <typeinfo> #include <typeinfo>
#endif #endif
namespace tbb { namespace tbb {
template<typename T> struct tbb_hash_compare;
template<typename Key, typename T, typename HashCompare = tbb_hash_compare<
Key>, typename A = tbb_allocator<std::pair<Key, T> > >
class concurrent_hash_map;
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
//! ITT instrumented routine that loads pointer from location pointed t o by src. //! ITT instrumented routine that loads pointer from location pointed t o by src.
void* __TBB_EXPORTED_FUNC itt_load_pointer_with_acquire_v3( const void* src ); void* __TBB_EXPORTED_FUNC itt_load_pointer_with_acquire_v3( const void* src );
//! ITT instrumented routine that stores src into location pointed to b y dst. //! ITT instrumented routine that stores src into location pointed to b y dst.
void __TBB_EXPORTED_FUNC itt_store_pointer_with_release_v3( void* dst, void* src ); void __TBB_EXPORTED_FUNC itt_store_pointer_with_release_v3( void* dst, void* src );
//! Routine that loads pointer from location pointed to by src without causing ITT to report a race. //! Routine that loads pointer from location pointed to by src without causing ITT to report a race.
void* __TBB_EXPORTED_FUNC itt_load_pointer_v3( const void* src ); void* __TBB_EXPORTED_FUNC itt_load_pointer_v3( const void* src );
}
//! @endcond
//! hash_compare that is default argument for concurrent_hash_map
template<typename Key>
struct tbb_hash_compare {
static size_t hash( const Key& a ) { return tbb_hasher(a); }
static bool equal( const Key& a, const Key& b ) { return a == b; }
};
namespace interface4 {
template<typename Key, typename T, typename HashCompare = tbb_hash_comp
are<Key>, typename A = tbb_allocator<std::pair<Key, T> > >
class concurrent_hash_map;
//! @cond INTERNAL
namespace internal {
//! Type of a hash code. //! Type of a hash code.
typedef size_t hashcode_t; typedef size_t hashcode_t;
//! Node base type
struct hash_map_node_base : tbb::internal::no_copy {
//! Mutex type
typedef spin_rw_mutex mutex_t;
//! Scoped lock type for mutex
typedef mutex_t::scoped_lock scoped_t;
//! Next node in chain
hash_map_node_base *next;
mutex_t mutex;
};
//! Incompleteness flag value
static hash_map_node_base *const rehash_req = reinterpret_cast<hash_map
_node_base*>(size_t(3));
//! Rehashed empty bucket flag
static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash
_map_node_base*>(size_t(0));
//! base class of concurrent_hash_map //! base class of concurrent_hash_map
class hash_map_base { class hash_map_base {
public: public:
//! Size type //! Size type
typedef size_t size_type; typedef size_t size_type;
//! Type of a hash code. //! Type of a hash code.
typedef size_t hashcode_t; typedef size_t hashcode_t;
//! Segment index type //! Segment index type
typedef size_t segment_index_t; typedef size_t segment_index_t;
//! Node base type //! Node base type
struct node_base : no_copy { typedef hash_map_node_base node_base;
//! Mutex type
typedef spin_rw_mutex mutex_t;
//! Scoped lock type for mutex
typedef mutex_t::scoped_lock scoped_t;
//! Next node in chain
node_base *next;
mutex_t mutex;
};
//! Incompleteness flag value
# define __TBB_rehash_req reinterpret_cast<node_base*>(1)
//! Rehashed empty bucket flag
# define __TBB_empty_rehashed reinterpret_cast<node_base*>(0)
//! Bucket type //! Bucket type
struct bucket : no_copy { struct bucket : tbb::internal::no_copy {
//! Mutex type for buckets //! Mutex type for buckets
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;
mutex_t mutex; mutex_t mutex;
node_base *node_list; node_base *node_list;
}; };
//! Count of segments in the first block //! Count of segments in the first block
static size_type const embedded_block = 1; static size_type const embedded_block = 1;
//! Count of segments in the first block //! Count of segments in the first block
skipping to change at line 145 skipping to change at line 172
return (segment_index_t(1)<<k & ~segment_index_t(1)); return (segment_index_t(1)<<k & ~segment_index_t(1));
} }
//! @return segment size except for @arg k == 0 //! @return segment size except for @arg k == 0
static size_type segment_size( segment_index_t k ) { static size_type segment_size( segment_index_t k ) {
return size_type(1)<<k; // fake value for k==0 return size_type(1)<<k; // fake value for k==0
} }
//! @return true if @arg ptr is valid pointer //! @return true if @arg ptr is valid pointer
static bool is_valid( void *ptr ) { static bool is_valid( void *ptr ) {
return ptr > reinterpret_cast<void*>(1); return reinterpret_cast<size_t>(ptr) > size_t(63);
} }
//! Initialize buckets //! Initialize buckets
static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_ initial ) { static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_ initial ) {
if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) ); if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
else for(size_type i = 0; i < sz; i++, ptr++) { else for(size_type i = 0; i < sz; i++, ptr++) {
*reinterpret_cast<intptr_t*>(&ptr->mutex) = 0; *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
ptr->node_list = __TBB_rehash_req; ptr->node_list = rehash_req;
} }
} }
//! Add node @arg n to bucket @arg b //! Add node @arg n to bucket @arg b
static void add_to_bucket( bucket *b, node_base *n ) { static void add_to_bucket( bucket *b, node_base *n ) {
__TBB_ASSERT(b->node_list != rehash_req, NULL);
n->next = b->node_list; n->next = b->node_list;
b->node_list = n; // its under lock and flag is set b->node_list = n; // its under lock and flag is set
} }
//! Exception safety helper //! Exception safety helper
struct enable_segment_failsafe { struct enable_segment_failsafe {
segment_ptr_t *my_segment_ptr; segment_ptr_t *my_segment_ptr;
enable_segment_failsafe(segments_table_t &table, segment_index_ t k) : my_segment_ptr(&table[k]) {} enable_segment_failsafe(segments_table_t &table, segment_index_ t k) : my_segment_ptr(&table[k]) {}
~enable_segment_failsafe() { ~enable_segment_failsafe() {
if( my_segment_ptr ) *my_segment_ptr = 0; // indicate no al location in progress if( my_segment_ptr ) *my_segment_ptr = 0; // indicate no al location in progress
skipping to change at line 184 skipping to change at line 212
__TBB_ASSERT( k, "Zero segment must be embedded" ); __TBB_ASSERT( k, "Zero segment must be embedded" );
enable_segment_failsafe watchdog( my_table, k ); enable_segment_failsafe watchdog( my_table, k );
cache_aligned_allocator<bucket> alloc; cache_aligned_allocator<bucket> alloc;
size_type sz; size_type sz;
__TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignm ent"); __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignm ent");
if( k >= first_block ) { if( k >= first_block ) {
sz = segment_size( k ); sz = segment_size( k );
segment_ptr_t ptr = alloc.allocate( sz ); segment_ptr_t ptr = alloc.allocate( sz );
init_buckets( ptr, sz, is_initial ); init_buckets( ptr, sz, is_initial );
#if TBB_USE_THREADING_TOOLS #if TBB_USE_THREADING_TOOLS
// TODO: actually, fence and notification are unneccessary here and below // TODO: actually, fence and notification are unnecessary h ere and below
itt_store_pointer_with_release_v3( my_table + k, ptr ); itt_store_pointer_with_release_v3( my_table + k, ptr );
#else #else
my_table[k] = ptr;// my_mask has release fence my_table[k] = ptr;// my_mask has release fence
#endif #endif
sz <<= 1;// double it to get entire capacity of the contain er sz <<= 1;// double it to get entire capacity of the contain er
} else { // the first block } else { // the first block
__TBB_ASSERT( k == embedded_block, "Wrong segment index" ); __TBB_ASSERT( k == embedded_block, "Wrong segment index" );
sz = segment_size( first_block ); sz = segment_size( first_block );
segment_ptr_t ptr = alloc.allocate( sz - embedded_buckets ) ; segment_ptr_t ptr = alloc.allocate( sz - embedded_buckets ) ;
init_buckets( ptr, sz - embedded_buckets, is_initial ); init_buckets( ptr, sz - embedded_buckets, is_initial );
skipping to change at line 220 skipping to change at line 248
//! Get bucket by (masked) hashcode //! Get bucket by (masked) hashcode
bucket *get_bucket( hashcode_t h ) const throw() { // TODO: add thr ow() everywhere? bucket *get_bucket( hashcode_t h ) const throw() { // TODO: add thr ow() everywhere?
segment_index_t s = segment_index_of( h ); segment_index_t s = segment_index_of( h );
h -= segment_base(s); h -= segment_base(s);
segment_ptr_t seg = my_table[s]; segment_ptr_t seg = my_table[s];
__TBB_ASSERT( is_valid(seg), "hashcode must be cut by valid mas k for allocated segments" ); __TBB_ASSERT( is_valid(seg), "hashcode must be cut by valid mas k for allocated segments" );
return &seg[h]; return &seg[h];
} }
// internal serial rehashing helper
void mark_rehashed_levels( hashcode_t h ) throw () {
segment_index_t s = segment_index_of( h );
while( segment_ptr_t seg = my_table[++s] )
if( seg[h].node_list == rehash_req ) {
seg[h].node_list = empty_rehashed;
mark_rehashed_levels( h + segment_base(s) );
}
}
//! Check for mask race //! Check for mask race
// Splitting into two functions should help inlining // Splitting into two functions should help inlining
inline bool check_mask_race( const hashcode_t h, hashcode_t &m ) co nst { inline bool check_mask_race( const hashcode_t h, hashcode_t &m ) co nst {
hashcode_t m_now, m_old = m; hashcode_t m_now, m_old = m;
#if TBB_USE_THREADING_TOOLS #if TBB_USE_THREADING_TOOLS
m_now = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask ); m_now = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask );
#else #else
m_now = my_mask; m_now = my_mask;
#endif #endif
if( m_old != m_now ) if( m_old != m_now )
skipping to change at line 245 skipping to change at line 283
bool check_rehashing_collision( const hashcode_t h, hashcode_t m_ol d, hashcode_t m ) const { bool check_rehashing_collision( const hashcode_t h, hashcode_t m_ol d, hashcode_t m ) const {
__TBB_ASSERT(m_old != m, NULL); // TODO?: m arg could be optimi zed out by passing h = h&m __TBB_ASSERT(m_old != m, NULL); // TODO?: m arg could be optimi zed out by passing h = h&m
if( (h & m_old) != (h & m) ) { // mask changed for this hashcod e, rare event if( (h & m_old) != (h & m) ) { // mask changed for this hashcod e, rare event
// condition above proves that 'h' has some other bits set beside 'm_old' // condition above proves that 'h' has some other bits set beside 'm_old'
// find next applicable mask after m_old //TODO: look at bsl instruction // find next applicable mask after m_old //TODO: look at bsl instruction
for( ++m_old; !(h & m_old); m_old <<= 1 ); // at maximum fe w rounds depending on the first block size for( ++m_old; !(h & m_old); m_old <<= 1 ); // at maximum fe w rounds depending on the first block size
m_old = (m_old<<1) - 1; // get full mask from a bit m_old = (m_old<<1) - 1; // get full mask from a bit
__TBB_ASSERT((m_old&(m_old+1))==0 && m_old <= m, NULL); __TBB_ASSERT((m_old&(m_old+1))==0 && m_old <= m, NULL);
// check whether it is rehashing/ed // check whether it is rehashing/ed
#if TBB_USE_THREADING_TOOLS #if TBB_USE_THREADING_TOOLS
if( itt_load_pointer_with_acquire_v3(&( get_bucket(h & m_ol d)->node_list )) != __TBB_rehash_req ) if( itt_load_pointer_with_acquire_v3(&( get_bucket(h & m_ol d)->node_list )) != rehash_req )
#else #else
if( __TBB_load_with_acquire(get_bucket( h & m_old )->node_l ist) != __TBB_rehash_req ) if( __TBB_load_with_acquire(get_bucket( h & m_old )->node_l ist) != rehash_req )
#endif #endif
return true; return true;
} }
return false; return false;
} }
//! 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 = segment_index_of( mask+1 ); segment_index_t new_seg = segment_index_of( mask+1 );
__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");
#if TBB_USE_THREADING_TOOLS #if TBB_USE_THREADING_TOOLS
if( !itt_load_pointer_v3(my_table+new_seg) if( !itt_load_pointer_v3(my_table+new_seg)
#else #else
if( !my_table[new_seg] if( !my_table[new_seg]
#endif #endif
&& __TBB_CompareAndSwapW(&my_table[new_seg ], 1, 0) == 0 ) && __TBB_CompareAndSwapW(&my_table[new_seg], 2, 0) == 0 )
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 )
skipping to change at line 316 skipping to change at line 354
template<typename C, typename T, typename U> template<typename C, typename T, typename U>
friend bool operator==( const hash_map_iterator<C,T>& i, const hash _map_iterator<C,U>& j ); friend bool operator==( const hash_map_iterator<C,T>& i, const hash _map_iterator<C,U>& j );
template<typename C, typename T, typename U> template<typename C, typename T, typename U>
friend bool operator!=( const hash_map_iterator<C,T>& i, const hash _map_iterator<C,U>& j ); friend bool operator!=( const hash_map_iterator<C,T>& i, const hash _map_iterator<C,U>& j );
template<typename C, typename T, typename U> template<typename C, typename T, typename U>
friend ptrdiff_t operator-( const hash_map_iterator<C,T>& i, const hash_map_iterator<C,U>& j ); friend ptrdiff_t operator-( const hash_map_iterator<C,T>& i, const hash_map_iterator<C,U>& j );
template<typename C, typename U> template<typename C, typename U>
friend class internal::hash_map_iterator; friend class hash_map_iterator;
template<typename I> template<typename I>
friend class internal::hash_map_range; friend class hash_map_range;
void advance_to_next_bucket() { // TODO?: refactor to iterator_base class void advance_to_next_bucket() { // TODO?: refactor to iterator_base class
size_t k = my_index+1; size_t k = my_index+1;
while( my_bucket && k <= my_map->my_mask ) { while( my_bucket && k <= my_map->my_mask ) {
// Following test uses 2's-complement wizardry // Following test uses 2's-complement wizardry
if( k& (k-2) ) // not the begining of a segment if( k& (k-2) ) // not the beginning of a segment
++my_bucket; ++my_bucket;
else my_bucket = my_map->get_bucket( k ); else my_bucket = my_map->get_bucket( k );
my_node = static_cast<node*>( my_bucket->node_list ); my_node = static_cast<node*>( my_bucket->node_list );
if( hash_map_base::is_valid(my_node) ) { if( hash_map_base::is_valid(my_node) ) {
my_index = k; return; my_index = k; return;
} }
++k; ++k;
} }
my_bucket = 0; my_node = 0; my_index = k; // the end my_bucket = 0; my_node = 0; my_index = k; // the end
} }
#if !defined(_MSC_VER) || defined(__INTEL_COMPILER) #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
template<typename Key, typename T, typename HashCompare, typename A > template<typename Key, typename T, typename HashCompare, typename A >
friend class tbb::concurrent_hash_map; friend class interface4::concurrent_hash_map;
#else #else
public: // workaround public: // workaround
#endif #endif
//! concurrent_hash_map over which we are iterating. //! concurrent_hash_map over which we are iterating.
const Container *my_map; const Container *my_map;
//! Index in hash table for current item //! Index in hash table for current item
size_t my_index; size_t my_index;
//! Pointer to bucket //! Pointer to bucket
skipping to change at line 456 skipping to change at line 494
//! type conversion //! type conversion
template<typename U> template<typename U>
hash_map_range( hash_map_range<U>& r) : hash_map_range( hash_map_range<U>& r) :
my_begin(r.my_begin), my_begin(r.my_begin),
my_end(r.my_end), my_end(r.my_end),
my_midpoint(r.my_midpoint), my_midpoint(r.my_midpoint),
my_grainsize(r.my_grainsize) my_grainsize(r.my_grainsize)
{} {}
#if TBB_DEPRECATED #if TBB_DEPRECATED
//! Init range with iterators and grainsize specified //! Init range with iterators and grainsize specified
hash_map_range( const Iterator& begin_, const Iterator& end_, size_ type grainsize = 1 ) : hash_map_range( const Iterator& begin_, const Iterator& end_, size_ type grainsize_ = 1 ) :
my_begin(begin_), my_begin(begin_),
my_end(end_), my_end(end_),
my_grainsize(grainsize) my_grainsize(grainsize_)
{ {
if(!my_end.my_index && !my_end.my_bucket) // end if(!my_end.my_index && !my_end.my_bucket) // end
my_end.my_index = my_end.my_map->my_mask + 1; my_end.my_index = my_end.my_map->my_mask + 1;
set_midpoint(); set_midpoint();
__TBB_ASSERT( grainsize>0, "grainsize must be positive" ); __TBB_ASSERT( grainsize_>0, "grainsize must be positive" );
} }
#endif #endif
//! Init range with container and grainsize specified //! Init range with container and grainsize specified
hash_map_range( const map_type &map, size_type grainsize = 1 ) : hash_map_range( const map_type &map, size_type grainsize_ = 1 ) :
my_begin( Iterator( map, 0, map.my_embedded_segment, map.my_emb edded_segment->node_list ) ), my_begin( Iterator( map, 0, map.my_embedded_segment, map.my_emb edded_segment->node_list ) ),
my_end( Iterator( map, map.my_mask + 1, 0, 0 ) ), my_end( Iterator( map, map.my_mask + 1, 0, 0 ) ),
my_grainsize( grainsize ) my_grainsize( grainsize_ )
{ {
__TBB_ASSERT( grainsize>0, "grainsize must be positive" ); __TBB_ASSERT( grainsize_>0, "grainsize must be positive" );
set_midpoint(); set_midpoint();
} }
const Iterator& begin() const {return my_begin;} const Iterator& begin() const {return my_begin;}
const Iterator& end() const {return my_end;} const Iterator& end() const {return my_end;}
//! The grain size for this range. //! The grain size for this range.
size_type grainsize() const {return my_grainsize;} size_type grainsize() const {return my_grainsize;}
}; };
template<typename Iterator> template<typename Iterator>
void hash_map_range<Iterator>::set_midpoint() const { void hash_map_range<Iterator>::set_midpoint() const {
skipping to change at line 500 skipping to change at line 538
} else { } else {
my_midpoint = my_end; my_midpoint = my_end;
} }
__TBB_ASSERT( my_begin.my_index <= my_midpoint.my_index, __TBB_ASSERT( my_begin.my_index <= my_midpoint.my_index,
"my_begin is after my_midpoint" ); "my_begin is after my_midpoint" );
__TBB_ASSERT( my_midpoint.my_index <= my_end.my_index, __TBB_ASSERT( my_midpoint.my_index <= my_end.my_index,
"my_midpoint is after my_end" ); "my_midpoint is after my_end" );
__TBB_ASSERT( my_begin != my_midpoint || my_begin == my_end, __TBB_ASSERT( my_begin != my_midpoint || my_begin == my_end,
"[my_begin, my_midpoint) range should not be empty" ); "[my_begin, my_midpoint) range should not be empty" );
} }
} // namespace internal
//! @endcond
//! Hash multiplier
static const size_t hash_multiplier = sizeof(size_t)==4? 2654435769U : 1140
0714819323198485ULL;
//! Hasher functions
template<typename T>
inline static size_t tbb_hasher( const T& t ) {
return static_cast<size_t>( t ) * hash_multiplier;
}
template<typename P>
inline static size_t tbb_hasher( P* ptr ) {
size_t const h = reinterpret_cast<size_t>( ptr );
return (h >> 3) ^ h;
}
template<typename E, typename S, typename A>
inline static size_t tbb_hasher( const std::basic_string<E,S,A>& s ) {
size_t h = 0;
for( const E* c = s.c_str(); *c; c++ )
h = static_cast<size_t>(*c) ^ (h * hash_multiplier);
return h;
}
template<typename F, typename S>
inline static size_t tbb_hasher( const std::pair<F,S>& p ) {
return tbb_hasher(p.first) ^ tbb_hasher(p.second);
}
//! hash_compare - default argument } // internal
template<typename T> //! @endcond
struct tbb_hash_compare {
static size_t hash( const T& t ) { return tbb_hasher(t); }
static bool equal( const T& a, const T& b ) { return a == b; }
};
//! Unordered map from Key to T. //! Unordered map from Key to T.
/** concurrent_hash_map is associative container with concurrent access. /** concurrent_hash_map is associative container with concurrent access.
@par Compatibility @par Compatibility
The class meets all Container Requirements from C++ Standard (See ISO/I EC 14882:2003(E), clause 23.1). The class meets all Container Requirements from C++ Standard (See ISO/I EC 14882:2003(E), clause 23.1).
@par Exception Safety @par Exception Safety
- Hash function is not permitted to throw an exception. User-defined ty pes Key and T are forbidden from throwing an exception in destructors. - Hash function is not permitted to throw an exception. User-defined ty pes Key and T are forbidden from throwing an exception in destructors.
- If exception happens during insert() operations, it has no effect (un less exception raised by HashCompare::hash() function during grow_segment). - If exception happens during insert() operations, it has no effect (un less exception raised by HashCompare::hash() function during grow_segment).
- If exception happens during operator=() operation, the container can have a part of source items, and methods size() and empty() can return wron g results. - If exception happens during operator=() operation, the container can have a part of source items, and methods size() and empty() can return wron g results.
@par Changes since TBB 2.1 @par Changes since TBB 2.1
- Replaced internal algorithm and data structure. Patent is pending. - Replaced internal algorithm and data structure. Patent is pending.
- Added buckets number argument for constructor
@par Changes since TBB 2.0 @par Changes since TBB 2.0
- Fixed exception-safety - Fixed exception-safety
- Added template argument for allocator - Added template argument for allocator
- Added allocator argument in constructors - Added allocator argument in constructors
- Added constructor from a range of iterators - Added constructor from a range of iterators
- Added several new overloaded insert() methods - Added several new overloaded insert() methods
- Added get_allocator() - Added get_allocator()
- Added swap() - Added swap()
- Added count() - Added count()
skipping to change at line 575 skipping to change at line 584
template<typename Container, typename Value> template<typename Container, typename Value>
friend class internal::hash_map_iterator; friend class internal::hash_map_iterator;
template<typename I> template<typename I>
friend class internal::hash_map_range; friend class internal::hash_map_range;
public: public:
typedef Key key_type; typedef Key key_type;
typedef T mapped_type; typedef T mapped_type;
typedef std::pair<const Key,T> value_type; typedef std::pair<const Key,T> value_type;
typedef internal::hash_map_base::size_type size_type; typedef hash_map_base::size_type size_type;
typedef ptrdiff_t difference_type; typedef ptrdiff_t difference_type;
typedef value_type *pointer; typedef value_type *pointer;
typedef const value_type *const_pointer; typedef const value_type *const_pointer;
typedef value_type &reference; typedef value_type &reference;
typedef const value_type &const_reference; typedef const value_type &const_reference;
typedef internal::hash_map_iterator<concurrent_hash_map,value_type> ite rator; typedef internal::hash_map_iterator<concurrent_hash_map,value_type> ite rator;
typedef internal::hash_map_iterator<concurrent_hash_map,const value_typ e> const_iterator; typedef internal::hash_map_iterator<concurrent_hash_map,const value_typ e> const_iterator;
typedef internal::hash_map_range<iterator> range_type; typedef internal::hash_map_range<iterator> range_type;
typedef internal::hash_map_range<const_iterator> const_range_type; typedef internal::hash_map_range<const_iterator> const_range_type;
typedef Allocator allocator_type; typedef Allocator allocator_type;
skipping to change at line 601 skipping to change at line 610
node_allocator_type my_allocator; node_allocator_type my_allocator;
HashCompare my_hash_compare; HashCompare my_hash_compare;
struct node : public node_base { struct node : public node_base {
value_type item; value_type item;
node( const Key &key ) : item(key, T()) {} node( const Key &key ) : item(key, T()) {}
node( const Key &key, const T &t ) : item(key, t) {} node( const Key &key, const T &t ) : item(key, t) {}
// exception-safe allocation, see C++ Standard 2003, clause 5.3.4p1 7 // exception-safe allocation, see C++ Standard 2003, clause 5.3.4p1 7
void *operator new( size_t /*size*/, node_allocator_type &a ) { void *operator new( size_t /*size*/, node_allocator_type &a ) {
void *ptr = a.allocate(1); void *ptr = a.allocate(1);
if(!ptr) throw std::bad_alloc(); if(!ptr)
tbb::internal::throw_exception(tbb::internal::eid_bad_alloc
);
return ptr; return ptr;
} }
// match placement-new form above to be called if exception thrown in constructor // match placement-new form above to be called if exception thrown in constructor
void operator delete( void *ptr, node_allocator_type &a ) {return a .deallocate(static_cast<node*>(ptr),1); } void operator delete( void *ptr, node_allocator_type &a ) {return a .deallocate(static_cast<node*>(ptr),1); }
}; };
void delete_node( node_base *n ) { void delete_node( node_base *n ) {
my_allocator.destroy( static_cast<node*>(n) ); my_allocator.destroy( static_cast<node*>(n) );
my_allocator.deallocate( static_cast<node*>(n), 1); my_allocator.deallocate( static_cast<node*>(n), 1);
} }
node *search_bucket( const key_type &key, bucket *b ) const { node *search_bucket( const key_type &key, bucket *b ) const {
node *n = static_cast<node*>( b->node_list ); node *n = static_cast<node*>( b->node_list );
while( is_valid(n) && !my_hash_compare.equal(key, n->item.first) ) while( is_valid(n) && !my_hash_compare.equal(key, n->item.first) )
n = static_cast<node*>( n->next ); n = static_cast<node*>( n->next );
__TBB_ASSERT(n != __TBB_rehash_req, "Search can be executed only fo r rehashed bucket"); __TBB_ASSERT(n != internal::rehash_req, "Search can be executed onl y for rehashed bucket");
return n; return n;
} }
//! bucket accessor is to find, rehash, acquire a lock, and access a bu cket //! bucket accessor is to find, rehash, acquire a lock, and access a bu cket
class bucket_accessor : public bucket::scoped_t { class bucket_accessor : public bucket::scoped_t {
bool my_is_writer; // TODO: use it from base type bool my_is_writer; // TODO: use it from base type
bucket *my_b; bucket *my_b;
public: public:
bucket_accessor( concurrent_hash_map *base, const hashcode_t h, boo l writer = false ) { acquire( base, h, writer ); } bucket_accessor( concurrent_hash_map *base, const hashcode_t h, boo l writer = false ) { acquire( base, h, writer ); }
//! find a bucket by maksed hashcode, optionally rehash, and acquir e the lock //! find a bucket by masked hashcode, optionally rehash, and acquir e the lock
inline void acquire( concurrent_hash_map *base, const hashcode_t h, bool writer = false ) { inline void acquire( concurrent_hash_map *base, const hashcode_t h, bool writer = false ) {
my_b = base->get_bucket( h ); my_b = base->get_bucket( h );
#if TBB_USE_THREADING_TOOLS #if TBB_USE_THREADING_TOOLS
// TODO: actually, notification is unneccessary here, just hidi // TODO: actually, notification is unnecessary here, just hidin
ng double-check g double-check
if( itt_load_pointer_with_acquire_v3(&my_b->node_list) == __TBB if( itt_load_pointer_with_acquire_v3(&my_b->node_list) == inter
_rehash_req nal::rehash_req
#else #else
if( __TBB_load_with_acquire(my_b->node_list) == __TBB_rehash_re q if( __TBB_load_with_acquire(my_b->node_list) == internal::rehas h_req
#endif #endif
&& try_acquire( my_b->mutex, /*write=*/true ) ) && try_acquire( my_b->mutex, /*write=*/true ) )
{ {
if( my_b->node_list == __TBB_rehash_req ) base->rehash_buck et( my_b, h ); //recursive rehashing if( my_b->node_list == internal::rehash_req ) base->rehash_ bucket( my_b, h ); //recursive rehashing
my_is_writer = true; my_is_writer = true;
} }
else bucket::scoped_t::acquire( my_b->mutex, /*write=*/my_is_wr iter = writer ); else bucket::scoped_t::acquire( my_b->mutex, /*write=*/my_is_wr iter = writer );
__TBB_ASSERT( my_b->node_list != __TBB_rehash_req, NULL); __TBB_ASSERT( my_b->node_list != internal::rehash_req, NULL);
} }
//! check whether bucket is locked for write //! check whether bucket is locked for write
bool is_writer() { return my_is_writer; } bool is_writer() { return my_is_writer; }
//! get bucket pointer //! get bucket pointer
bucket *operator() () { return my_b; } bucket *operator() () { return my_b; }
// TODO: optimize out // TODO: optimize out
bool upgrade_to_writer() { my_is_writer = true; return bucket::scop ed_t::upgrade_to_writer(); } bool upgrade_to_writer() { my_is_writer = true; return bucket::scop ed_t::upgrade_to_writer(); }
}; };
// TODO refactor to hash_base // TODO refactor to hash_base
void rehash_bucket( bucket *b_new, const hashcode_t h ) { void rehash_bucket( bucket *b_new, const hashcode_t h ) {
__TBB_ASSERT( *(intptr_t*)(&b_new->mutex), "b_new must be locked (f or write)"); __TBB_ASSERT( *(intptr_t*)(&b_new->mutex), "b_new must be locked (f or write)");
__TBB_ASSERT( h > 1, "The lowermost buckets can't be rehashed" ); __TBB_ASSERT( h > 1, "The lowermost buckets can't be rehashed" );
__TBB_store_with_release(b_new->node_list, __TBB_empty_rehashed); / / mark rehashed __TBB_store_with_release(b_new->node_list, internal::empty_rehashed ); // mark rehashed
hashcode_t mask = ( 1u<<__TBB_Log2( h ) ) - 1; // get parent mask f rom the topmost bit hashcode_t mask = ( 1u<<__TBB_Log2( h ) ) - 1; // get parent mask f rom the topmost bit
bucket_accessor b_old( this, h & mask ); bucket_accessor b_old( this, h & mask );
mask = (mask<<1) | 1; // get full mask for new bucket mask = (mask<<1) | 1; // get full mask for new bucket
__TBB_ASSERT( (mask&(mask+1))==0 && (h & mask) == h, NULL ); __TBB_ASSERT( (mask&(mask+1))==0 && (h & mask) == h, NULL );
restart: restart:
for( node_base **p = &b_old()->node_list, *n = __TBB_load_with_acqu ire(*p); is_valid(n); n = *p ) { for( node_base **p = &b_old()->node_list, *n = __TBB_load_with_acqu ire(*p); is_valid(n); n = *p ) {
hashcode_t c = my_hash_compare.hash( static_cast<node*>(n)->ite m.first ); hashcode_t c = my_hash_compare.hash( static_cast<node*>(n)->ite m.first );
#if TBB_USE_ASSERT
hashcode_t bmask = h & (mask>>1);
bmask = bmask==0? 1 : ( 1u<<(__TBB_Log2( bmask )+1 ) ) - 1; //
minimal mask of parent bucket
__TBB_ASSERT( (c & bmask) == (h & bmask), "hash() function chan
ged for key in table" );
#endif
if( (c & mask) == h ) { if( (c & mask) == h ) {
if( !b_old.is_writer() ) if( !b_old.is_writer() )
if( !b_old.upgrade_to_writer() ) { if( !b_old.upgrade_to_writer() ) {
goto restart; // node ptr can be invalid due to con current erase goto restart; // node ptr can be invalid due to con current erase
} }
*p = n->next; // exclude from b_old *p = n->next; // exclude from b_old
add_to_bucket( b_new, n ); add_to_bucket( b_new, n );
} else p = &n->next; // iterate to next item } else p = &n->next; // iterate to next item
} }
} }
skipping to change at line 748 skipping to change at line 763
pointer operator->() const { pointer operator->() const {
return &operator*(); return &operator*();
} }
}; };
//! Construct empty table. //! Construct empty table.
concurrent_hash_map(const allocator_type &a = allocator_type()) concurrent_hash_map(const allocator_type &a = allocator_type())
: my_allocator(a) : my_allocator(a)
{} {}
//! Construct empty table with n preallocated buckets. This number serv
es also as initial concurrency level.
concurrent_hash_map(size_type n, const allocator_type &a = allocator_ty
pe())
: my_allocator(a)
{
reserve( n );
}
//! Copy constructor //! Copy constructor
concurrent_hash_map( const concurrent_hash_map& table, const allocator_ type &a = allocator_type()) concurrent_hash_map( const concurrent_hash_map& table, const allocator_ type &a = allocator_type())
: my_allocator(a) : my_allocator(a)
{ {
internal_copy(table); internal_copy(table);
} }
//! Construction with copying iteration range and given allocator insta nce //! Construction with copying iteration range and given allocator insta nce
template<typename I> template<typename I>
concurrent_hash_map(I first, I last, const allocator_type &a = allocato r_type()) concurrent_hash_map(I first, I last, const allocator_type &a = allocato r_type())
skipping to change at line 773 skipping to change at line 795
//! Assignment //! Assignment
concurrent_hash_map& operator=( const concurrent_hash_map& table ) { concurrent_hash_map& operator=( const concurrent_hash_map& table ) {
if( this!=&table ) { if( this!=&table ) {
clear(); clear();
internal_copy(table); internal_copy(table);
} }
return *this; return *this;
} }
//! Rehashes and optionally resizes the whole table.
/** Useful to optimize performance before or after concurrent operation
s.
Also enables using of find() and count() concurrent methods in seri
al context. */
void rehash(size_type n = 0);
//! Clear table //! Clear table
void clear(); void clear();
//! Clear table and destroy it. //! Clear table and destroy it.
~concurrent_hash_map() { clear(); } ~concurrent_hash_map() { clear(); }
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
// Parallel algorithm support // Parallel algorithm support
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
range_type range( size_type grainsize=1 ) { range_type range( size_type grainsize=1 ) {
skipping to change at line 808 skipping to change at line 835
//! Number of items in table. //! Number of items in table.
size_type size() const { return my_size; } size_type size() const { return my_size; }
//! True if size()==0. //! True if size()==0.
bool empty() const { return my_size == 0; } bool empty() const { return my_size == 0; }
//! Upper bound on size. //! Upper bound on size.
size_type max_size() const {return (~size_type(0))/sizeof(node);} size_type max_size() const {return (~size_type(0))/sizeof(node);}
//! Returns the current number of buckets
size_type bucket_count() const { return my_mask+1; }
//! return allocator object //! return allocator object
allocator_type get_allocator() const { return this->my_allocator; } allocator_type get_allocator() const { return this->my_allocator; }
//! swap two instances. Iterators are invalidated //! swap two instances. Iterators are invalidated
void swap(concurrent_hash_map &table); void swap(concurrent_hash_map &table);
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
// concurrent map operations // concurrent map operations
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
skipping to change at line 911 skipping to change at line 941
//! Returns an iterator for an item defined by the key, or for the next item after it (if upper==true) //! Returns an iterator for an item defined by the key, or for the next item after it (if upper==true)
template<typename I> template<typename I>
std::pair<I, I> internal_equal_range( const Key& key, I end ) const; std::pair<I, I> internal_equal_range( const Key& key, I end ) const;
//! Copy "source" to *this, where *this must start out empty. //! Copy "source" to *this, where *this must start out empty.
void internal_copy( const concurrent_hash_map& source ); void internal_copy( const concurrent_hash_map& source );
template<typename I> template<typename I>
void internal_copy(I first, I last); void internal_copy(I first, I last);
//! fast find when no concurrent erasure is used //! Fast find when no concurrent erasure is used. For internal use insi
const_pointer find( const Key& key ) const { de TBB only!
/** Return pointer to item with given key, or NULL if no such item exis
ts.
Must not be called concurrently with erasure operations. */
const_pointer internal_fast_find( const Key& key ) const {
hashcode_t h = my_hash_compare.hash( key ); hashcode_t h = my_hash_compare.hash( key );
#if TBB_USE_THREADING_TOOLS
hashcode_t m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_m
ask );
#else
hashcode_t m = my_mask; hashcode_t m = my_mask;
#endif
node *n;
restart: restart:
__TBB_ASSERT((m&(m+1))==0, NULL); __TBB_ASSERT((m&(m+1))==0, NULL);
bucket *b = get_bucket( h & m ); bucket *b = get_bucket( h & m );
if( b->node_list == __TBB_rehash_req ) { #if TBB_USE_THREADING_TOOLS
// TODO: actually, notification is unnecessary here, just hiding do
uble-check
if( itt_load_pointer_with_acquire_v3(&b->node_list) == internal::re
hash_req )
#else
if( __TBB_load_with_acquire(b->node_list) == internal::rehash_req )
#endif
{
bucket::scoped_t lock; bucket::scoped_t lock;
if( lock.try_acquire( b->mutex, /*write=*/true ) && b->node_lis if( lock.try_acquire( b->mutex, /*write=*/true ) ) {
t == __TBB_rehash_req ) if( b->node_list == internal::rehash_req)
const_cast<concurrent_hash_map*>(this)->rehash_bucket( b, h const_cast<concurrent_hash_map*>(this)->rehash_bucket(
& m ); //recursive rehashing b, h & m ); //recursive rehashing
else internal::spin_wait_while_eq( b->node_list, __TBB_rehash_r }
eq ); //TODO: rework for fast find? else lock.acquire( b->mutex, /*write=*/false );
__TBB_ASSERT(b->node_list!=internal::rehash_req,NULL);
} }
node *n = search_bucket( key, b ); n = search_bucket( key, b );
if( check_mask_race( h, m ) )
goto restart;
if( n ) if( n )
return &n->item; return &n->item;
else if( check_mask_race( h, m ) )
goto restart;
return 0; return 0;
} }
}; };
#if _MSC_VER && !defined(__INTEL_COMPILER) #if _MSC_VER && !defined(__INTEL_COMPILER)
// Suppress "conditional expression is constant" warning. // Suppress "conditional expression is constant" warning.
#pragma warning( push ) #pragma warning( push )
#pragma warning( disable: 4127 ) #pragma warning( disable: 4127 )
#endif #endif
skipping to change at line 962 skipping to change at line 1008
{//lock scope {//lock scope
__TBB_ASSERT((m&(m+1))==0, NULL); __TBB_ASSERT((m&(m+1))==0, NULL);
return_value = false; return_value = false;
// get bucket // get bucket
bucket_accessor b( this, h & m ); bucket_accessor b( this, h & m );
// find a node // find a node
n = search_bucket( key, b() ); n = search_bucket( key, b() );
if( op_insert ) { if( op_insert ) {
// [opt] insert a key // [opt] insert a key
if( !is_valid(n) ) { if( !n ) {
if( !tmp_n ) { if( !tmp_n ) {
if(t) tmp_n = new( my_allocator ) node(key, *t); if(t) tmp_n = new( my_allocator ) node(key, *t);
else tmp_n = new( my_allocator ) node(key); else tmp_n = new( my_allocator ) node(key);
} }
if( !b.is_writer() && !b.upgrade_to_writer() ) { // TODO: i mproved insertion if( !b.is_writer() && !b.upgrade_to_writer() ) { // TODO: i mproved insertion
// Rerun search_list, in case another thread inserted t he item during the upgrade. // Rerun search_list, in case another thread inserted t he item during the upgrade.
n = search_bucket( key, b() ); n = search_bucket( key, b() );
if( is_valid(n) ) { // unfortunately, it did if( is_valid(n) ) { // unfortunately, it did
b.downgrade_to_reader(); b.downgrade_to_reader();
goto exists; goto exists;
skipping to change at line 998 skipping to change at line 1044
return false; return false;
} }
return_value = true; return_value = true;
grow_segment = 0; grow_segment = 0;
} }
if( !result ) goto check_growth; if( !result ) goto check_growth;
// TODO: the following seems as generic/regular operation // TODO: the following seems as generic/regular operation
// acquire the item // acquire the item
if( !result->my_lock.try_acquire( n->mutex, write ) ) { if( !result->my_lock.try_acquire( n->mutex, write ) ) {
// we are unlucky, prepare for longer wait // we are unlucky, prepare for longer wait
internal::atomic_backoff trials; tbb::internal::atomic_backoff trials;
do { do {
if( !trials.bounded_pause() ) { if( !trials.bounded_pause() ) {
// the wait takes really long, restart the operation // the wait takes really long, restart the operation
b.release(); b.release();
__TBB_ASSERT( !op_insert || !return_value, "Can't acqui re new item in locked bucket?" );
__TBB_Yield(); __TBB_Yield();
#if TBB_USE_THREADING_TOOLS
m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_
mask );
#else
m = my_mask; m = my_mask;
#endif
goto restart; goto restart;
} }
} while( !result->my_lock.try_acquire( n->mutex, write ) ); } while( !result->my_lock.try_acquire( n->mutex, write ) );
} }
}//lock scope }//lock scope
result->my_node = n; result->my_node = n;
result->my_hash = h; result->my_hash = h;
check_growth: check_growth:
// [opt] grow the container // [opt] grow the container
if( grow_segment ) if( grow_segment )
enable_segment( grow_segment ); enable_segment( grow_segment );
if( tmp_n ) // if op_insert only if( tmp_n ) // if op_insert only
delete_node( tmp_n ); delete_node( tmp_n );
return return_value; return return_value;
} }
template<typename Key, typename T, typename HashCompare, typename A> template<typename Key, typename T, typename HashCompare, typename A>
template<typename I> template<typename I>
std::pair<I, I> concurrent_hash_map<Key,T,HashCompare,A>::internal_equal_ra nge( const Key& key, I end ) const { std::pair<I, I> concurrent_hash_map<Key,T,HashCompare,A>::internal_equal_ra nge( const Key& key, I end_ ) const {
hashcode_t h = my_hash_compare.hash( key ); hashcode_t h = my_hash_compare.hash( key );
hashcode_t m = my_mask; hashcode_t m = my_mask;
__TBB_ASSERT((m&(m+1))==0, NULL); __TBB_ASSERT((m&(m+1))==0, NULL);
h &= m; h &= m;
bucket *b = get_bucket( h ); bucket *b = get_bucket( h );
while( b->node_list == __TBB_rehash_req ) { while( b->node_list == internal::rehash_req ) {
m = ( 1u<<__TBB_Log2( h ) ) - 1; // get parent mask from the topmos t bit m = ( 1u<<__TBB_Log2( h ) ) - 1; // get parent mask from the topmos t bit
b = get_bucket( h &= m ); b = get_bucket( h &= m );
} }
node *n = search_bucket( key, b ); node *n = search_bucket( key, b );
if( !n ) if( !n )
return std::make_pair(end, end); return std::make_pair(end_, end_);
iterator lower(*this, h, b, n), upper(lower); iterator lower(*this, h, b, n), upper(lower);
return std::make_pair(lower, ++upper); return std::make_pair(lower, ++upper);
} }
template<typename Key, typename T, typename HashCompare, typename A> template<typename Key, typename T, typename HashCompare, typename A>
bool concurrent_hash_map<Key,T,HashCompare,A>::exclude( const_accessor &ite m_accessor, bool readonly ) { bool concurrent_hash_map<Key,T,HashCompare,A>::exclude( const_accessor &ite m_accessor, bool readonly ) {
__TBB_ASSERT( item_accessor.my_node, NULL ); __TBB_ASSERT( item_accessor.my_node, NULL );
node_base *const n = item_accessor.my_node; node_base *const n = item_accessor.my_node;
item_accessor.my_node = NULL; // we ought release accessor anyway item_accessor.my_node = NULL; // we ought release accessor anyway
hashcode_t const h = item_accessor.my_hash; hashcode_t const h = item_accessor.my_hash;
#if TBB_USE_THREADING_TOOLS
hashcode_t m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask
);
#else
hashcode_t m = my_mask; hashcode_t m = my_mask;
#endif
do { do {
// get bucket // get bucket
bucket_accessor b( this, h & m, /*writer=*/true ); bucket_accessor b( this, h & m, /*writer=*/true );
node_base **p = &b()->node_list; node_base **p = &b()->node_list;
while( *p && *p != n ) while( *p && *p != n )
p = &(*p)->next; p = &(*p)->next;
if( !*p ) { // someone else was the first if( !*p ) { // someone else was the first
if( check_mask_race( h, m ) ) if( check_mask_race( h, m ) )
continue; continue;
item_accessor.my_lock.release(); item_accessor.my_lock.release();
skipping to change at line 1075 skipping to change at line 1130
item_accessor.my_lock.upgrade_to_writer(); // return value means no thing here item_accessor.my_lock.upgrade_to_writer(); // return value means no thing here
item_accessor.my_lock.release(); item_accessor.my_lock.release();
delete_node( n ); // Only one thread can delete it due to write lock on the chain_mutex delete_node( n ); // Only one thread can delete it due to write lock on the chain_mutex
return true; return true;
} }
template<typename Key, typename T, typename HashCompare, typename A> template<typename Key, typename T, typename HashCompare, typename A>
bool concurrent_hash_map<Key,T,HashCompare,A>::erase( const Key &key ) { bool concurrent_hash_map<Key,T,HashCompare,A>::erase( const Key &key ) {
node_base *n; node_base *n;
hashcode_t const h = my_hash_compare.hash( key ); hashcode_t const h = my_hash_compare.hash( key );
#if TBB_USE_THREADING_TOOLS
hashcode_t m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask
);
#else
hashcode_t m = my_mask; hashcode_t m = my_mask;
#endif
restart:
{//lock scope {//lock scope
restart:
// get bucket // get bucket
bucket_accessor b( this, h & m ); bucket_accessor b( this, h & m );
search: search:
node_base **p = &b()->node_list; node_base **p = &b()->node_list;
n = *p; n = *p;
while( is_valid(n) && !my_hash_compare.equal(key, static_cast<node* >(n)->item.first ) ) { while( is_valid(n) && !my_hash_compare.equal(key, static_cast<node* >(n)->item.first ) ) {
p = &n->next; p = &n->next;
n = *p; n = *p;
} }
if( !n ) { // not found, but mask could be changed if( !n ) { // not found, but mask could be changed
skipping to change at line 1116 skipping to change at line 1175
} }
template<typename Key, typename T, typename HashCompare, typename A> template<typename Key, typename T, typename HashCompare, typename A>
void concurrent_hash_map<Key,T,HashCompare,A>::swap(concurrent_hash_map<Key ,T,HashCompare,A> &table) { void concurrent_hash_map<Key,T,HashCompare,A>::swap(concurrent_hash_map<Key ,T,HashCompare,A> &table) {
std::swap(this->my_allocator, table.my_allocator); std::swap(this->my_allocator, table.my_allocator);
std::swap(this->my_hash_compare, table.my_hash_compare); std::swap(this->my_hash_compare, table.my_hash_compare);
internal_swap(table); internal_swap(table);
} }
template<typename Key, typename T, typename HashCompare, typename A> template<typename Key, typename T, typename HashCompare, typename A>
void concurrent_hash_map<Key,T,HashCompare,A>::rehash(size_type sz) {
reserve( sz ); // TODO: add reduction of number of buckets as well
hashcode_t mask = my_mask;
hashcode_t b = (mask+1)>>1; // size or first index of the last segment
__TBB_ASSERT((b&(b-1))==0, NULL);
bucket *bp = get_bucket( b ); // only the last segment should be scanne
d for rehashing
for(; b <= mask; b++, bp++ ) {
node_base *n = bp->node_list;
__TBB_ASSERT( is_valid(n) || n == internal::empty_rehashed || n ==
internal::rehash_req, "Broken internal structure" );
__TBB_ASSERT( *reinterpret_cast<intptr_t*>(&bp->mutex) == 0, "concu
rrent or unexpectedly terminated operation during rehash() execution" );
if( n == internal::rehash_req ) { // rehash bucket, conditional bec
ause rehashing of a previous bucket may affect this one
hashcode_t h = b; bucket *b_old = bp;
do {
__TBB_ASSERT( h > 1, "The lowermost buckets can't be rehash
ed" );
hashcode_t m = ( 1u<<__TBB_Log2( h ) ) - 1; // get parent m
ask from the topmost bit
b_old = get_bucket( h &= m );
} while( b_old->node_list == internal::rehash_req );
// now h - is index of the root rehashed bucket b_old
mark_rehashed_levels( h ); // mark all non-rehashed children re
cursively across all segments
for( node_base **p = &b_old->node_list, *q = *p; is_valid(q); q
= *p ) {
hashcode_t c = my_hash_compare.hash( static_cast<node*>(q)-
>item.first );
if( (c & mask) != h ) { // should be rehashed
*p = q->next; // exclude from b_old
bucket *b_new = get_bucket( c & mask );
__TBB_ASSERT( b_new->node_list != internal::rehash_req,
"hash() function changed for key in table or internal error" );
add_to_bucket( b_new, q );
} else p = &q->next; // iterate to next item
}
}
}
#if TBB_USE_PERFORMANCE_WARNINGS
int current_size = int(my_size), buckets = int(mask)+1, empty_buckets =
0, overpopulated_buckets = 0; // usage statistics
static bool reported = false;
#endif
#if TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS
for( b = 0; b <= mask; b++ ) {// only last segment should be scanned fo
r rehashing
if( b & (b-2) ) ++bp; // not the beginning of a segment
else bp = get_bucket( b );
node_base *n = bp->node_list;
__TBB_ASSERT( *reinterpret_cast<intptr_t*>(&bp->mutex) == 0, "concu
rrent or unexpectedly terminated operation during rehash() execution" );
__TBB_ASSERT( is_valid(n) || n == internal::empty_rehashed, "Broken
internal structure" );
#if TBB_USE_PERFORMANCE_WARNINGS
if( n == internal::empty_rehashed ) empty_buckets++;
else if( n->next ) overpopulated_buckets++;
#endif
#if TBB_USE_ASSERT
for( ; is_valid(n); n = n->next ) {
hashcode_t h = my_hash_compare.hash( static_cast<node*>(n)->ite
m.first ) & mask;
__TBB_ASSERT( h == b, "hash() function changed for key in table
or internal error" );
}
#endif
}
#endif // TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS
#if TBB_USE_PERFORMANCE_WARNINGS
if( buckets > current_size) empty_buckets -= buckets - current_size;
else overpopulated_buckets -= current_size - buckets; // TODO: load_fac
tor?
if( !reported && buckets >= 512 && ( 2*empty_buckets > current_size ||
2*overpopulated_buckets > current_size ) ) {
tbb::internal::runtime_warning(
"Performance is not optimal because the hash function produces
bad randomness in lower bits in %s.\nSize: %d Empties: %d Overlaps: %d",
typeid(*this).name(), current_size, empty_buckets, overpopulate
d_buckets );
reported = true;
}
#endif
}
template<typename Key, typename T, typename HashCompare, typename A>
void concurrent_hash_map<Key,T,HashCompare,A>::clear() { void concurrent_hash_map<Key,T,HashCompare,A>::clear() {
hashcode_t m = my_mask; hashcode_t m = my_mask;
__TBB_ASSERT((m&(m+1))==0, NULL); __TBB_ASSERT((m&(m+1))==0, NULL);
#if TBB_USE_DEBUG || TBB_USE_PERFORMANCE_WARNINGS #if TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS
#if TBB_USE_PERFORMANCE_WARNINGS #if TBB_USE_PERFORMANCE_WARNINGS
int size = int(my_size), buckets = int(m)+1, empty_buckets = 0, overpop ulated_buckets = 0; // usage statistics int current_size = int(my_size), buckets = int(m)+1, empty_buckets = 0, overpopulated_buckets = 0; // usage statistics
static bool reported = false; static bool reported = false;
#endif #endif
bucket *bp = 0;
// check consistency // check consistency
for( segment_index_t b = 0; b <= m; b++ ) { for( segment_index_t b = 0; b <= m; b++ ) {
node_base *n = get_bucket(b)->node_list; if( b & (b-2) ) ++bp; // not the beginning of a segment
else bp = get_bucket( b );
node_base *n = bp->node_list;
__TBB_ASSERT( is_valid(n) || n == internal::empty_rehashed || n ==
internal::rehash_req, "Broken internal structure" );
__TBB_ASSERT( *reinterpret_cast<intptr_t*>(&bp->mutex) == 0, "concu
rrent or unexpectedly terminated operation during clear() execution" );
#if TBB_USE_PERFORMANCE_WARNINGS #if TBB_USE_PERFORMANCE_WARNINGS
if( n == __TBB_empty_rehashed ) empty_buckets++; if( n == internal::empty_rehashed ) empty_buckets++;
else if( n == __TBB_rehash_req ) buckets--; else if( n == internal::rehash_req ) buckets--;
else if( n->next ) overpopulated_buckets++; else if( n->next ) overpopulated_buckets++;
#endif #endif
#if __TBB_EXTRA_DEBUG
for(; is_valid(n); n = n->next ) { for(; is_valid(n); n = n->next ) {
hashcode_t h = my_hash_compare.hash( static_cast<node*>(n)->ite m.first ); hashcode_t h = my_hash_compare.hash( static_cast<node*>(n)->ite m.first );
h &= m; h &= m;
__TBB_ASSERT( h == b || get_bucket(h)->node_list == __TBB_rehas h_req, "Rehashing is not finished until serial stage due to concurrent or t erminated operation" ); __TBB_ASSERT( h == b || get_bucket(h)->node_list == internal::r ehash_req, "hash() function changed for key in table or internal error" );
} }
#endif
} }
#if TBB_USE_PERFORMANCE_WARNINGS #if TBB_USE_PERFORMANCE_WARNINGS
if( buckets > size) empty_buckets -= buckets - size; if( buckets > current_size) empty_buckets -= buckets - current_size;
else overpopulated_buckets -= size - buckets; // TODO: load_factor? else overpopulated_buckets -= current_size - buckets; // TODO: load_fac
if( !reported && buckets >= 512 && ( 2*empty_buckets >= size || 2*overp tor?
opulated_buckets > size ) ) { if( !reported && buckets >= 512 && ( 2*empty_buckets > current_size ||
internal::runtime_warning( 2*overpopulated_buckets > current_size ) ) {
tbb::internal::runtime_warning(
"Performance is not optimal because the hash function produces bad randomness in lower bits in %s.\nSize: %d Empties: %d Overlaps: %d", "Performance is not optimal because the hash function produces bad randomness in lower bits in %s.\nSize: %d Empties: %d Overlaps: %d",
typeid(*this).name(), size, empty_buckets, overpopulated_bucket s ); typeid(*this).name(), current_size, empty_buckets, overpopulate d_buckets );
reported = true; reported = true;
} }
#endif #endif
#endif//TBB_USE_DEBUG || TBB_USE_PERFORMANCE_WARNINGS #endif//TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS
my_size = 0; my_size = 0;
segment_index_t s = segment_index_of( m ); segment_index_t s = segment_index_of( m );
__TBB_ASSERT( s+1 == pointers_per_table || !my_table[s+1], "wrong mask or concurrent grow" ); __TBB_ASSERT( s+1 == pointers_per_table || !my_table[s+1], "wrong mask or concurrent grow" );
cache_aligned_allocator<bucket> alloc; cache_aligned_allocator<bucket> alloc;
do { do {
__TBB_ASSERT( is_valid( my_table[s] ), "wrong mask or concurrent gr ow" ); __TBB_ASSERT( is_valid( my_table[s] ), "wrong mask or concurrent gr ow" );
segment_ptr_t buckets = my_table[s]; segment_ptr_t buckets_ptr = my_table[s];
size_type sz = segment_size( s ? s : 1 ); size_type sz = segment_size( s ? s : 1 );
for( segment_index_t i = 0; i < sz; i++ ) for( segment_index_t i = 0; i < sz; i++ )
for( node_base *n = buckets[i].node_list; is_valid(n); n = buck for( node_base *n = buckets_ptr[i].node_list; is_valid(n); n =
ets[i].node_list ) { buckets_ptr[i].node_list ) {
buckets[i].node_list = n->next; buckets_ptr[i].node_list = n->next;
delete_node( n ); delete_node( n );
} }
if( s >= first_block) // the first segment or the next if( s >= first_block) // the first segment or the next
alloc.deallocate( buckets, sz ); alloc.deallocate( buckets_ptr, sz );
else if( s == embedded_block && embedded_block != first_block ) else if( s == embedded_block && embedded_block != first_block )
alloc.deallocate( buckets, segment_size(first_block)-embedded_b uckets ); alloc.deallocate( buckets_ptr, segment_size(first_block)-embedd ed_buckets );
if( s >= embedded_block ) my_table[s] = 0; if( s >= embedded_block ) my_table[s] = 0;
} while(s-- > 0); } while(s-- > 0);
my_mask = embedded_buckets - 1; my_mask = embedded_buckets - 1;
} }
template<typename Key, typename T, typename HashCompare, typename A> template<typename Key, typename T, typename HashCompare, typename A>
void concurrent_hash_map<Key,T,HashCompare,A>::internal_copy( const concurr ent_hash_map& source ) { void concurrent_hash_map<Key,T,HashCompare,A>::internal_copy( const concurr ent_hash_map& source ) {
reserve( source.my_size ); // TODO: load_factor? reserve( source.my_size ); // TODO: load_factor?
if( my_mask == source.my_mask ) { // optimized version hashcode_t mask = source.my_mask;
for( const_iterator it = source.begin(), end = source.end(); it != if( my_mask == mask ) { // optimized version
end; ++it ) { bucket *dst = 0, *src = 0;
bucket *b = get_bucket( it.my_index ); bool rehash_required = false;
__TBB_ASSERT( b->node_list != __TBB_rehash_req, "Invalid bucket for( hashcode_t k = 0; k <= mask; k++ ) {
in destination table"); if( k & (k-2) ) ++dst,src++; // not the beginning of a segment
node *n = new( my_allocator ) node(it->first, it->second); else { dst = get_bucket( k ); src = source.get_bucket( k ); }
add_to_bucket( b, n ); __TBB_ASSERT( dst->node_list != internal::rehash_req, "Invalid
++my_size; // TODO: replace by non-atomic op bucket in destination table");
node *n = static_cast<node*>( src->node_list );
if( n == internal::rehash_req ) { // source is not rehashed, it
ems are in previous buckets
rehash_required = true;
dst->node_list = internal::rehash_req;
} else for(; n; n = static_cast<node*>( n->next ) ) {
add_to_bucket( dst, new( my_allocator ) node(n->item.first,
n->item.second) );
++my_size; // TODO: replace by non-atomic op
}
} }
if( rehash_required ) rehash();
} else internal_copy( source.begin(), source.end() ); } else internal_copy( source.begin(), source.end() );
} }
template<typename Key, typename T, typename HashCompare, typename A> template<typename Key, typename T, typename HashCompare, typename A>
template<typename I> template<typename I>
void concurrent_hash_map<Key,T,HashCompare,A>::internal_copy(I first, I las t) { void concurrent_hash_map<Key,T,HashCompare,A>::internal_copy(I first, I las t) {
hashcode_t m = my_mask; hashcode_t m = my_mask;
for(; first != last; ++first) { for(; first != last; ++first) {
hashcode_t h = my_hash_compare.hash( first->first ); hashcode_t h = my_hash_compare.hash( first->first );
bucket *b = get_bucket( h & m ); bucket *b = get_bucket( h & m );
__TBB_ASSERT( b->node_list != __TBB_rehash_req, "Invalid bucket in destination table"); __TBB_ASSERT( b->node_list != internal::rehash_req, "Invalid bucket in destination table");
node *n = new( my_allocator ) node(first->first, first->second); node *n = new( my_allocator ) node(first->first, first->second);
add_to_bucket( b, n ); add_to_bucket( b, n );
++my_size; // TODO: replace by non-atomic op ++my_size; // TODO: replace by non-atomic op
} }
} }
} // namespace interface4
using interface4::concurrent_hash_map;
template<typename Key, typename T, typename HashCompare, typename A1, typen ame A2> template<typename Key, typename T, typename HashCompare, typename A1, typen ame A2>
inline bool operator==(const concurrent_hash_map<Key, T, HashCompare, A1> & a, const concurrent_hash_map<Key, T, HashCompare, A2> &b) { inline bool operator==(const concurrent_hash_map<Key, T, HashCompare, A1> & a, const concurrent_hash_map<Key, T, HashCompare, A2> &b) {
if(a.size() != b.size()) return false; if(a.size() != b.size()) return false;
typename concurrent_hash_map<Key, T, HashCompare, A1>::const_iterator i (a.begin()), i_end(a.end()); typename concurrent_hash_map<Key, T, HashCompare, A1>::const_iterator i (a.begin()), i_end(a.end());
typename concurrent_hash_map<Key, T, HashCompare, A2>::const_iterator j , j_end(b.end()); typename concurrent_hash_map<Key, T, HashCompare, A2>::const_iterator j , j_end(b.end());
for(; i != i_end; ++i) { for(; i != i_end; ++i) {
j = b.equal_range(i->first).first; j = b.equal_range(i->first).first;
if( j == j_end || !(i->second == j->second) ) return false; if( j == j_end || !(i->second == j->second) ) return false;
} }
return true; return true;
 End of changes. 83 change blocks. 
131 lines changed or deleted 316 lines changed or added


 concurrent_queue.h   concurrent_queue.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 53 skipping to change at line 53
class concurrent_queue: public internal::concurrent_queue_base_v3<T> { class concurrent_queue: public internal::concurrent_queue_base_v3<T> {
template<typename Container, typename Value> friend class internal::con current_queue_iterator; template<typename Container, typename Value> friend class internal::con current_queue_iterator;
//! Allocator type //! Allocator type
typedef typename A::template rebind<char>::other page_allocator_type; typedef typename A::template rebind<char>::other page_allocator_type;
page_allocator_type my_allocator; page_allocator_type my_allocator;
//! Allocates a block of size n (bytes) //! Allocates a block of size n (bytes)
/*overide*/ virtual void *allocate_block( size_t n ) { /*overide*/ virtual void *allocate_block( size_t n ) {
void *b = reinterpret_cast<void*>(my_allocator.allocate( n )); void *b = reinterpret_cast<void*>(my_allocator.allocate( n ));
if( !b ) this->internal_throw_exception(); if( !b )
internal::throw_exception(internal::eid_bad_alloc);
return b; return b;
} }
//! Returns a block of size n (bytes) //! Deallocates block created by allocate_block.
/*override*/ virtual void deallocate_block( void *b, size_t n ) { /*override*/ virtual void deallocate_block( void *b, size_t n ) {
my_allocator.deallocate( reinterpret_cast<char*>(b), n ); my_allocator.deallocate( reinterpret_cast<char*>(b), n );
} }
public: public:
//! Element type in the queue. //! Element type in the queue.
typedef T value_type; typedef T value_type;
//! Reference type //! Reference type
typedef T& reference; typedef T& reference;
skipping to change at line 83 skipping to change at line 84
typedef size_t size_type; typedef size_t size_type;
//! Difference type for iterator //! Difference type for iterator
typedef ptrdiff_t difference_type; typedef ptrdiff_t difference_type;
//! Allocator type //! Allocator type
typedef A allocator_type; typedef A allocator_type;
//! Construct empty queue //! Construct empty queue
explicit concurrent_queue(const allocator_type& a = allocator_type()) : explicit concurrent_queue(const allocator_type& a = allocator_type()) :
internal::concurrent_queue_base_v3<T>( sizeof(T) ), my_allocator( a ) my_allocator( a )
{ {
} }
//! [begin,end) constructor //! [begin,end) constructor
template<typename InputIterator> template<typename InputIterator>
concurrent_queue( InputIterator begin, InputIterator end, const allocat or_type& a = allocator_type()) : concurrent_queue( InputIterator begin, InputIterator end, const allocat or_type& a = allocator_type()) :
internal::concurrent_queue_base_v3<T>( sizeof(T) ), my_allocator( a ) my_allocator( a )
{ {
for( ; begin != end; ++begin ) for( ; begin != end; ++begin )
internal_push(&*begin); internal_push(&*begin);
} }
//! Copy constructor //! Copy constructor
concurrent_queue( const concurrent_queue& src, const allocator_type& a = allocator_type()) : concurrent_queue( const concurrent_queue& src, const allocator_type& a = allocator_type()) :
internal::concurrent_queue_base_v3<T>( sizeof(T) ), my_allocator( a ) internal::concurrent_queue_base_v3<T>(), my_allocator( a )
{ {
assign( src ); assign( src );
} }
//! Destroy queue //! Destroy queue
~concurrent_queue(); ~concurrent_queue();
//! Enqueue an item at tail of queue. //! Enqueue an item at tail of queue.
void push( const T& source ) { void push( const T& source ) {
internal_push( &source ); internal_push( &source );
skipping to change at line 152 skipping to change at line 153
template<typename T, class A> template<typename T, class A>
concurrent_queue<T,A>::~concurrent_queue() { concurrent_queue<T,A>::~concurrent_queue() {
clear(); clear();
this->internal_finish_clear(); this->internal_finish_clear();
} }
template<typename T, class A> template<typename T, class A>
void concurrent_queue<T,A>::clear() { void concurrent_queue<T,A>::clear() {
while( !empty() ) { while( !empty() ) {
T value; T value;
internal_try_pop(&value); this->internal_try_pop(&value);
} }
} }
} // namespace strict_ppl } // namespace strict_ppl
//! A high-performance thread-safe blocking concurrent bounded queue. //! A high-performance thread-safe blocking concurrent bounded queue.
/** This is the pre-PPL TBB concurrent queue which supports boundedness and blocking semantics. /** This is the pre-PPL TBB concurrent queue which supports boundedness and blocking semantics.
Note that method names agree with the PPL-style concurrent queue. Note that method names agree with the PPL-style concurrent queue.
Multiple threads may each push and pop concurrently. Multiple threads may each push and pop concurrently.
Assignment construction is not allowed. Assignment construction is not allowed.
@ingroup containers */ @ingroup containers */
template<typename T, class A = cache_aligned_allocator<T> > template<typename T, class A = cache_aligned_allocator<T> >
class concurrent_bounded_queue: public internal::concurrent_queue_base_v3 { class concurrent_bounded_queue: public internal::concurrent_queue_base_v3 {
template<typename Container, typename Value> friend class internal::con current_queue_iterator; template<typename Container, typename Value> friend class internal::con current_queue_iterator;
//! Allocator type //! Allocator type
typedef typename A::template rebind<char>::other page_allocator_type; typedef typename A::template rebind<char>::other page_allocator_type;
page_allocator_type my_allocator; page_allocator_type my_allocator;
typedef typename concurrent_queue_base_v3::padded_page<T> padded_page;
//! Class used to ensure exception-safety of method "pop" //! Class used to ensure exception-safety of method "pop"
class destroyer: internal::no_copy { class destroyer: internal::no_copy {
T& my_value; T& my_value;
public: public:
destroyer( T& value ) : my_value(value) {} destroyer( T& value ) : my_value(value) {}
~destroyer() {my_value.~T();} ~destroyer() {my_value.~T();}
}; };
T& get_ref( page& page, size_t index ) { T& get_ref( page& p, size_t index ) {
__TBB_ASSERT( index<items_per_page, NULL ); __TBB_ASSERT( index<items_per_page, NULL );
return static_cast<T*>(static_cast<void*>(&page+1))[index]; return (&static_cast<padded_page*>(static_cast<void*>(&p))->last)[i ndex];
} }
/*override*/ virtual void copy_item( page& dst, size_t index, const voi d* src ) { /*override*/ virtual void copy_item( page& dst, size_t index, const voi d* src ) {
new( &get_ref(dst,index) ) T(*static_cast<const T*>(src)); new( &get_ref(dst,index) ) T(*static_cast<const T*>(src));
} }
/*override*/ virtual void copy_page_item( page& dst, size_t dindex, con st page& src, size_t sindex ) { /*override*/ virtual void copy_page_item( page& dst, size_t dindex, con st page& src, size_t sindex ) {
new( &get_ref(dst,dindex) ) T( static_cast<const T*>(static_cast<co nst void*>(&src+1))[sindex] ); new( &get_ref(dst,dindex) ) T( get_ref( const_cast<page&>(src), sin dex ) );
} }
/*override*/ virtual void assign_and_destroy_item( void* dst, page& src , size_t index ) { /*override*/ virtual void assign_and_destroy_item( void* dst, page& src , size_t index ) {
T& from = get_ref(src,index); T& from = get_ref(src,index);
destroyer d(from); destroyer d(from);
*static_cast<T*>(dst) = from; *static_cast<T*>(dst) = from;
} }
/*overide*/ virtual page *allocate_page() { /*overide*/ virtual page *allocate_page() {
size_t n = sizeof(page) + items_per_page*item_size; size_t n = sizeof(padded_page) + (items_per_page-1)*sizeof(T);
page *p = reinterpret_cast<page*>(my_allocator.allocate( n )); page *p = reinterpret_cast<page*>(my_allocator.allocate( n ));
if( !p ) internal_throw_exception(); if( !p )
internal::throw_exception(internal::eid_bad_alloc);
return p; return p;
} }
/*override*/ virtual void deallocate_page( page *p ) { /*override*/ virtual void deallocate_page( page *p ) {
size_t n = sizeof(page) + items_per_page*item_size; size_t n = sizeof(padded_page) + items_per_page*sizeof(T);
my_allocator.deallocate( reinterpret_cast<char*>(p), n ); my_allocator.deallocate( reinterpret_cast<char*>(p), n );
} }
public: public:
//! Element type in the queue. //! Element type in the queue.
typedef T value_type; typedef T value_type;
//! Allocator type //! Allocator type
typedef A allocator_type; typedef A allocator_type;
skipping to change at line 299 skipping to change at line 303
bool empty() const {return internal_empty();} bool empty() const {return internal_empty();}
//! Maximum number of allowed elements //! Maximum number of allowed elements
size_type capacity() const { size_type capacity() const {
return my_capacity; return my_capacity;
} }
//! Set the capacity //! Set the capacity
/** Setting the capacity to 0 causes subsequent try_push operations to always fail, /** Setting the capacity to 0 causes subsequent try_push operations to always fail,
and subsequent push operations to block forever. */ and subsequent push operations to block forever. */
void set_capacity( size_type capacity ) { void set_capacity( size_type new_capacity ) {
internal_set_capacity( capacity, sizeof(T) ); internal_set_capacity( new_capacity, sizeof(T) );
} }
//! return allocator object //! return allocator object
allocator_type get_allocator() const { return this->my_allocator; } allocator_type get_allocator() const { return this->my_allocator; }
//! clear the queue. not thread-safe. //! clear the queue. not thread-safe.
void clear() ; void clear() ;
typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,T> iterator; typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,T> iterator;
typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,co nst T> const_iterator; typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,co nst T> const_iterator;
skipping to change at line 365 skipping to change at line 369
} }
//! Copy constructor //! Copy constructor
concurrent_queue( const concurrent_queue& src, const A& a = A()) : concurrent_queue( const concurrent_queue& src, const A& a = A()) :
concurrent_bounded_queue<T,A>( src, a ) concurrent_bounded_queue<T,A>( src, a )
{ {
} }
//! [begin,end) constructor //! [begin,end) constructor
template<typename InputIterator> template<typename InputIterator>
concurrent_queue( InputIterator begin, InputIterator end, const A& a = concurrent_queue( InputIterator b /*begin*/, InputIterator e /*end*/, c
A()) : onst A& a = A()) :
concurrent_bounded_queue<T,A>( begin, end, a ) concurrent_bounded_queue<T,A>( b, e, a )
{ {
} }
//! Enqueue an item at tail of queue if queue is not already full. //! Enqueue an item at tail of queue if queue is not already full.
/** Does not wait for queue to become not full. /** Does not wait for queue to become not full.
Returns true if item is pushed; false if queue was already full. */ Returns true if item is pushed; false if queue was already full. */
bool push_if_not_full( const T& source ) { bool push_if_not_full( const T& source ) {
return try_push( source ); return try_push( source );
} }
 End of changes. 16 change blocks. 
18 lines changed or deleted 22 lines changed or added


 concurrent_vector.h   concurrent_vector.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 33 skipping to change at line 33
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_concurrent_vector_H #ifndef __TBB_concurrent_vector_H
#define __TBB_concurrent_vector_H #define __TBB_concurrent_vector_H
#include "tbb_stddef.h" #include "tbb_stddef.h"
#include <algorithm> #include "tbb_exception.h"
#include <iterator>
#include <new>
#include <cstring>
#include "atomic.h" #include "atomic.h"
#include "cache_aligned_allocator.h" #include "cache_aligned_allocator.h"
#include "blocked_range.h" #include "blocked_range.h"
#include "tbb_machine.h" #include "tbb_machine.h"
#include <new>
#if !TBB_USE_EXCEPTIONS && _MSC_VER
// Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers
#pragma warning (push)
#pragma warning (disable: 4530)
#endif
#include <algorithm>
#include <iterator>
#if !TBB_USE_EXCEPTIONS && _MSC_VER
#pragma warning (pop)
#endif
#if _MSC_VER==1500 && !__INTEL_COMPILER #if _MSC_VER==1500 && !__INTEL_COMPILER
// VS2008/VC9 seems to have an issue; limits pull in math.h // VS2008/VC9 seems to have an issue; limits pull in math.h
#pragma warning( push ) #pragma warning( push )
#pragma warning( disable: 4985 ) #pragma warning( disable: 4985 )
#endif #endif
#include <limits> /* std::numeric_limits */ #include <limits> /* std::numeric_limits */
#if _MSC_VER==1500 && !__INTEL_COMPILER #if _MSC_VER==1500 && !__INTEL_COMPILER
#pragma warning( pop ) #pragma warning( pop )
#endif #endif
skipping to change at line 64 skipping to change at line 74
// Workaround for overzealous compiler warnings in /Wp64 mode // Workaround for overzealous compiler warnings in /Wp64 mode
#pragma warning (push) #pragma warning (push)
#pragma warning (disable: 4267) #pragma warning (disable: 4267)
#endif #endif
namespace tbb { namespace tbb {
template<typename T, class A = cache_aligned_allocator<T> > template<typename T, class A = cache_aligned_allocator<T> >
class concurrent_vector; class concurrent_vector;
//! Bad allocation marker
#define __TBB_BAD_ALLOC reinterpret_cast<void*>(size_t(63))
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
//! Bad allocation marker
static void *const vector_allocation_error_flag = reinterpret_cast<void
*>(size_t(63));
//! Routine that loads pointer from location pointed to by src without any fence, without causing ITT to report a race. //! Routine that loads pointer from location pointed to by src without any fence, without causing ITT to report a race.
void* __TBB_EXPORTED_FUNC itt_load_pointer_v3( const void* src ); void* __TBB_EXPORTED_FUNC itt_load_pointer_v3( const void* src );
//! Base class of concurrent vector implementation. //! Base class of concurrent vector implementation.
/** @ingroup containers */ /** @ingroup containers */
class concurrent_vector_base_v3 { class concurrent_vector_base_v3 {
protected: protected:
// Basic types declarations // Basic types declarations
typedef size_t segment_index_t; typedef size_t segment_index_t;
skipping to change at line 96 skipping to change at line 106
//! Number of slots for segment's pointers inside the class //! Number of slots for segment's pointers inside the class
pointers_per_short_table = 3, // to fit into 8 words of entire structure pointers_per_short_table = 3, // to fit into 8 words of entire structure
pointers_per_long_table = sizeof(segment_index_t) * 8 // one se gment per bit pointers_per_long_table = sizeof(segment_index_t) * 8 // one se gment per bit
}; };
// Segment pointer. Can be zero-initialized // Segment pointer. Can be zero-initialized
struct segment_t { struct segment_t {
void* array; void* array;
#if TBB_USE_ASSERT #if TBB_USE_ASSERT
~segment_t() { ~segment_t() {
__TBB_ASSERT( array <= __TBB_BAD_ALLOC, "should have been f reed by clear" ); __TBB_ASSERT( array <= internal::vector_allocation_error_fl ag, "should have been freed by clear" );
} }
#endif /* TBB_USE_ASSERT */ #endif /* TBB_USE_ASSERT */
}; };
// Data fields // Data fields
//! allocator function pointer //! allocator function pointer
void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t); void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
//! count of segments in the first block //! count of segments in the first block
skipping to change at line 169 skipping to change at line 179
void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size ); void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
size_type __TBB_EXPORTED_METHOD internal_capacity() const; size_type __TBB_EXPORTED_METHOD internal_capacity() const;
void internal_grow( size_type start, size_type finish, size_type el ement_size, internal_array_op2 init, const void *src ); void internal_grow( size_type start, size_type finish, size_type el ement_size, internal_array_op2 init, const void *src );
size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src ); size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_s ize, size_type& index ); void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_s ize, size_type& index );
segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_arra y_op1 destroy ); segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_arra y_op1 destroy );
void* __TBB_EXPORTED_METHOD internal_compact( size_type element_siz e, void *table, internal_array_op1 destroy, internal_array_op2 copy ); void* __TBB_EXPORTED_METHOD internal_compact( size_type element_siz e, void *table, internal_array_op1 destroy, internal_array_op2 copy );
void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_b ase_v3& src, size_type element_size, internal_array_op2 copy ); void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_b ase_v3& src, size_type element_size, internal_array_op2 copy );
void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector _base_v3& src, size_type element_size, void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector _base_v3& src, size_type element_size,
internal_array_op1 destroy, internal_array_op 2 assign, internal_array_op2 copy ); internal_array_op1 destroy, internal_array_op 2 assign, internal_array_op2 copy );
//! Obsolete
void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) cons t; void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) cons t;
void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v); void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src, void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
internal_array_op1 dest roy, internal_array_op2 init ); internal_array_op1 dest roy, internal_array_op2 init );
size_type __TBB_EXPORTED_METHOD internal_grow_to_at_least_with_resu lt( size_type new_size, size_type element_size, internal_array_op2 init, co nst void *src ); size_type __TBB_EXPORTED_METHOD internal_grow_to_at_least_with_resu lt( size_type new_size, size_type element_size, internal_array_op2 init, co nst void *src );
//! Deprecated entry point for backwards compatibility to TBB 2.1. //! Deprecated entry point for backwards compatibility to TBB 2.1.
void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new _size, size_type element_size, internal_array_op2 init, const void *src ); void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new _size, size_type element_size, internal_array_op2 init, const void *src );
private: private:
skipping to change at line 450 skipping to change at line 461
private internal::concurrent_vector_base { private internal::concurrent_vector_base {
private: private:
template<typename I> template<typename I>
class generic_range_type: public blocked_range<I> { class generic_range_type: public blocked_range<I> {
public: public:
typedef T value_type; typedef T value_type;
typedef T& reference; typedef T& reference;
typedef const T& const_reference; typedef const T& const_reference;
typedef I iterator; typedef I iterator;
typedef ptrdiff_t difference_type; typedef ptrdiff_t difference_type;
generic_range_type( I begin_, I end_, size_t grainsize = 1) : block ed_range<I>(begin_,end_,grainsize) {} generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : bloc ked_range<I>(begin_,end_,grainsize_) {}
template<typename U> template<typename U>
generic_range_type( const generic_range_type<U>& r) : blocked_range <I>(r.begin(),r.end(),r.grainsize()) {} generic_range_type( const generic_range_type<U>& r) : blocked_range <I>(r.begin(),r.end(),r.grainsize()) {}
generic_range_type( generic_range_type& r, split ) : blocked_range< I>(r,split()) {} generic_range_type( generic_range_type& r, split ) : blocked_range< I>(r,split()) {}
}; };
template<typename C, typename U> template<typename C, typename U>
friend class internal::vector_iterator; friend class internal::vector_iterator;
public: public:
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
// STL compatible types // STL compatible types
skipping to change at line 507 skipping to change at line 518
: internal::allocator_base<T, A>(a) : internal::allocator_base<T, A>(a)
{ {
vector_allocator_ptr = &internal_allocator; vector_allocator_ptr = &internal_allocator;
} }
//! Copying constructor //! Copying constructor
concurrent_vector( const concurrent_vector& vector, const allocator_typ e& a = allocator_type() ) concurrent_vector( const concurrent_vector& vector, const allocator_typ e& a = allocator_type() )
: internal::allocator_base<T, A>(a) : internal::allocator_base<T, A>(a)
{ {
vector_allocator_ptr = &internal_allocator; vector_allocator_ptr = &internal_allocator;
try { __TBB_TRY {
internal_copy(vector, sizeof(T), &copy_array); internal_copy(vector, sizeof(T), &copy_array);
} catch(...) { } __TBB_CATCH(...) {
segment_t *table = my_segment; segment_t *table = my_segment;
internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block ); internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block );
throw; __TBB_RETHROW();
} }
} }
//! Copying constructor for vector with different allocator type //! Copying constructor for vector with different allocator type
template<class M> template<class M>
concurrent_vector( const concurrent_vector<T, M>& vector, const allocat or_type& a = allocator_type() ) concurrent_vector( const concurrent_vector<T, M>& vector, const allocat or_type& a = allocator_type() )
: internal::allocator_base<T, A>(a) : internal::allocator_base<T, A>(a)
{ {
vector_allocator_ptr = &internal_allocator; vector_allocator_ptr = &internal_allocator;
try { __TBB_TRY {
internal_copy(vector.internal_vector_base(), sizeof(T), &copy_a rray); internal_copy(vector.internal_vector_base(), sizeof(T), &copy_a rray);
} catch(...) { } __TBB_CATCH(...) {
segment_t *table = my_segment; segment_t *table = my_segment;
internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block ); internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block );
throw; __TBB_RETHROW();
} }
} }
//! Construction with initial size specified by argument n //! Construction with initial size specified by argument n
explicit concurrent_vector(size_type n) explicit concurrent_vector(size_type n)
{ {
vector_allocator_ptr = &internal_allocator; vector_allocator_ptr = &internal_allocator;
try { __TBB_TRY {
internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array , &initialize_array ); internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array , &initialize_array );
} catch(...) { } __TBB_CATCH(...) {
segment_t *table = my_segment; segment_t *table = my_segment;
internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block ); internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block );
throw; __TBB_RETHROW();
} }
} }
//! Construction with initial size specified by argument n, initializat ion by copying of t, and given allocator instance //! Construction with initial size specified by argument n, initializat ion by copying of t, and given allocator instance
concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type()) concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
: internal::allocator_base<T, A>(a) : internal::allocator_base<T, A>(a)
{ {
vector_allocator_ptr = &internal_allocator; vector_allocator_ptr = &internal_allocator;
try { __TBB_TRY {
internal_resize( n, sizeof(T), max_size(), static_cast<const vo id*>(&t), &destroy_array, &initialize_array_by ); internal_resize( n, sizeof(T), max_size(), static_cast<const vo id*>(&t), &destroy_array, &initialize_array_by );
} catch(...) { } __TBB_CATCH(...) {
segment_t *table = my_segment; segment_t *table = my_segment;
internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block ); internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block );
throw; __TBB_RETHROW();
} }
} }
//! Construction with copying iteration range and given allocator insta nce //! Construction with copying iteration range and given allocator insta nce
template<class I> template<class I>
concurrent_vector(I first, I last, const allocator_type &a = allocator_ type()) concurrent_vector(I first, I last, const allocator_type &a = allocator_ type())
: internal::allocator_base<T, A>(a) : internal::allocator_base<T, A>(a)
{ {
vector_allocator_ptr = &internal_allocator; vector_allocator_ptr = &internal_allocator;
try { __TBB_TRY {
internal_assign_range(first, last, static_cast<is_integer_tag<s td::numeric_limits<I>::is_integer> *>(0) ); internal_assign_range(first, last, static_cast<is_integer_tag<s td::numeric_limits<I>::is_integer> *>(0) );
} catch(...) { } __TBB_CATCH(...) {
segment_t *table = my_segment; segment_t *table = my_segment;
internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block ); internal_free_segments( reinterpret_cast<void**>(table), intern al_clear(&destroy_array), my_first_block );
throw; __TBB_RETHROW();
} }
} }
//! Assignment //! Assignment
concurrent_vector& operator=( const concurrent_vector& vector ) { concurrent_vector& operator=( const concurrent_vector& vector ) {
if( this != &vector ) if( this != &vector )
internal_assign(vector, sizeof(T), &destroy_array, &assign_arra y, &copy_array); internal_assign(vector, sizeof(T), &destroy_array, &assign_arra y, &copy_array);
return *this; return *this;
} }
skipping to change at line 893 skipping to change at line 904
~internal_loop_guide() { ~internal_loop_guide() {
if(i < n) // if exception raised, do zerroing on the rest of it ems if(i < n) // if exception raised, do zerroing on the rest of it ems
std::memset(array+i, 0, (n-i)*sizeof(value_type)); std::memset(array+i, 0, (n-i)*sizeof(value_type));
} }
}; };
}; };
template<typename T, class A> template<typename T, class A>
void concurrent_vector<T, A>::shrink_to_fit() { void concurrent_vector<T, A>::shrink_to_fit() {
internal_segments_table old; internal_segments_table old;
try { __TBB_TRY {
if( internal_compact( sizeof(T), &old, &destroy_array, &copy_array ) ) if( internal_compact( sizeof(T), &old, &destroy_array, &copy_array ) )
internal_free_segments( old.table, pointers_per_long_table, old .first_block ); // free joined and unnecessary segments internal_free_segments( old.table, pointers_per_long_table, old .first_block ); // free joined and unnecessary segments
} catch(...) { } __TBB_CATCH(...) {
if( old.first_block ) // free segment allocated for compacting. Onl y for support of exceptions in ctor of user T[ype] if( old.first_block ) // free segment allocated for compacting. Onl y for support of exceptions in ctor of user T[ype]
internal_free_segments( old.table, 1, old.first_block ); internal_free_segments( old.table, 1, old.first_block );
throw; __TBB_RETHROW();
} }
} }
template<typename T, class A> template<typename T, class A>
void concurrent_vector<T, A>::internal_free_segments(void *table[], segment _index_t k, segment_index_t first_block) { void concurrent_vector<T, A>::internal_free_segments(void *table[], segment _index_t k, segment_index_t first_block) {
// Free the arrays // Free the arrays
while( k > first_block ) { while( k > first_block ) {
--k; --k;
T* array = static_cast<T*>(table[k]); T* array = static_cast<T*>(table[k]);
table[k] = NULL; table[k] = NULL;
if( array > __TBB_BAD_ALLOC ) // check for correct segment pointer if( array > internal::vector_allocation_error_flag ) // check for c orrect segment pointer
this->my_allocator.deallocate( array, segment_size(k) ); this->my_allocator.deallocate( array, segment_size(k) );
} }
T* array = static_cast<T*>(table[0]); T* array = static_cast<T*>(table[0]);
if( array > __TBB_BAD_ALLOC ) { if( array > internal::vector_allocation_error_flag ) {
__TBB_ASSERT( first_block > 0, NULL ); __TBB_ASSERT( first_block > 0, NULL );
while(k > 0) table[--k] = NULL; while(k > 0) table[--k] = NULL;
this->my_allocator.deallocate( array, segment_size(first_block) ); this->my_allocator.deallocate( array, segment_size(first_block) );
} }
} }
template<typename T, class A> template<typename T, class A>
T& concurrent_vector<T, A>::internal_subscript( size_type index ) const { T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
__TBB_ASSERT( index < my_early_size, "index out of bounds" ); __TBB_ASSERT( index < my_early_size, "index out of bounds" );
size_type j = index; size_type j = index;
segment_index_t k = segment_base_index_of( j ); segment_index_t k = segment_base_index_of( j );
__TBB_ASSERT( my_segment != (segment_t*)my_storage || k < pointers_per_ short_table, "index is being allocated" ); __TBB_ASSERT( (segment_t*)my_segment != my_storage || k < pointers_per_ short_table, "index is being allocated" );
// no need in __TBB_load_with_acquire since thread works in own space o r gets // no need in __TBB_load_with_acquire since thread works in own space o r gets
#if TBB_USE_THREADING_TOOLS #if TBB_USE_THREADING_TOOLS
T* array = static_cast<T*>( tbb::internal::itt_load_pointer_v3(&my_segm ent[k].array)); T* array = static_cast<T*>( tbb::internal::itt_load_pointer_v3(&my_segm ent[k].array));
#else #else
T* array = static_cast<T*>(my_segment[k].array); T* array = static_cast<T*>(my_segment[k].array);
#endif /* TBB_USE_THREADING_TOOLS */ #endif /* TBB_USE_THREADING_TOOLS */
__TBB_ASSERT( array != __TBB_BAD_ALLOC, "the instance is broken by bad allocation. Use at() instead" ); __TBB_ASSERT( array != internal::vector_allocation_error_flag, "the ins tance is broken by bad allocation. Use at() instead" );
__TBB_ASSERT( array, "index is being allocated" ); __TBB_ASSERT( array, "index is being allocated" );
return array[j]; return array[j];
} }
template<typename T, class A> template<typename T, class A>
T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type i ndex ) const { T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type i ndex ) const {
if( index >= my_early_size ) if( index >= my_early_size )
internal_throw_exception(0); // throw std::out_of_range internal::throw_exception(internal::eid_out_of_range); // throw std ::out_of_range
size_type j = index; size_type j = index;
segment_index_t k = segment_base_index_of( j ); segment_index_t k = segment_base_index_of( j );
if( my_segment == (segment_t*)my_storage && k >= pointers_per_short_tab if( (segment_t*)my_segment == my_storage && k >= pointers_per_short_tab
le ) le )
internal_throw_exception(1); // throw std::range_error internal::throw_exception(internal::eid_segment_range_error); // th
row std::range_error
void *array = my_segment[k].array; // no need in __TBB_load_with_acquir e void *array = my_segment[k].array; // no need in __TBB_load_with_acquir e
if( array <= __TBB_BAD_ALLOC ) // check for correct segment pointer if( array <= internal::vector_allocation_error_flag ) // check for corr
internal_throw_exception(2); // throw std::range_error ect segment pointer
internal::throw_exception(internal::eid_index_range_error); // thro
w std::range_error
return static_cast<T*>(array)[j]; return static_cast<T*>(array)[j];
} }
template<typename T, class A> template<class I> template<typename T, class A> template<class I>
void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) { void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
__TBB_ASSERT(my_early_size == 0, NULL); __TBB_ASSERT(my_early_size == 0, NULL);
size_type n = std::distance(first, last); size_type n = std::distance(first, last);
if( !n ) return; if( !n ) return;
internal_reserve(n, sizeof(T), max_size()); internal_reserve(n, sizeof(T), max_size());
my_early_size = n; my_early_size = n;
 End of changes. 34 change blocks. 
39 lines changed or deleted 55 lines changed or added


 enumerable_thread_specific.h   enumerable_thread_specific.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 121 skipping to change at line 121
enumerable_thread_specific_iterator &operator-=( ptrdiff_t offs et ) { enumerable_thread_specific_iterator &operator-=( ptrdiff_t offs et ) {
my_index -= offset; my_index -= offset;
my_value = NULL; my_value = NULL;
return *this; return *this;
} }
Value& operator*() const { Value& operator*() const {
Value* value = my_value; Value* value = my_value;
if( !value ) { if( !value ) {
value = my_value = &(*my_container)[my_index].value; value = my_value = reinterpret_cast<Value *>(&(*my_cont ainer)[my_index].value);
} }
__TBB_ASSERT( value==&(*my_container)[my_index].value, "cor rupt cache" ); __TBB_ASSERT( value==reinterpret_cast<Value *>(&(*my_contai ner)[my_index].value), "corrupt cache" );
return *value; return *value;
} }
Value& operator[]( ptrdiff_t k ) const { Value& operator[]( ptrdiff_t k ) const {
return (*my_container)[my_index + k].value; return (*my_container)[my_index + k].value;
} }
Value* operator->() const {return &operator*();} Value* operator->() const {return &operator*();}
enumerable_thread_specific_iterator& operator++() { enumerable_thread_specific_iterator& operator++() {
skipping to change at line 456 skipping to change at line 456
} }
/* override */ T apply() { return f(); } // does copy construc tion of returned value. /* override */ T apply() { return f(); } // does copy construc tion of returned value.
}; };
template<typename Key, typename T, typename HC, typename A> template<typename Key, typename T, typename HC, typename A>
class ets_concurrent_hash_map : public tbb::concurrent_hash_map<Key , T, HC, A> { class ets_concurrent_hash_map : public tbb::concurrent_hash_map<Key , T, HC, A> {
public: public:
typedef tbb::concurrent_hash_map<Key, T, HC, A> base_type; typedef tbb::concurrent_hash_map<Key, T, HC, A> base_type;
typedef typename base_type::const_pointer const_pointer; typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::key_type key_type; typedef typename base_type::key_type key_type;
const_pointer find( const key_type &k ) { return base_type::fin const_pointer find( const key_type &k ) {
d( k ); } // make public return this->internal_fast_find( k );
} // make public
};
//! Template for adding padding in order to avoid false sharing
/** ModularSize should be sizeof(U) modulo the cache line size.
All maintenance of the space will be done explicitly on push_ba
ck,
and all thread local copies must be destroyed before the concur
rent
vector is deleted.
*/
template<typename U, size_t ModularSize>
struct ets_element {
char value[sizeof(U) + NFS_MaxLineSize-ModularSize];
void unconstruct() {
// "reinterpret_cast<U*>(&value)->~U();" causes type-punnin
g warning with gcc 4.4,
// "U* u = reinterpret_cast<U*>(&value); u->~U();" causes u
nused variable warning with VS2010.
// Thus another "casting via union" hack.
union { void* space; U* val; } helper;
helper.space = &value;
helper.val->~U();
}
};
//! Partial specialization for case where no padding is needed.
template<typename U>
struct ets_element<U,0> {
char value[sizeof(U)];
void unconstruct() { // Same implementation as in general case
union { void* space; U* val; } helper;
helper.space = &value;
helper.val->~U();
}
}; };
} // namespace internal } // namespace internal
//! @endcond //! @endcond
//! The thread local class template //! The enumerable_thread_specific container
/** enumerable_thread_specific has the following properties:
- thread-local copies are lazily created, with default, exemplar or
function initialization.
- thread-local copies do not move (during lifetime, and excepting c
lear()) so the address of a copy is invariant.
- the contained objects need not have operator=() defined if combin
e is not used.
- enumerable_thread_specific containers may be copy-constructed or
assigned.
- thread-local copies can be managed by hash-table, or can be acces
sed via TLS storage for speed.
- outside of parallel contexts, the contents of all thread-local co
pies are accessible by iterator or using combine or combine_each methods
@par Segmented iterator
When the thread-local objects are containers with input_iterators d
efined, a segmented iterator may
be used to iterate over all the elements of all thread-local copies
.
@par combine and combine_each
- Both methods are defined for enumerable_thread_specific.
- combine() requires the the type T have operator=() defined.
- neither method modifies the contents of the object (though there
is no guarantee that the applied methods do not modify the object.)
- Both are evaluated in serial context (the methods are assumed to
be non-benign.)
@ingroup containers */
template <typename T, template <typename T,
typename Allocator=cache_aligned_allocator<T>, typename Allocator=cache_aligned_allocator<T>,
ets_key_usage_type ETS_key_type=ets_no_key > ets_key_usage_type ETS_key_type=ets_no_key >
class enumerable_thread_specific { class enumerable_thread_specific {
template<typename U, typename A, ets_key_usage_type C> friend class enumerable_thread_specific; template<typename U, typename A, ets_key_usage_type C> friend class enumerable_thread_specific;
typedef internal::tls_manager< ETS_key_type > my_tls_manager; typedef internal::tls_manager< ETS_key_type > my_tls_manager;
//! The padded elements; padded to avoid false sharing typedef internal::ets_element<T,sizeof(T)%internal::NFS_MaxLineSize
template<typename U> > padded_element;
struct padded_element {
U value;
char padding[ ( (sizeof(U) - 1) / internal::NFS_MaxLineSize + 1
) * internal::NFS_MaxLineSize - sizeof(U) ];
padded_element(const U &v) : value(v) {}
padded_element() {}
};
//! A generic range, used to create range objects from the iterator s //! A generic range, used to create range objects from the iterator s
template<typename I> template<typename I>
class generic_range_type: public blocked_range<I> { class generic_range_type: public blocked_range<I> {
public: public:
typedef T value_type; typedef T value_type;
typedef T& reference; typedef T& reference;
typedef const T& const_reference; typedef const T& const_reference;
typedef I iterator; typedef I iterator;
typedef ptrdiff_t difference_type; typedef ptrdiff_t difference_type;
generic_range_type( I begin_, I end_, size_t grainsize = 1) : b locked_range<I>(begin_,end_,grainsize) {} generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {}
template<typename U> template<typename U>
generic_range_type( const generic_range_type<U>& r) : blocked_r ange<I>(r.begin(),r.end(),r.grainsize()) {} generic_range_type( const generic_range_type<U>& r) : blocked_r ange<I>(r.begin(),r.end(),r.grainsize()) {}
generic_range_type( generic_range_type& r, split ) : blocked_ra nge<I>(r,split()) {} generic_range_type( generic_range_type& r, split ) : blocked_ra nge<I>(r,split()) {}
}; };
typedef typename Allocator::template rebind< padded_element<T> >::o typedef typename Allocator::template rebind< padded_element >::othe
ther padded_allocator_type; r padded_allocator_type;
typedef tbb::concurrent_vector< padded_element<T>, padded_allocator typedef tbb::concurrent_vector< padded_element, padded_allocator_ty
_type > internal_collection_type; pe > internal_collection_type;
typedef typename internal_collection_type::size_type hash_table_ind ex_type; // storing array indices rather than iterators to simplify typedef typename internal_collection_type::size_type hash_table_ind ex_type; // storing array indices rather than iterators to simplify
// copying the hash table that correlates thread IDs with concurren t vector elements. // copying the hash table that correlates thread IDs with concurren t vector elements.
typedef typename Allocator::template rebind< std::pair< typename in ternal::thread_hash_compare::thread_key, hash_table_index_type > >::other h ash_element_allocator; typedef typename Allocator::template rebind< std::pair< typename in ternal::thread_hash_compare::thread_key, hash_table_index_type > >::other h ash_element_allocator;
typedef internal::ets_concurrent_hash_map< typename internal::threa d_hash_compare::thread_key, hash_table_index_type, internal::thread_hash_co mpare, hash_element_allocator > thread_to_index_type; typedef internal::ets_concurrent_hash_map< typename internal::threa d_hash_compare::thread_key, hash_table_index_type, internal::thread_hash_co mpare, hash_element_allocator > thread_to_index_type;
typename my_tls_manager::tls_key_t my_key; typename my_tls_manager::tls_key_t my_key;
void reset_key() { void reset_key() {
my_tls_manager::destroy_key(my_key); my_tls_manager::destroy_key(my_key);
my_tls_manager::create_key(my_key); my_tls_manager::create_key(my_key);
} }
internal::callback_base<T> *my_finit_callback; internal::callback_base<T> *my_finit_callback;
// need to use a pointed-to exemplar because T may not be assignabl e. // need to use a pointed-to exemplar because T may not be assignabl e.
// using tbb_allocator instead of padded_element_allocator because we may be // using tbb_allocator instead of padded_element_allocator because we may be
// copying an exemplar from one instantiation of ETS to another wit h a different // copying an exemplar from one instantiation of ETS to another wit h a different
// allocator. // allocator.
typedef typename tbb::tbb_allocator<padded_element<T> > exemplar_al typedef typename tbb::tbb_allocator<padded_element > exemplar_alloc
locator_type; ator_type;
static padded_element<T> * create_exemplar(const T& my_value) { static padded_element * create_exemplar(const T& my_value) {
padded_element<T> *new_exemplar = 0; padded_element *new_exemplar = reinterpret_cast<padded_element
// void *new_space = padded_allocator_type().allocate(1); *>(exemplar_allocator_type().allocate(1));
void *new_space = exemplar_allocator_type().allocate(1); new(new_exemplar->value) T(my_value);
new_exemplar = new(new_space) padded_element<T>(my_value);
return new_exemplar; return new_exemplar;
} }
static padded_element<T> *create_exemplar( ) { static padded_element *create_exemplar( ) {
// void *new_space = padded_allocator_type().allocate(1); padded_element *new_exemplar = reinterpret_cast<padded_element
void *new_space = exemplar_allocator_type().allocate(1); *>(exemplar_allocator_type().allocate(1));
padded_element<T> *new_exemplar = new(new_space) padded_element new(new_exemplar->value) T( );
<T>( );
return new_exemplar; return new_exemplar;
} }
static void free_exemplar(padded_element<T> *my_ptr) { static void free_exemplar(padded_element *my_ptr) {
// padded_allocator_type().destroy(my_ptr); my_ptr->unconstruct();
// padded_allocator_type().deallocate(my_ptr,1);
exemplar_allocator_type().destroy(my_ptr); exemplar_allocator_type().destroy(my_ptr);
exemplar_allocator_type().deallocate(my_ptr,1); exemplar_allocator_type().deallocate(my_ptr,1);
} }
padded_element<T>* my_exemplar_ptr; padded_element* my_exemplar_ptr;
internal_collection_type my_locals; internal_collection_type my_locals;
thread_to_index_type my_hash_tbl; thread_to_index_type my_hash_tbl;
public: public:
//! Basic types //! Basic types
typedef Allocator allocator_type; typedef Allocator allocator_type;
typedef T value_type; typedef T value_type;
typedef T& reference; typedef T& reference;
skipping to change at line 567 skipping to change at line 607
// Iterator types // Iterator types
typedef typename internal::enumerable_thread_specific_iterator< int ernal_collection_type, value_type > iterator; typedef typename internal::enumerable_thread_specific_iterator< int ernal_collection_type, value_type > iterator;
typedef typename internal::enumerable_thread_specific_iterator< int ernal_collection_type, const value_type > const_iterator; typedef typename internal::enumerable_thread_specific_iterator< int ernal_collection_type, const value_type > const_iterator;
// Parallel range types // Parallel range types
typedef generic_range_type< iterator > range_type; typedef generic_range_type< iterator > range_type;
typedef generic_range_type< const_iterator > const_range_type; typedef generic_range_type< const_iterator > const_range_type;
//! Default constructor, which leads to default construction of loc al copies //! Default constructor, which leads to default construction of loc al copies
enumerable_thread_specific() : my_finit_callback(0) { enumerable_thread_specific() : my_finit_callback(0) {
my_exemplar_ptr = create_exemplar(); my_exemplar_ptr = 0;
my_tls_manager::create_key(my_key); my_tls_manager::create_key(my_key);
} }
//! construction with initializer method //! construction with initializer method
// Finit should be a function taking 0 parameters and returning a T // Finit should be a function taking 0 parameters and returning a T
template <typename Finit> template <typename Finit>
enumerable_thread_specific( Finit _finit ) enumerable_thread_specific( Finit _finit )
{ {
my_finit_callback = internal::callback_leaf<T,Finit>::new_callb ack( _finit ); my_finit_callback = internal::callback_leaf<T,Finit>::new_callb ack( _finit );
my_tls_manager::create_key(my_key);
my_exemplar_ptr = 0; // don't need exemplar if function is prov ided my_exemplar_ptr = 0; // don't need exemplar if function is prov ided
my_tls_manager::create_key(my_key);
} }
//! Constuction with exemplar, which leads to copy construction of local copies //! Constuction with exemplar, which leads to copy construction of local copies
enumerable_thread_specific(const T &_exemplar) : my_finit_callback( 0) { enumerable_thread_specific(const T &_exemplar) : my_finit_callback( 0) {
my_exemplar_ptr = create_exemplar(_exemplar); my_exemplar_ptr = create_exemplar(_exemplar);
my_tls_manager::create_key(my_key); my_tls_manager::create_key(my_key);
} }
//! Destructor //! Destructor
~enumerable_thread_specific() { ~enumerable_thread_specific() {
unconstruct_locals();
my_tls_manager::destroy_key(my_key); my_tls_manager::destroy_key(my_key);
if(my_finit_callback) { if(my_finit_callback) {
my_finit_callback->destroy(); my_finit_callback->destroy();
} }
if(my_exemplar_ptr) if(my_exemplar_ptr)
{ {
free_exemplar(my_exemplar_ptr); free_exemplar(my_exemplar_ptr);
} }
} }
skipping to change at line 631 skipping to change at line 672
// see if the table entry can be found by accessor // see if the table entry can be found by accessor
typename thread_to_index_type::accessor a; typename thread_to_index_type::accessor a;
if(!my_hash_tbl.insert(a, my_t_key)) { if(!my_hash_tbl.insert(a, my_t_key)) {
exists = true; exists = true;
local_index = a->second; local_index = a->second;
} }
else { else {
// create new entry // create new entry
exists = false; exists = false;
if(my_finit_callback) {
// convert iterator to array index
#if TBB_DEPRECATED #if TBB_DEPRECATED
local_index = my_locals.push_back(my_finit_call back->apply()); local_index = my_locals.push_back(padded_element()) ;
#else #else
local_index = my_locals.push_back(my_finit_call back->apply()) - my_locals.begin(); local_index = my_locals.push_back(padded_element()) - my_locals.begin();
#endif #endif
pointer lref = reinterpret_cast<T*>((my_locals[loc
al_index].value));
if(my_finit_callback) {
new(lref) T(my_finit_callback->apply());
}
else if(my_exemplar_ptr) {
pointer t_exemp = reinterpret_cast<T *>(&(my_ex
emplar_ptr->value));
new(lref) T(*t_exemp);
} }
else { else {
// convert iterator to array index new(lref) T();
#if TBB_DEPRECATED
local_index = my_locals.push_back(*my_exemplar_
ptr);
#else
local_index = my_locals.push_back(*my_exemplar_
ptr) - my_locals.begin();
#endif
} }
// insert into hash table // insert into hash table
a->second = local_index; a->second = local_index;
} }
} }
} }
reference local_ref = (my_locals[local_index].value); pointer local_ref = reinterpret_cast<T*>((my_locals[local_index
my_tls_manager::set_tls( my_key, static_cast<void *>(&local_ref ].value));
) ); my_tls_manager::set_tls( my_key, static_cast<void *>(local_ref)
return local_ref; );
return *local_ref;
} // local } // local
//! Get the number of local copies //! Get the number of local copies
size_type size() const { return my_locals.size(); } size_type size() const { return my_locals.size(); }
//! true if there have been no local copies created //! true if there have been no local copies created
bool empty() const { return my_locals.empty(); } bool empty() const { return my_locals.empty(); }
//! begin iterator //! begin iterator
iterator begin() { return iterator( my_locals, 0 ); } iterator begin() { return iterator( my_locals, 0 ); }
skipping to change at line 681 skipping to change at line 722
//! end const iterator //! end const iterator
const_iterator end() const { return const_iterator(my_locals, my_lo cals.size()); } const_iterator end() const { return const_iterator(my_locals, my_lo cals.size()); }
//! Get range for parallel algorithms //! Get range for parallel algorithms
range_type range( size_t grainsize=1 ) { return range_type( begin() , end(), grainsize ); } range_type range( size_t grainsize=1 ) { return range_type( begin() , end(), grainsize ); }
//! Get const range for parallel algorithms //! Get const range for parallel algorithms
const_range_type range( size_t grainsize=1 ) const { return const_r ange_type( begin(), end(), grainsize ); } const_range_type range( size_t grainsize=1 ) const { return const_r ange_type( begin(), end(), grainsize ); }
void unconstruct_locals() {
for(typename internal_collection_type::iterator cvi = my_locals
.begin(); cvi != my_locals.end(); ++cvi) {
cvi->unconstruct();
}
}
//! Destroys local copies //! Destroys local copies
void clear() { void clear() {
unconstruct_locals();
my_locals.clear(); my_locals.clear();
my_hash_tbl.clear(); my_hash_tbl.clear();
reset_key(); reset_key();
// callback is not destroyed // callback is not destroyed
// exemplar is not destroyed // exemplar is not destroyed
} }
// STL container methods // STL container methods
// copy constructor // copy constructor
private: private:
template<typename U, typename A2, ets_key_usage_type C2> template<typename U, typename A2, ets_key_usage_type C2>
void void
internal_copy_construct( const enumerable_thread_specific<U, A2, C2 >& other) { internal_copy_construct( const enumerable_thread_specific<U, A2, C2 >& other) {
typedef typename tbb::enumerable_thread_specific<U, A2, C2> oth er_type; typedef typename tbb::enumerable_thread_specific<U, A2, C2> oth er_type;
for(typename other_type::const_iterator ci = other.begin(); ci != other.end(); ++ci) { for(typename other_type::const_iterator ci = other.begin(); ci != other.end(); ++ci) {
my_locals.push_back(*ci); hash_table_index_type local_index;
#if TBB_DEPRECATED
local_index = my_locals.push_back(padded_element());
#else
local_index = my_locals.push_back(padded_element()) - my_lo
cals.begin();
#endif
(void) new(my_locals[local_index].value) T(*ci);
} }
if(other.my_finit_callback) { if(other.my_finit_callback) {
my_finit_callback = other.my_finit_callback->make_copy(); my_finit_callback = other.my_finit_callback->make_copy();
} }
else { else {
my_finit_callback = 0; my_finit_callback = 0;
} }
if(other.my_exemplar_ptr) { if(other.my_exemplar_ptr) {
my_exemplar_ptr = create_exemplar(other.my_exemplar_ptr->va pointer local_ref = reinterpret_cast<T*>(other.my_exemplar_
lue); ptr->value);
my_exemplar_ptr = create_exemplar(*local_ref);
} }
else { else {
my_exemplar_ptr = 0; my_exemplar_ptr = 0;
} }
my_tls_manager::create_key(my_key); my_tls_manager::create_key(my_key);
} }
public: public:
template<typename U, typename Alloc, ets_key_usage_type Cachetype> template<typename U, typename Alloc, ets_key_usage_type Cachetype>
enumerable_thread_specific( const enumerable_thread_specific<U, All oc, Cachetype>& other ) : my_hash_tbl(other.my_hash_tbl) enumerable_thread_specific( const enumerable_thread_specific<U, All oc, Cachetype>& other ) : my_hash_tbl(other.my_hash_tbl)
{ // Have to do push_back because the contained elements are not necessarily assignable. {
internal_copy_construct(other); internal_copy_construct(other);
} }
// non-templatized version
enumerable_thread_specific( const enumerable_thread_specific& other ) : my_hash_tbl(other.my_hash_tbl) enumerable_thread_specific( const enumerable_thread_specific& other ) : my_hash_tbl(other.my_hash_tbl)
{ {
internal_copy_construct(other); internal_copy_construct(other);
} }
private: private:
template<typename U, typename A2, ets_key_usage_type C2> template<typename U, typename A2, ets_key_usage_type C2>
enumerable_thread_specific & enumerable_thread_specific &
internal_assign(const enumerable_thread_specific<U, A2, C2>& other) { internal_assign(const enumerable_thread_specific<U, A2, C2>& other) {
typedef typename tbb::enumerable_thread_specific<U, A2, C2> oth er_type; typedef typename tbb::enumerable_thread_specific<U, A2, C2> oth er_type;
if(static_cast<void *>( this ) != static_cast<const void *>( &o ther )) { if(static_cast<void *>( this ) != static_cast<const void *>( &o ther )) {
this->clear(); // resets TLS key this->clear(); // resets TLS key
my_hash_tbl = other.my_hash_tbl; my_hash_tbl = other.my_hash_tbl;
// cannot use assign because T may not be assignable.
for(typename other_type::const_iterator ci = other.begin(); ci != other.end(); ++ci) { for(typename other_type::const_iterator ci = other.begin(); ci != other.end(); ++ci) {
my_locals.push_back(*ci); hash_table_index_type local_index;
#if TBB_DEPRECATED
local_index = my_locals.push_back(padded_element())
;
#else
local_index = my_locals.push_back(padded_element())
- my_locals.begin();
#endif
(void) new(my_locals[local_index].value) T(*ci);
} }
if(my_finit_callback) { if(my_finit_callback) {
my_finit_callback->destroy(); my_finit_callback->destroy();
my_finit_callback = 0; my_finit_callback = 0;
} }
if(my_exemplar_ptr) { if(my_exemplar_ptr) {
free_exemplar(my_exemplar_ptr); free_exemplar(my_exemplar_ptr);
my_exemplar_ptr = 0; my_exemplar_ptr = 0;
} }
if(other.my_finit_callback) { if(other.my_finit_callback) {
my_finit_callback = other.my_finit_callback->make_copy( ); my_finit_callback = other.my_finit_callback->make_copy( );
} }
if(other.my_exemplar_ptr) { if(other.my_exemplar_ptr) {
my_exemplar_ptr = create_exemplar(other.my_exemplar_ptr pointer local_ref = reinterpret_cast<T*>(other.my_exemp
->value); lar_ptr->value);
my_exemplar_ptr = create_exemplar(*local_ref);
} }
} }
return *this; return *this;
} }
public: public:
// assignment // assignment
enumerable_thread_specific& operator=(const enumerable_thread_speci fic& other) { enumerable_thread_specific& operator=(const enumerable_thread_speci fic& other) {
return internal_assign(other); return internal_assign(other);
} }
template<typename U, typename Alloc, ets_key_usage_type Cachetype> template<typename U, typename Alloc, ets_key_usage_type Cachetype>
enumerable_thread_specific& operator=(const enumerable_thread_speci fic<U, Alloc, Cachetype>& other) enumerable_thread_specific& operator=(const enumerable_thread_speci fic<U, Alloc, Cachetype>& other)
{ {
return internal_assign(other); return internal_assign(other);
} }
private:
// combine_func_t has signature T(T,T) or T(const T&, const T&)
template <typename combine_func_t>
T internal_combine(typename internal_collection_type::const_range_t
ype r, combine_func_t f_combine) {
if(r.is_divisible()) {
typename internal_collection_type::const_range_type r2(r,sp
lit());
return f_combine(internal_combine(r2, f_combine), internal_
combine(r, f_combine));
}
if(r.size() == 1) {
return r.begin()->value;
}
typename internal_collection_type::const_iterator i2 = r.begin(
);
++i2;
return f_combine(r.begin()->value, i2->value);
}
public:
// combine_func_t has signature T(T,T) or T(const T&, const T&) // combine_func_t has signature T(T,T) or T(const T&, const T&)
template <typename combine_func_t> template <typename combine_func_t>
T combine(combine_func_t f_combine) { T combine(combine_func_t f_combine) {
if(my_locals.begin() == my_locals.end()) { if(begin() == end()) {
if(my_finit_callback) { if(my_finit_callback) {
return my_finit_callback->apply(); return my_finit_callback->apply();
} }
return (*my_exemplar_ptr).value; pointer local_ref = reinterpret_cast<T*>((my_exemplar_ptr->
value));
return T(*local_ref);
} }
typename internal_collection_type::const_range_type r(my_locals const_iterator ci = begin();
.begin(), my_locals.end(), (size_t)2); T my_result = *ci;
return internal_combine(r, f_combine); while(++ci != end())
my_result = f_combine( my_result, *ci );
return my_result;
} }
// combine_func_t has signature void(T) or void(const T&) // combine_func_t has signature void(T) or void(const T&)
template <typename combine_func_t> template <typename combine_func_t>
void combine_each(combine_func_t f_combine) { void combine_each(combine_func_t f_combine) {
for(const_iterator ci = begin(); ci != end(); ++ci) { for(const_iterator ci = begin(); ci != end(); ++ci) {
f_combine( *ci ); f_combine( *ci );
} }
} }
}; // enumerable_thread_specific }; // enumerable_thread_specific
template< typename Container > template< typename Container >
class flattened2d { class flattened2d {
// This intermediate typedef is to address issues with VC7.1 compil ers // This intermediate typedef is to address issues with VC7.1 compil ers
typedef typename Container::value_type conval_type; typedef typename Container::value_type conval_type;
public: public:
 End of changes. 36 change blocks. 
91 lines changed or deleted 152 lines changed or added


 ibm_aix51.h   ibm_aix51.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 linux_common.h   linux_common.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 38 skipping to change at line 38
#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
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <sched.h> #include <sched.h>
// Definition of __TBB_Yield() // Definition of __TBB_Yield()
#ifndef __TBB_Yield
#define __TBB_Yield() sched_yield() #define __TBB_Yield() sched_yield()
#endif
/* Futex definitions */ /* Futex definitions */
#include <sys/syscall.h> #include <sys/syscall.h>
#if defined(SYS_futex) #if defined(SYS_futex)
#define __TBB_USE_FUTEX 1 #define __TBB_USE_FUTEX 1
#include <limits.h> #include <limits.h>
#include <errno.h> #include <errno.h>
// Unfortunately, some versions of Linux do not have a header that defines FUTEX_WAIT and FUTEX_WAKE. // Unfortunately, some versions of Linux do not have a header that defines FUTEX_WAIT and FUTEX_WAKE.
 End of changes. 3 change blocks. 
1 lines changed or deleted 3 lines changed or added


 linux_ia32.h   linux_ia32.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 44 skipping to change at line 44
#include "linux_common.h" #include "linux_common.h"
#endif #endif
#define __TBB_WORDSIZE 4 #define __TBB_WORDSIZE 4
#define __TBB_BIG_ENDIAN 0 #define __TBB_BIG_ENDIAN 0
#define __TBB_release_consistency_helper() __asm__ __volatile__("": : :"mem ory") #define __TBB_release_consistency_helper() __asm__ __volatile__("": : :"mem ory")
inline void __TBB_rel_acq_fence() { __asm__ __volatile__("mfence": : :"memo ry"); } inline void __TBB_rel_acq_fence() { __asm__ __volatile__("mfence": : :"memo ry"); }
#if __TBB_ICC_ASM_VOLATILE_BROKEN
#define __TBB_VOLATILE
#else
#define __TBB_VOLATILE volatile
#endif
#define __MACHINE_DECL_ATOMICS(S,T,X) \ #define __MACHINE_DECL_ATOMICS(S,T,X) \
static inline T __TBB_machine_cmpswp##S (volatile void *ptr, T value, T com parand ) \ static inline T __TBB_machine_cmpswp##S (volatile void *ptr, T value, T com parand ) \
{ \ { \
T result; \ T result; \
\ \
__asm__ __volatile__("lock\ncmpxchg" X " %2,%1" \ __asm__ __volatile__("lock\ncmpxchg" X " %2,%1" \
: "=a"(result), "=m"(*(T *)ptr) : "=a"(result), "=m"(*(__TBB_VOLATILE T*)ptr)
\ \
: "q"(value), "0"(comparand), "m"(*(T *)ptr) : "q"(value), "0"(comparand), "m"(*(__TBB_VOLATIL
\ E T*)ptr) \
: "memory"); \ : "memory"); \
return result; \ return result; \
} \ } \
\ \
static inline T __TBB_machine_fetchadd##S(volatile void *ptr, T addend) \ static inline T __TBB_machine_fetchadd##S(volatile void *ptr, T addend) \
{ \ { \
T result; \ T result; \
__asm__ __volatile__("lock\nxadd" X " %0,%1" \ __asm__ __volatile__("lock\nxadd" X " %0,%1" \
: "=r"(result), "=m"(*(T *)ptr) : "=r"(result), "=m"(*(__TBB_VOLATILE T*)ptr)
\ \
: "0"(addend), "m"(*(T *)ptr) : "0"(addend), "m"(*(__TBB_VOLATILE T*)ptr)
\ \
: "memory"); \ : "memory"); \
return result; \ return result; \
} \ } \
\ \
static inline T __TBB_machine_fetchstore##S(volatile void *ptr, T value) \ static inline T __TBB_machine_fetchstore##S(volatile void *ptr, T value) \
{ \ { \
T result; \ T result; \
__asm__ __volatile__("lock\nxchg" X " %0,%1" \ __asm__ __volatile__("lock\nxchg" X " %0,%1" \
: "=r"(result), "=m"(*(T *)ptr) : "=r"(result), "=m"(*(__TBB_VOLATILE T*)ptr)
\ \
: "0"(value), "m"(*(T *)ptr) : "0"(value), "m"(*(__TBB_VOLATILE T*)ptr)
\ \
: "memory"); \ : "memory"); \
return result; \ return result; \
} \ } \
__MACHINE_DECL_ATOMICS(1,int8_t,"") __MACHINE_DECL_ATOMICS(1,int8_t,"")
__MACHINE_DECL_ATOMICS(2,int16_t,"") __MACHINE_DECL_ATOMICS(2,int16_t,"")
__MACHINE_DECL_ATOMICS(4,int32_t,"l") __MACHINE_DECL_ATOMICS(4,int32_t,"l")
static inline int64_t __TBB_machine_cmpswp8 (volatile void *ptr, int64_t va lue, int64_t comparand ) static inline int64_t __TBB_machine_cmpswp8 (volatile void *ptr, int64_t va lue, int64_t comparand )
{ {
int64_t result; int64_t result;
#if __PIC__ #if __PIC__
/* compiling position-independent code */ /* compiling position-independent code */
// EBX register preserved for compliancy with position-independent code rules on IA32 // EBX register preserved for compliance with position-independent code rules on IA32
__asm__ __volatile__ ( __asm__ __volatile__ (
"pushl %%ebx\n\t" "pushl %%ebx\n\t"
"movl (%%ecx),%%ebx\n\t" "movl (%%ecx),%%ebx\n\t"
"movl 4(%%ecx),%%ecx\n\t" "movl 4(%%ecx),%%ecx\n\t"
"lock\n\t cmpxchg8b %1\n\t" "lock\n\t cmpxchg8b %1\n\t"
"popl %%ebx" "popl %%ebx"
: "=A"(result), "=m"(*(int64_t *)ptr) : "=A"(result), "=m"(*(int64_t *)ptr)
: "m"(*(int64_t *)ptr) : "m"(*(int64_t *)ptr)
, "0"(comparand) , "0"(comparand)
, "c"(&value) , "c"(&value)
skipping to change at line 109 skipping to change at line 115
#endif #endif
); );
#else /* !__PIC__ */ #else /* !__PIC__ */
union { union {
int64_t i64; int64_t i64;
int32_t i32[2]; int32_t i32[2];
}; };
i64 = value; i64 = value;
__asm__ __volatile__ ( __asm__ __volatile__ (
"lock\n\t cmpxchg8b %1\n\t" "lock\n\t cmpxchg8b %1\n\t"
: "=A"(result), "=m"(*(int64_t *)ptr) : "=A"(result), "=m"(*(__TBB_VOLATILE int64_t *)ptr)
: "m"(*(int64_t *)ptr) : "m"(*(__TBB_VOLATILE int64_t *)ptr)
, "0"(comparand) , "0"(comparand)
, "b"(i32[0]), "c"(i32[1]) , "b"(i32[0]), "c"(i32[1])
: "memory" : "memory"
); );
#endif /* __PIC__ */ #endif /* __PIC__ */
return result; return result;
} }
static inline int32_t __TBB_machine_lg( uint32_t x ) { static inline int32_t __TBB_machine_lg( uint32_t x ) {
int32_t j; int32_t j;
__asm__ ("bsr %1,%0" : "=r"(j) : "r"(x)); __asm__ ("bsr %1,%0" : "=r"(j) : "r"(x));
return j; return j;
} }
static inline void __TBB_machine_or( volatile void *ptr, uint32_t addend ) { static inline void __TBB_machine_or( volatile void *ptr, uint32_t addend ) {
__asm__ __volatile__("lock\norl %1,%0" : "=m"(*(uint32_t *)ptr) : "r"(a ddend), "m"(*(uint32_t *)ptr) : "memory"); __asm__ __volatile__("lock\norl %1,%0" : "=m"(*(__TBB_VOLATILE uint32_t *)ptr) : "r"(addend), "m"(*(__TBB_VOLATILE uint32_t *)ptr) : "memory");
} }
static inline void __TBB_machine_and( volatile void *ptr, uint32_t addend ) { static inline void __TBB_machine_and( volatile void *ptr, uint32_t addend ) {
__asm__ __volatile__("lock\nandl %1,%0" : "=m"(*(uint32_t *)ptr) : "r"( addend), "m"(*(uint32_t *)ptr) : "memory"); __asm__ __volatile__("lock\nandl %1,%0" : "=m"(*(__TBB_VOLATILE uint32_ t *)ptr) : "r"(addend), "m"(*(__TBB_VOLATILE uint32_t *)ptr) : "memory");
} }
static inline void __TBB_machine_pause( int32_t delay ) { static inline void __TBB_machine_pause( int32_t delay ) {
for (int32_t i = 0; i < delay; i++) { for (int32_t i = 0; i < delay; i++) {
__asm__ __volatile__("pause;"); __asm__ __volatile__("pause;");
} }
return; return;
} }
static inline int64_t __TBB_machine_load8 (const volatile void *ptr) { static inline int64_t __TBB_machine_load8 (const volatile void *ptr) {
int64_t result; int64_t result;
if( ((uint32_t)ptr&7u)==0 ) { if( ((uint32_t)ptr&7u)==0 ) {
// Aligned load // Aligned load
__asm__ __volatile__ ( "fildq %1\n\t" __asm__ __volatile__ ( "fildq %1\n\t"
"fistpq %0" : "=m"(result) : "m"(*(uint64_t *)ptr) : "memory" ); "fistpq %0" : "=m"(result) : "m"(*(const __ TBB_VOLATILE uint64_t*)ptr) : "memory" );
} else { } else {
// Unaligned load // Unaligned load
result = __TBB_machine_cmpswp8((void*)ptr,0,0); result = __TBB_machine_cmpswp8(const_cast<void*>(ptr),0,0);
} }
return result; return result;
} }
//! 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( ((uint32_t)ptr&7u)==0 ) {
// Aligned store // Aligned store
__asm__ __volatile__ ( "fildq %1\n\t" __asm__ __volatile__ ( "fildq %1\n\t"
"fistpq %0" : "=m"(*(int64_t *)ptr) : "m"(v alue) : "memory" ); "fistpq %0" : "=m"(*(__TBB_VOLATILE int64_t *)ptr) : "m"(value) : "memory" );
} 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);
} }
} }
template <typename T, size_t S> template <typename T, size_t S>
skipping to change at line 189 skipping to change at line 195
static inline void store_with_release(volatile T &location, T value) { static inline void store_with_release(volatile T &location, T value) {
__asm__ __volatile__("" : : : "memory" ); // Compiler fence to ke ep operations from migrating upwards __asm__ __volatile__("" : : : "memory" ); // Compiler fence to ke ep operations from migrating upwards
location = value; location = value;
} }
}; };
template <typename T> template <typename T>
struct __TBB_machine_load_store<T,8> { struct __TBB_machine_load_store<T,8> {
static inline T load_with_acquire(const volatile T& location) { static inline T load_with_acquire(const volatile T& location) {
T to_return = __TBB_machine_load8((volatile void *)&location); T to_return = __TBB_machine_load8((const volatile void *)&location) ;
__asm__ __volatile__("" : : : "memory" ); // Compiler fence to ke ep operations from migrating upwards __asm__ __volatile__("" : : : "memory" ); // Compiler fence to ke ep operations from migrating upwards
return to_return; return to_return;
} }
static inline void store_with_release(volatile T &location, T value) { static inline void store_with_release(volatile T &location, T value) {
__asm__ __volatile__("" : : : "memory" ); // Compiler fence to ke ep operations from migrating downwards __asm__ __volatile__("" : : : "memory" ); // Compiler fence to ke ep operations from migrating downwards
__TBB_machine_store8((volatile void *)&location,(int64_t)value); __TBB_machine_store8((volatile void *)&location,(int64_t)value);
} }
}; };
#undef __TBB_VOLATILE
template<typename T> template<typename T>
inline T __TBB_machine_load_with_acquire(const volatile T &location) { inline T __TBB_machine_load_with_acquire(const volatile T &location) {
return __TBB_machine_load_store<T,sizeof(T)>::load_with_acquire(locatio n); return __TBB_machine_load_store<T,sizeof(T)>::load_with_acquire(locatio n);
} }
template<typename T, typename V> template<typename T, typename V>
inline void __TBB_machine_store_with_release(volatile T &location, V value) { inline void __TBB_machine_store_with_release(volatile T &location, V value) {
__TBB_machine_load_store<T,sizeof(T)>::store_with_release(location,valu e); __TBB_machine_load_store<T,sizeof(T)>::store_with_release(location,valu e);
} }
 End of changes. 14 change blocks. 
22 lines changed or deleted 30 lines changed or added


 linux_ia64.h   linux_ia64.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 linux_intel64.h   linux_intel64.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 40 skipping to change at line 40
#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
#include "linux_common.h" #include "linux_common.h"
#define __TBB_WORDSIZE 8 #define __TBB_WORDSIZE 8
#define __TBB_BIG_ENDIAN 0 #define __TBB_BIG_ENDIAN 0
#define __TBB_release_consistency_helper() __asm__ __volatile__("": : :"mem ory") #define __TBB_release_consistency_helper() __asm__ __volatile__("": : :"mem ory")
#ifndef __TBB_rel_acq_fence
inline void __TBB_rel_acq_fence() { __asm__ __volatile__("mfence": : :"memo ry"); } inline void __TBB_rel_acq_fence() { __asm__ __volatile__("mfence": : :"memo ry"); }
#endif
#define __MACHINE_DECL_ATOMICS(S,T,X) \ #define __MACHINE_DECL_ATOMICS(S,T,X) \
static inline T __TBB_machine_cmpswp##S (volatile void *ptr, T value, T com parand ) \ static inline T __TBB_machine_cmpswp##S (volatile void *ptr, T value, T com parand ) \
{ \ { \
T result; \ T result; \
\ \
__asm__ __volatile__("lock\ncmpxchg" X " %2,%1" \ __asm__ __volatile__("lock\ncmpxchg" X " %2,%1" \
: "=a"(result), "=m"(*(T *)ptr) : "=a"(result), "=m"(*(volatile T*)ptr)
\ \
: "q"(value), "0"(comparand), "m"(*(T *)ptr) : "q"(value), "0"(comparand), "m"(*(volatile T*)p
\ tr) \
: "memory"); \ : "memory"); \
return result; \ return result; \
} \ } \
\ \
static inline T __TBB_machine_fetchadd##S(volatile void *ptr, T addend) \ static inline T __TBB_machine_fetchadd##S(volatile void *ptr, T addend) \
{ \ { \
T result; \ T result; \
__asm__ __volatile__("lock\nxadd" X " %0,%1" \ __asm__ __volatile__("lock\nxadd" X " %0,%1" \
: "=r"(result),"=m"(*(T *)ptr) : "=r"(result),"=m"(*(volatile T*)ptr)
\ \
: "0"(addend), "m"(*(T *)ptr) : "0"(addend), "m"(*(volatile T*)ptr)
\ \
: "memory"); \ : "memory"); \
return result; \ return result; \
} \ } \
\ \
static inline T __TBB_machine_fetchstore##S(volatile void *ptr, T value) \ static inline T __TBB_machine_fetchstore##S(volatile void *ptr, T value) \
{ \ { \
T result; \ T result; \
__asm__ __volatile__("lock\nxchg" X " %0,%1" \ __asm__ __volatile__("lock\nxchg" X " %0,%1" \
: "=r"(result),"=m"(*(T *)ptr) : "=r"(result),"=m"(*(volatile T*)ptr)
\ \
: "0"(value), "m"(*(T *)ptr) : "0"(value), "m"(*(volatile T*)ptr)
\ \
: "memory"); \ : "memory"); \
return result; \ return result; \
} \ } \
__MACHINE_DECL_ATOMICS(1,int8_t,"") __MACHINE_DECL_ATOMICS(1,int8_t,"")
__MACHINE_DECL_ATOMICS(2,int16_t,"") __MACHINE_DECL_ATOMICS(2,int16_t,"")
__MACHINE_DECL_ATOMICS(4,int32_t,"") __MACHINE_DECL_ATOMICS(4,int32_t,"")
__MACHINE_DECL_ATOMICS(8,int64_t,"q") __MACHINE_DECL_ATOMICS(8,int64_t,"q")
static inline int64_t __TBB_machine_lg( uint64_t x ) { static inline int64_t __TBB_machine_lg( uint64_t x ) {
int64_t j; int64_t j;
__asm__ ("bsr %1,%0" : "=r"(j) : "r"(x)); __asm__ ("bsr %1,%0" : "=r"(j) : "r"(x));
return j; return j;
} }
static inline void __TBB_machine_or( volatile void *ptr, uint64_t addend ) { static inline void __TBB_machine_or( volatile void *ptr, uint64_t addend ) {
__asm__ __volatile__("lock\norq %1,%0" : "=m"(*(uint64_t *)ptr) : "r"(a ddend), "m"(*(uint64_t *)ptr) : "memory"); __asm__ __volatile__("lock\norq %1,%0" : "=m"(*(volatile uint64_t*)ptr) : "r"(addend), "m"(*(volatile uint64_t*)ptr) : "memory");
} }
static inline void __TBB_machine_and( volatile void *ptr, uint64_t addend ) { static inline void __TBB_machine_and( volatile void *ptr, uint64_t addend ) {
__asm__ __volatile__("lock\nandq %1,%0" : "=m"(*(uint64_t *)ptr) : "r"( addend), "m"(*(uint64_t *)ptr) : "memory"); __asm__ __volatile__("lock\nandq %1,%0" : "=m"(*(volatile uint64_t*)ptr ) : "r"(addend), "m"(*(volatile uint64_t*)ptr) : "memory");
} }
static inline void __TBB_machine_pause( int32_t delay ) { static inline void __TBB_machine_pause( int32_t delay ) {
for (int32_t i = 0; i < delay; i++) { for (int32_t i = 0; i < delay; i++) {
__asm__ __volatile__("pause;"); __asm__ __volatile__("pause;");
} }
return; return;
} }
// Machine specific atomic operations // Machine specific atomic operations
skipping to change at line 127 skipping to change at line 129
#define __TBB_FetchAndStore8(P,V) __TBB_machine_fetchstore8(P,V) #define __TBB_FetchAndStore8(P,V) __TBB_machine_fetchstore8(P,V)
#define __TBB_FetchAndStoreW(P,V) __TBB_machine_fetchstore8(P,V) #define __TBB_FetchAndStoreW(P,V) __TBB_machine_fetchstore8(P,V)
#define __TBB_Store8(P,V) (*P = V) #define __TBB_Store8(P,V) (*P = V)
#define __TBB_Load8(P) (*P) #define __TBB_Load8(P) (*P)
#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)
// Definition of other functions // Definition of other functions
#ifndef __TBB_Pause
#define __TBB_Pause(V) __TBB_machine_pause(V) #define __TBB_Pause(V) __TBB_machine_pause(V)
#endif
#define __TBB_Log2(V) __TBB_machine_lg(V) #define __TBB_Log2(V) __TBB_machine_lg(V)
// Special atomic functions // Special atomic functions
#define __TBB_FetchAndAddWrelease(P,V) __TBB_FetchAndAddW(P,V) #define __TBB_FetchAndAddWrelease(P,V) __TBB_FetchAndAddW(P,V)
#define __TBB_FetchAndIncrementWacquire(P) __TBB_FetchAndAddW(P,1) #define __TBB_FetchAndIncrementWacquire(P) __TBB_FetchAndAddW(P,1)
#define __TBB_FetchAndDecrementWrelease(P) __TBB_FetchAndAddW(P,-1) #define __TBB_FetchAndDecrementWrelease(P) __TBB_FetchAndAddW(P,-1)
// Use generic definitions from tbb_machine.h // Use generic definitions from tbb_machine.h
#undef __TBB_TryLockByte #undef __TBB_TryLockByte
#undef __TBB_LockByte #undef __TBB_LockByte
 End of changes. 10 change blocks. 
15 lines changed or deleted 19 lines changed or added


 mac_ppc.h   mac_ppc.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 mutex.h   mutex.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 33 skipping to change at line 33
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_mutex_H #ifndef __TBB_mutex_H
#define __TBB_mutex_H #define __TBB_mutex_H
#if _WIN32||_WIN64 #if _WIN32||_WIN64
#include <windows.h> #include <windows.h>
#if !defined(_WIN32_WINNT) #if !defined(_WIN32_WINNT)
// The following Windows API function is declared explicitly; // The following Windows API function is declared explicitly;
// otherwise any user would have to specify /D_WIN32_WINNT=0x0400 // otherwise any user would have to specify /D_WIN32_WINNT=0x0400
extern "C" BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION ); extern "C" BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION );
#endif #endif
#else /* if not _WIN32||_WIN64 */ #else /* if not _WIN32||_WIN64 */
#include <pthread.h> #include <pthread.h>
namespace tbb { namespace internal {
// Use this internal TBB function to throw an exception
extern void handle_perror( int error_code, const char* what );
} } //namespaces
#endif /* _WIN32||_WIN64 */ #endif /* _WIN32||_WIN64 */
#include <new> #include <new>
#include "aligned_space.h" #include "aligned_space.h"
#include "tbb_stddef.h" #include "tbb_stddef.h"
#include "tbb_profiling.h" #include "tbb_profiling.h"
namespace tbb { namespace tbb {
//! Wrapper around the platform's native reader-writer lock. //! Wrapper around the platform's native reader-writer lock.
skipping to change at line 100 skipping to change at line 95
//! The scoped locking pattern //! The scoped locking pattern
/** It helps to avoid the common problem of forgetting to release lock. /** It helps to avoid the common problem of forgetting to release lock.
It also nicely provides the "node" for queuing locks. */ It also nicely provides the "node" for queuing locks. */
class scoped_lock : internal::no_copy { class scoped_lock : internal::no_copy {
public: public:
//! Construct lock that has not acquired a mutex. //! Construct lock that has not acquired a mutex.
scoped_lock() : my_mutex(NULL) {}; scoped_lock() : my_mutex(NULL) {};
//! Acquire lock on given mutex. //! Acquire lock on given mutex.
/** Upon entry, *this should not be in the "have acquired a mutex" state. */
scoped_lock( mutex& mutex ) { scoped_lock( mutex& mutex ) {
acquire( mutex ); acquire( mutex );
} }
//! Release lock (if lock is held). //! Release lock (if lock is held).
~scoped_lock() { ~scoped_lock() {
if( my_mutex ) if( my_mutex )
release(); release();
} }
skipping to change at line 213 skipping to change at line 207
s.internal_release(); s.internal_release();
#else #else
#if _WIN32||_WIN64 #if _WIN32||_WIN64
LeaveCriticalSection(&impl); LeaveCriticalSection(&impl);
#else #else
pthread_mutex_unlock(&impl); pthread_mutex_unlock(&impl);
#endif /* _WIN32||_WIN64 */ #endif /* _WIN32||_WIN64 */
#endif /* TBB_USE_ASSERT */ #endif /* TBB_USE_ASSERT */
} }
private: //! Return native_handle
#if _WIN32||_WIN64 #if _WIN32||_WIN64
CRITICAL_SECTION impl; typedef LPCRITICAL_SECTION native_handle_type;
#else
typedef pthread_mutex_t* native_handle_type;
#endif
native_handle_type native_handle() { return (native_handle_type) &impl;
}
enum state_t { enum state_t {
INITIALIZED=0x1234, INITIALIZED=0x1234,
DESTROYED=0x789A, DESTROYED=0x789A,
HELD=0x56CD HELD=0x56CD
} state; };
private:
#if _WIN32||_WIN64
CRITICAL_SECTION impl;
enum state_t state;
#else #else
pthread_mutex_t impl; pthread_mutex_t impl;
#endif /* _WIN32||_WIN64 */ #endif /* _WIN32||_WIN64 */
//! All checks from mutex constructor using mutex.state were moved here //! All checks from mutex constructor using mutex.state were moved here
void __TBB_EXPORTED_METHOD internal_construct(); void __TBB_EXPORTED_METHOD internal_construct();
//! All checks from mutex destructor using mutex.state were moved here //! All checks from mutex destructor using mutex.state were moved here
void __TBB_EXPORTED_METHOD internal_destroy(); void __TBB_EXPORTED_METHOD internal_destroy();
#if _WIN32||_WIN64
public:
//! Set the internal state
void set_state( state_t to ) { state = to; }
#endif
}; };
__TBB_DEFINE_PROFILING_SET_NAME(mutex) __TBB_DEFINE_PROFILING_SET_NAME(mutex)
} // namespace tbb } // namespace tbb
#endif /* __TBB_mutex_H */ #endif /* __TBB_mutex_H */
 End of changes. 7 change blocks. 
18 lines changed or deleted 28 lines changed or added


 null_mutex.h   null_mutex.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 null_rw_mutex.h   null_rw_mutex.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 parallel_do.h   parallel_do.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 179 skipping to change at line 179
public: public:
const Body* my_body; const Body* my_body;
empty_task* my_barrier; empty_task* my_barrier;
parallel_do_feeder_impl() parallel_do_feeder_impl()
{ {
my_barrier = new( task::allocate_root() ) empty_task(); my_barrier = new( task::allocate_root() ) empty_task();
__TBB_ASSERT(my_barrier, "root task allocation failed"); __TBB_ASSERT(my_barrier, "root task allocation failed");
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
parallel_do_feeder_impl(tbb::task_group_context &context) parallel_do_feeder_impl(tbb::task_group_context &context)
{ {
my_barrier = new( task::allocate_root(context) ) empty_task(); my_barrier = new( task::allocate_root(context) ) empty_task();
__TBB_ASSERT(my_barrier, "root task allocation failed"); __TBB_ASSERT(my_barrier, "root task allocation failed");
} }
#endif #endif
~parallel_do_feeder_impl() ~parallel_do_feeder_impl()
{ {
my_barrier->destroy(*my_barrier); my_barrier->destroy(*my_barrier);
skipping to change at line 395 skipping to change at line 395
} }
return NULL; return NULL;
} }
}; // class do_task_iter }; // class do_task_iter
//! For internal use only. //! For internal use only.
/** Implements parallel iteration over a range. /** Implements parallel iteration over a range.
@ingroup algorithms */ @ingroup algorithms */
template<typename Iterator, typename Body, typename Item> template<typename Iterator, typename Body, typename Item>
void run_parallel_do( Iterator first, Iterator last, const Body& body void run_parallel_do( Iterator first, Iterator last, const Body& body
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, task_group_context& context , task_group_context& context
#endif #endif
) )
{ {
typedef do_task_iter<Iterator, Body, Item> root_iteration_task; typedef do_task_iter<Iterator, Body, Item> root_iteration_task;
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
parallel_do_feeder_impl<Body, Item> feeder(context); parallel_do_feeder_impl<Body, Item> feeder(context);
#else #else
parallel_do_feeder_impl<Body, Item> feeder; parallel_do_feeder_impl<Body, Item> feeder;
#endif #endif
feeder.my_body = &body; feeder.my_body = &body;
root_iteration_task &t = *new( feeder.my_barrier->allocate_child() ) root_iteration_task(first, last, feeder); root_iteration_task &t = *new( feeder.my_barrier->allocate_child() ) root_iteration_task(first, last, feeder);
feeder.my_barrier->set_ref_count(2); feeder.my_barrier->set_ref_count(2);
feeder.my_barrier->spawn_and_wait_for_all(t); feeder.my_barrier->spawn_and_wait_for_all(t);
} }
//! For internal use only. //! For internal use only.
/** Detects types of Body's operator function arguments. /** Detects types of Body's operator function arguments.
@ingroup algorithms **/ @ingroup algorithms **/
template<typename Iterator, typename Body, typename Item> template<typename Iterator, typename Body, typename Item>
void select_parallel_do( Iterator first, Iterator last, const Body& bod y, void (Body::*)(Item) const void select_parallel_do( Iterator first, Iterator last, const Body& bod y, void (Body::*)(Item) const
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, task_group_context& context , task_group_context& context
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
) )
{ {
run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, context , context
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
); );
} }
//! For internal use only. //! For internal use only.
/** Detects types of Body's operator function arguments. /** Detects types of Body's operator function arguments.
@ingroup algorithms **/ @ingroup algorithms **/
template<typename Iterator, typename Body, typename Item, typename _Ite m> template<typename Iterator, typename Body, typename Item, typename _Ite m>
void select_parallel_do( Iterator first, Iterator last, const Body& bod y, void (Body::*)(Item, parallel_do_feeder<_Item>&) const void select_parallel_do( Iterator first, Iterator last, const Body& bod y, void (Body::*)(Item, parallel_do_feeder<_Item>&) const
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, task_group_context& context , task_group_context& context
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
) )
{ {
run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, context , context
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
); );
} }
} // namespace internal } // namespace internal
//! @endcond //! @endcond
/** \page parallel_do_body_req Requirements on parallel_do body /** \page parallel_do_body_req Requirements on parallel_do body
Class \c Body implementing the concept of parallel_do body must define: Class \c Body implementing the concept of parallel_do body must define:
- \code - \code
B::operator()( B::operator()(
skipping to change at line 480 skipping to change at line 480
/** \name parallel_do /** \name parallel_do
See also requirements on \ref parallel_do_body_req "parallel_do Body". **/ See also requirements on \ref parallel_do_body_req "parallel_do Body". **/
//@{ //@{
//! Parallel iteration over a range, with optional addition of more work. //! Parallel iteration over a range, with optional addition of more work.
/** @ingroup algorithms */ /** @ingroup algorithms */
template<typename Iterator, typename Body> template<typename Iterator, typename Body>
void parallel_do( Iterator first, Iterator last, const Body& body ) void parallel_do( Iterator first, Iterator last, const Body& body )
{ {
if ( first == last ) if ( first == last )
return; return;
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
task_group_context context; task_group_context context;
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
internal::select_parallel_do( first, last, body, &Body::operator() internal::select_parallel_do( first, last, body, &Body::operator()
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, context , context
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
); );
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Parallel iteration over a range, with optional addition of more work an d user-supplied context //! Parallel iteration over a range, with optional addition of more work an d user-supplied context
/** @ingroup algorithms */ /** @ingroup algorithms */
template<typename Iterator, typename Body> template<typename Iterator, typename Body>
void parallel_do( Iterator first, Iterator last, const Body& body, task_gro up_context& context ) void parallel_do( Iterator first, Iterator last, const Body& body, task_gro up_context& context )
{ {
if ( first == last ) if ( first == last )
return; return;
internal::select_parallel_do( first, last, body, &Body::operator(), con text ); internal::select_parallel_do( first, last, body, &Body::operator(), con text );
} }
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
//@} //@}
} // namespace } // namespace
#endif /* __TBB_parallel_do_H */ #endif /* __TBB_parallel_do_H */
 End of changes. 18 change blocks. 
18 lines changed or deleted 18 lines changed or added


 parallel_for.h   parallel_for.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 36 skipping to change at line 36
the GNU General Public License. the GNU General Public License.
*/ */
#ifndef __TBB_parallel_for_H #ifndef __TBB_parallel_for_H
#define __TBB_parallel_for_H #define __TBB_parallel_for_H
#include "task.h" #include "task.h"
#include "partitioner.h" #include "partitioner.h"
#include "blocked_range.h" #include "blocked_range.h"
#include <new> #include <new>
#include <stdexcept> // std::invalid_argument #include "tbb_exception.h"
#include <string> // std::invalid_argument text
namespace tbb { namespace tbb {
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
//! Task type used in parallel_for //! Task type used in parallel_for
/** @ingroup algorithms */ /** @ingroup algorithms */
template<typename Range, typename Body, typename Partitioner> template<typename Range, typename Body, typename Partitioner>
class start_for: public task { class start_for: public task {
skipping to change at line 62 skipping to change at line 61
//! Constructor for root task. //! Constructor for root task.
start_for( const Range& range, const Body& body, Partitioner& parti tioner ) : start_for( const Range& range, const Body& body, Partitioner& parti tioner ) :
my_range(range), my_range(range),
my_body(body), my_body(body),
my_partition(partitioner) my_partition(partitioner)
{ {
} }
//! Splitting constructor used to generate children. //! Splitting constructor used to generate children.
/** this becomes left child. Newly constructed object is right chi ld. */ /** this becomes left child. Newly constructed object is right chi ld. */
start_for( start_for& parent, split ) : start_for( start_for& parent_, split ) :
my_range(parent.my_range,split()), my_range(parent_.my_range,split()),
my_body(parent.my_body), my_body(parent_.my_body),
my_partition(parent.my_partition,split()) my_partition(parent_.my_partition,split())
{ {
my_partition.set_affinity(*this); my_partition.set_affinity(*this);
} }
//! Update affinity info, if any. //! Update affinity info, if any.
/*override*/ void note_affinity( affinity_id id ) { /*override*/ void note_affinity( affinity_id id ) {
my_partition.note_affinity( id ); my_partition.note_affinity( id );
} }
public: public:
static void run( const Range& range, const Body& body, const Parti tioner& partitioner ) { static void run( const Range& range, const Body& body, const Parti tioner& partitioner ) {
if( !range.empty() ) { if( !range.empty() ) {
#if !__TBB_EXCEPTIONS || TBB_JOIN_OUTER_TASK_GROUP #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
start_for& a = *new(task::allocate_root()) start_for(range, body,const_cast<Partitioner&>(partitioner)); start_for& a = *new(task::allocate_root()) start_for(range, body,const_cast<Partitioner&>(partitioner));
#else #else
// Bound context prevents exceptions from body to affect ne sting or sibling algorithms, // Bound context prevents exceptions from body to affect ne sting or sibling algorithms,
// and allows users to handle exceptions safely by wrapping parallel_for in the try-block. // and allows users to handle exceptions safely by wrapping parallel_for in the try-block.
task_group_context context; task_group_context context;
start_for& a = *new(task::allocate_root(context)) start_for (range,body,const_cast<Partitioner&>(partitioner)); start_for& a = *new(task::allocate_root(context)) start_for (range,body,const_cast<Partitioner&>(partitioner));
#endif /* __TBB_EXCEPTIONS && !TBB_JOIN_OUTER_TASK_GROUP */ #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */
task::spawn_root_and_wait(a); task::spawn_root_and_wait(a);
} }
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
static void run( const Range& range, const Body& body, const Parti tioner& partitioner, task_group_context& context ) { static void run( const Range& range, const Body& body, const Parti tioner& partitioner, task_group_context& context ) {
if( !range.empty() ) { if( !range.empty() ) {
start_for& a = *new(task::allocate_root(context)) start_for (range,body,const_cast<Partitioner&>(partitioner)); start_for& a = *new(task::allocate_root(context)) start_for (range,body,const_cast<Partitioner&>(partitioner));
task::spawn_root_and_wait(a); task::spawn_root_and_wait(a);
} }
} }
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
}; };
template<typename Range, typename Body, typename Partitioner> template<typename Range, typename Body, typename Partitioner>
task* start_for<Range,Body,Partitioner>::execute() { task* start_for<Range,Body,Partitioner>::execute() {
if( !my_range.is_divisible() || my_partition.should_execute_range(* this) ) { if( !my_range.is_divisible() || my_partition.should_execute_range(* this) ) {
my_body( my_range ); my_body( my_range );
return my_partition.continue_after_execute_range(*this); return my_partition.continue_after_execute_range();
} else { } else {
empty_task& c = *new( this->allocate_continuation() ) empty_tas k; empty_task& c = *new( this->allocate_continuation() ) empty_tas k;
recycle_as_child_of(c); recycle_as_child_of(c);
c.set_ref_count(2); c.set_ref_count(2);
bool delay = my_partition.decide_whether_to_delay(); bool delay = my_partition.decide_whether_to_delay();
start_for& b = *new( c.allocate_child() ) start_for(*this,split ()); start_for& b = *new( c.allocate_child() ) start_for(*this,split ());
my_partition.spawn_or_delay(delay,*this,b); my_partition.spawn_or_delay(delay,b);
return this; return this;
} }
} }
} // 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_for_body_req Requirements on parallel_for body /** \page parallel_for_body_req Requirements on parallel_for body
Class \c Body implementing the concept of parallel_for body must define : Class \c Body implementing the concept of parallel_for body must define :
skipping to change at line 156 skipping to change at line 155
internal::start_for<Range,Body,auto_partitioner>::run(range,body,partit ioner); internal::start_for<Range,Body,auto_partitioner>::run(range,body,partit ioner);
} }
//! Parallel iteration over range with affinity_partitioner. //! Parallel iteration over range with affinity_partitioner.
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_for( const Range& range, const Body& body, affinity_partition er& partitioner ) { void parallel_for( const Range& range, const Body& body, affinity_partition er& partitioner ) {
internal::start_for<Range,Body,affinity_partitioner>::run(range,body,pa rtitioner); internal::start_for<Range,Body,affinity_partitioner>::run(range,body,pa rtitioner);
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Parallel iteration over range with simple partitioner and user-supplied context. //! Parallel iteration over range with simple partitioner and user-supplied context.
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_for( const Range& range, const Body& body, const simple_parti tioner& partitioner, task_group_context& context ) { void parallel_for( const Range& range, const Body& body, const simple_parti tioner& partitioner, task_group_context& context ) {
internal::start_for<Range,Body,simple_partitioner>::run(range, body, pa rtitioner, context); internal::start_for<Range,Body,simple_partitioner>::run(range, body, pa rtitioner, context);
} }
//! Parallel iteration over range with auto_partitioner and user-supplied c ontext. //! Parallel iteration over range with auto_partitioner and user-supplied c ontext.
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_for( const Range& range, const Body& body, const auto_partiti oner& partitioner, task_group_context& context ) { void parallel_for( const Range& range, const Body& body, const auto_partiti oner& partitioner, task_group_context& context ) {
internal::start_for<Range,Body,auto_partitioner>::run(range, body, part itioner, context); internal::start_for<Range,Body,auto_partitioner>::run(range, body, part itioner, context);
} }
//! Parallel iteration over range with affinity_partitioner and user-suppli ed context. //! Parallel iteration over range with affinity_partitioner and user-suppli ed context.
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_for( const Range& range, const Body& body, affinity_partition er& partitioner, task_group_context& context ) { void parallel_for( const Range& range, const Body& body, affinity_partition er& partitioner, task_group_context& context ) {
internal::start_for<Range,Body,affinity_partitioner>::run(range,body,pa rtitioner, context); internal::start_for<Range,Body,affinity_partitioner>::run(range,body,pa rtitioner, context);
} }
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
//@} //@}
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
//! Calls the function with values from range [begin, end) with a step provided //! Calls the function with values from range [begin, end) with a step provided
template<typename Function, typename Index> template<typename Function, typename Index>
class parallel_for_body : internal::no_assign { class parallel_for_body : internal::no_assign {
Function &my_func; const Function &my_func;
const Index my_begin; const Index my_begin;
const Index my_step; const Index my_step;
public: public:
parallel_for_body( Function& _func, Index& _begin, Index& _step) parallel_for_body( const Function& _func, Index& _begin, Index& _step)
: my_func(_func), my_begin(_begin), my_step(_step) {} : my_func(_func), my_begin(_begin), my_step(_step) {}
void operator()( tbb::blocked_range<Index>& r ) const { void operator()( tbb::blocked_range<Index>& r ) const {
for( Index i = r.begin(), k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step) for( Index i = r.begin(), k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step)
my_func( k ); my_func( k );
} }
}; };
} // namespace internal } // namespace internal
//! @endcond //! @endcond
namespace strict_ppl { namespace strict_ppl {
//@{ //@{
//! Parallel iteration over a range of integers with a step provided //! Parallel iteration over a range of integers with a step provided
template <typename Index, typename Function> template <typename Index, typename Function>
Function parallel_for(Index first, Index last, Index step, Function f) { void parallel_for(Index first, Index last, Index step, const Function& f) {
tbb::task_group_context context; tbb::task_group_context context;
return parallel_for(first, last, step, f, context); parallel_for(first, last, step, f, context);
} }
template <typename Index, typename Function> template <typename Index, typename Function>
Function parallel_for(Index first, Index last, Index step, Function f, tbb: void parallel_for(Index first, Index last, Index step, const Function& f, t
:task_group_context &context) { bb::task_group_context &context) {
if (step <= 0 ) throw std::invalid_argument("step should be positive"); if (step <= 0 )
internal::throw_exception(internal::eid_nonpositive_step); // throw
if (last > first) { s std::invalid_argument
else if (last > first) {
// Above "else" is necessary to prevent "potential divide by zero"
warning
Index end = (last - first) / step; Index end = (last - first) / step;
if (first + end * step < last) end++; if (first + end * step < last) end++;
tbb::blocked_range<Index> range(static_cast<Index>(0), end); tbb::blocked_range<Index> range(static_cast<Index>(0), end);
internal::parallel_for_body<Function, Index> body(f, first, step); internal::parallel_for_body<Function, Index> body(f, first, step);
tbb::parallel_for(range, body, tbb::auto_partitioner(), context); tbb::parallel_for(range, body, tbb::auto_partitioner(), context);
} }
return f;
} }
//! Parallel iteration over a range of integers with a default step value
template <typename Index, typename Function>
void parallel_for(Index first, Index last, const Function& f) {
tbb::task_group_context context;
parallel_for(first, last, static_cast<Index>(1), f, context);
}
template <typename Index, typename Function>
void parallel_for(Index first, Index last, const Function& f, tbb::task_gro
up_context &context) {
parallel_for(first, last, static_cast<Index>(1), f, context);
}
//@} //@}
} // namespace strict_ppl } // namespace strict_ppl
using strict_ppl::parallel_for; using strict_ppl::parallel_for;
} // namespace tbb } // namespace tbb
#endif /* __TBB_parallel_for_H */ #endif /* __TBB_parallel_for_H */
 End of changes. 18 change blocks. 
25 lines changed or deleted 38 lines changed or added


 parallel_for_each.h   parallel_for_each.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 41 skipping to change at line 41
#include "parallel_do.h" #include "parallel_do.h"
namespace tbb { namespace tbb {
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
// The class calls user function in operator() // The class calls user function in operator()
template <typename Function, typename Iterator> template <typename Function, typename Iterator>
class parallel_for_each_body : internal::no_assign { class parallel_for_each_body : internal::no_assign {
Function &my_func; const Function &my_func;
public: public:
parallel_for_each_body(Function &_func) : my_func(_func) {} parallel_for_each_body(const Function &_func) : my_func(_func) {}
parallel_for_each_body(const parallel_for_each_body<Function, Itera tor> &_caller) : my_func(_caller.my_func) {} parallel_for_each_body(const parallel_for_each_body<Function, Itera tor> &_caller) : my_func(_caller.my_func) {}
void operator() ( typename std::iterator_traits<Iterator>::value_ty pe value ) const { void operator() ( typename std::iterator_traits<Iterator>::value_ty pe& value ) const {
my_func(value); my_func(value);
} }
}; };
} // namespace internal } // namespace internal
//! @endcond //! @endcond
/** \name parallel_for_each /** \name parallel_for_each
**/ **/
//@{ //@{
//! Calls function f for all items from [first, last) interval using user-s upplied context //! Calls function f for all items from [first, last) interval using user-s upplied context
/** @ingroup algorithms */ /** @ingroup algorithms */
template<typename InputIterator, typename Function> template<typename InputIterator, typename Function>
Function parallel_for_each(InputIterator first, InputIterator last, Functio n f, task_group_context &context) { void parallel_for_each(InputIterator first, InputIterator last, const Funct ion& f, task_group_context &context) {
internal::parallel_for_each_body<Function, InputIterator> body(f); internal::parallel_for_each_body<Function, InputIterator> body(f);
tbb::parallel_do (first, last, body, context); tbb::parallel_do (first, last, body, context);
return f;
} }
//! Uses default context //! Uses default context
template<typename InputIterator, typename Function> template<typename InputIterator, typename Function>
Function parallel_for_each(InputIterator first, InputIterator last, Functio n f) { void parallel_for_each(InputIterator first, InputIterator last, const Funct ion& f) {
internal::parallel_for_each_body<Function, InputIterator> body(f); internal::parallel_for_each_body<Function, InputIterator> body(f);
tbb::parallel_do (first, last, body); tbb::parallel_do (first, last, body);
return f;
} }
//@} //@}
} // namespace } // namespace
#endif /* __TBB_parallel_for_each_H */ #endif /* __TBB_parallel_for_each_H */
 End of changes. 8 change blocks. 
8 lines changed or deleted 6 lines changed or added


 parallel_invoke.h   parallel_invoke.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 42 skipping to change at line 42
#include "task.h" #include "task.h"
namespace tbb { namespace tbb {
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
// Simple task object, executing user method // Simple task object, executing user method
template<typename function> template<typename function>
class function_invoker : public task{ class function_invoker : public task{
public: public:
function_invoker(function& _function) : my_function(_function) {} function_invoker(const function& _function) : my_function(_function ) {}
private: private:
function &my_function; const function &my_function;
/*override*/ /*override*/
task* execute() task* execute()
{ {
my_function(); my_function();
return NULL; return NULL;
} }
}; };
// The class spawns two or three child tasks // The class spawns two or three child tasks
template <size_t N, typename function1, typename function2, typename fu nction3> template <size_t N, typename function1, typename function2, typename fu nction3>
class spawner : public task { class spawner : public task {
private: private:
function1& my_func1; const function1& my_func1;
function2& my_func2; const function2& my_func2;
function3& my_func3; const function3& my_func3;
bool is_recycled; bool is_recycled;
task* execute (){ task* execute (){
if(is_recycled){ if(is_recycled){
return NULL; return NULL;
}else{ }else{
__TBB_ASSERT(N==2 || N==3, "Number of arguments passed to s pawner is wrong"); __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to s pawner is wrong");
set_ref_count(N); set_ref_count(N);
recycle_as_safe_continuation(); recycle_as_safe_continuation();
internal::function_invoker<function2>* invoker2 = new (allo cate_child()) internal::function_invoker<function2>(my_func2); internal::function_invoker<function2>* invoker2 = new (allo cate_child()) internal::function_invoker<function2>(my_func2);
skipping to change at line 85 skipping to change at line 85
__TBB_ASSERT(invoker3, "Child task allocation failed"); __TBB_ASSERT(invoker3, "Child task allocation failed");
spawn(*invoker3); spawn(*invoker3);
} }
my_func1(); my_func1();
is_recycled = true; is_recycled = true;
return NULL; return NULL;
} }
} // execute } // execute
public: public:
spawner(function1& _func1, function2& _func2, function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {} spawner(const function1& _func1, const function2& _func2, const fun ction3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_ recycled(false) {}
}; };
// Creates and spawns child tasks // Creates and spawns child tasks
class parallel_invoke_helper : public empty_task { class parallel_invoke_helper : public empty_task {
public: public:
// Dummy functor class // Dummy functor class
class parallel_invoke_noop { class parallel_invoke_noop {
public: public:
void operator() () const {} void operator() () const {}
}; };
// Creates a helper object with user-defined number of children exp ected // Creates a helper object with user-defined number of children exp ected
parallel_invoke_helper(int number_of_children) parallel_invoke_helper(int number_of_children)
{ {
set_ref_count(number_of_children + 1); set_ref_count(number_of_children + 1);
} }
// Adds child task and spawns it // Adds child task and spawns it
template <typename function> template <typename function>
void add_child (function &_func) void add_child (const function &_func)
{ {
internal::function_invoker<function>* invoker = new (allocate_c hild()) internal::function_invoker<function>(_func); internal::function_invoker<function>* invoker = new (allocate_c hild()) internal::function_invoker<function>(_func);
__TBB_ASSERT(invoker, "Child task allocation failed"); __TBB_ASSERT(invoker, "Child task allocation failed");
spawn(*invoker); spawn(*invoker);
} }
// Adds a task with multiple child tasks and spawns it // Adds a task with multiple child tasks and spawns it
// two arguments // two arguments
template <typename function1, typename function2> template <typename function1, typename function2>
void add_children (function1& _func1, function2& _func2) void add_children (const function1& _func1, const function2& _func2 )
{ {
// The third argument is dummy, it is ignored actually. // The third argument is dummy, it is ignored actually.
parallel_invoke_noop noop; parallel_invoke_noop noop;
internal::spawner<2, function1, function2, parallel_invoke_noop >& sub_root = *new(allocate_child())internal::spawner<2, function1, functio n2, parallel_invoke_noop>(_func1, _func2, noop); internal::spawner<2, function1, function2, parallel_invoke_noop >& sub_root = *new(allocate_child())internal::spawner<2, function1, functio n2, parallel_invoke_noop>(_func1, _func2, noop);
spawn(sub_root); spawn(sub_root);
} }
// three arguments // three arguments
template <typename function1, typename function2, typename function 3> template <typename function1, typename function2, typename function 3>
void add_children (function1& _func1, function2& _func2, function3& _func3) void add_children (const function1& _func1, const function2& _func2 , const function3& _func3)
{ {
internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, functio n3>(_func1, _func2, _func3); internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, functio n3>(_func1, _func2, _func3);
spawn(sub_root); spawn(sub_root);
} }
// Waits for all child tasks // Waits for all child tasks
template <typename F0> template <typename F0>
void run_and_finish(F0& f0) void run_and_finish(const F0& f0)
{ {
internal::function_invoker<F0>* invoker = new (allocate_child() ) internal::function_invoker<F0>(f0); internal::function_invoker<F0>* invoker = new (allocate_child() ) internal::function_invoker<F0>(f0);
__TBB_ASSERT(invoker, "Child task allocation failed"); __TBB_ASSERT(invoker, "Child task allocation failed");
spawn_and_wait_for_all(*invoker); spawn_and_wait_for_all(*invoker);
} }
}; };
// The class destroys root if exception occured as well as in normal ca se // The class destroys root if exception occured as well as in normal ca se
class parallel_invoke_cleaner: internal::no_copy { class parallel_invoke_cleaner: internal::no_copy {
public: public:
parallel_invoke_cleaner(int number_of_children, tbb::task_group_con text& context) : root(*new(task::allocate_root(context)) internal::parallel _invoke_helper(number_of_children)) parallel_invoke_cleaner(int number_of_children, tbb::task_group_con text& context) : root(*new(task::allocate_root(context)) internal::parallel _invoke_helper(number_of_children))
skipping to change at line 159 skipping to change at line 159
/** \name parallel_invoke /** \name parallel_invoke
**/ **/
//@{ //@{
//! Executes a list of tasks in parallel and waits for all tasks to complet e. //! Executes a list of tasks in parallel and waits for all tasks to complet e.
/** @ingroup algorithms */ /** @ingroup algorithms */
// parallel_invoke with user-defined context // parallel_invoke with user-defined context
// two arguments // two arguments
template<typename F0, typename F1 > template<typename F0, typename F1 >
void parallel_invoke(F0 f0, F1 f1, tbb::task_group_context& context) { void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& c ontext) {
internal::parallel_invoke_cleaner cleaner(2, context); internal::parallel_invoke_cleaner cleaner(2, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_child(f1); root.add_child(f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// three arguments // three arguments
template<typename F0, typename F1, typename F2 > template<typename F0, typename F1, typename F2 >
void parallel_invoke(F0 f0, F1 f1, F2 f2, tbb::task_group_context& context) { void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_gr oup_context& context) {
internal::parallel_invoke_cleaner cleaner(3, context); internal::parallel_invoke_cleaner cleaner(3, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_child(f2); root.add_child(f2);
root.add_child(f1); root.add_child(f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// four arguments // four arguments
template<typename F0, typename F1, typename F2, typename F3> template<typename F0, typename F1, typename F2, typename F3>
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, tbb::task_group_context& c void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
ontext) { ,
tbb::task_group_context& context)
{
internal::parallel_invoke_cleaner cleaner(4, context); internal::parallel_invoke_cleaner cleaner(4, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_child(f3); root.add_child(f3);
root.add_child(f2); root.add_child(f2);
root.add_child(f1); root.add_child(f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// five arguments // five arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4 > template<typename F0, typename F1, typename F2, typename F3, typename F4 >
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, tbb::task_group_con void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
text& context) { , const F4& f4,
tbb::task_group_context& context)
{
internal::parallel_invoke_cleaner cleaner(3, context); internal::parallel_invoke_cleaner cleaner(3, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_children(f4, f3); root.add_children(f4, f3);
root.add_children(f2, f1); root.add_children(f2, f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// six arguments // six arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t template<typename F0, typename F1, typename F2, typename F3, typename F4, t
ypename F5 > ypename F5>
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, tbb::task_gr void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
oup_context& context) { , const F4& f4, const F5& f5,
tbb::task_group_context& context)
{
internal::parallel_invoke_cleaner cleaner(3, context); internal::parallel_invoke_cleaner cleaner(3, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_children(f5, f4, f3); root.add_children(f5, f4, f3);
root.add_children(f2, f1); root.add_children(f2, f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// seven arguments // seven arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t template<typename F0, typename F1, typename F2, typename F3, typename F4, t
ypename F5, typename F6 > ypename F5, typename F6>
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, tbb:: void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
task_group_context& context) { , const F4& f4,
const F5& f5, const F6& f6,
tbb::task_group_context& context)
{
internal::parallel_invoke_cleaner cleaner(3, context); internal::parallel_invoke_cleaner cleaner(3, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_children(f6, f5, f4); root.add_children(f6, f5, f4);
root.add_children(f3, f2, f1); root.add_children(f3, f2, f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// eight arguments // eight arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t template<typename F0, typename F1, typename F2, typename F3, typename F4,
ypename F5, typename F6, typename F5, typename F6, typename F7>
typename F7> void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7 , const F4& f4,
, tbb::task_group_context& context) { const F5& f5, const F6& f6, const F7& f7,
tbb::task_group_context& context)
{
internal::parallel_invoke_cleaner cleaner(4, context); internal::parallel_invoke_cleaner cleaner(4, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_children(f7, f6, f5); root.add_children(f7, f6, f5);
root.add_children(f4, f3); root.add_children(f4, f3);
root.add_children(f2, f1); root.add_children(f2, f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// nine arguments // nine arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t template<typename F0, typename F1, typename F2, typename F3, typename F4,
ypename F5, typename F6, typename F5, typename F6, typename F7, typename F8>
typename F7, typename F8> void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7 , const F4& f4,
, F8 f8, tbb::task_group_context& context) { const F5& f5, const F6& f6, const F7& f7, const F8& f8
,
tbb::task_group_context& context)
{
internal::parallel_invoke_cleaner cleaner(4, context); internal::parallel_invoke_cleaner cleaner(4, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_children(f8, f7, f6); root.add_children(f8, f7, f6);
root.add_children(f5, f4, f3); root.add_children(f5, f4, f3);
root.add_children(f2, f1); root.add_children(f2, f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// ten arguments // ten arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t template<typename F0, typename F1, typename F2, typename F3, typename F4,
ypename F5, typename F6, typename F5, typename F6, typename F7, typename F8, typename F9>
typename F7, typename F8, typename F9> void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7 , const F4& f4,
, F8 f8, F9 f9, tbb::task_group_context& context) { const F5& f5, const F6& f6, const F7& f7, const F8& f8
, const F9& f9,
tbb::task_group_context& context)
{
internal::parallel_invoke_cleaner cleaner(4, context); internal::parallel_invoke_cleaner cleaner(4, context);
internal::parallel_invoke_helper& root = cleaner.root; internal::parallel_invoke_helper& root = cleaner.root;
root.add_children(f9, f8, f7); root.add_children(f9, f8, f7);
root.add_children(f6, f5, f4); root.add_children(f6, f5, f4);
root.add_children(f3, f2, f1); root.add_children(f3, f2, f1);
root.run_and_finish(f0); root.run_and_finish(f0);
} }
// two arguments // two arguments
template<typename F0, typename F1> template<typename F0, typename F1>
void parallel_invoke(F0 f0, F1 f1) { void parallel_invoke(const F0& f0, const F1& f1) {
task_group_context context; task_group_context context;
parallel_invoke<F0, F1>(f0, f1, context); parallel_invoke<F0, F1>(f0, f1, context);
} }
// three arguments // three arguments
template<typename F0, typename F1, typename F2> template<typename F0, typename F1, typename F2>
void parallel_invoke(F0 f0, F1 f1, F2 f2) { void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
task_group_context context; task_group_context context;
parallel_invoke<F0, F1, F2>(f0, f1, f2, context); parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
} }
// four arguments // four arguments
template<typename F0, typename F1, typename F2, typename F3 > template<typename F0, typename F1, typename F2, typename F3 >
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3) { void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3 ) {
task_group_context context; task_group_context context;
parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context); parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
} }
// five arguments // five arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4> template<typename F0, typename F1, typename F2, typename F3, typename F4>
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4) { void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3 , const F4& f4) {
task_group_context context; task_group_context context;
parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context); parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
} }
// six arguments // six arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t ypename F5> template<typename F0, typename F1, typename F2, typename F3, typename F4, t ypename F5>
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5) { void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3 , const F4& f4, const F5& f5) {
task_group_context context; task_group_context context;
parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context ); parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context );
} }
// seven arguments // seven arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t ypename F5, typename F6> template<typename F0, typename F1, typename F2, typename F3, typename F4, t ypename F5, typename F6>
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6) { void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
, const F4& f4,
const F5& f5, const F6& f6)
{
task_group_context context; task_group_context context;
parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context); parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
} }
// eigth arguments // eigth arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t template<typename F0, typename F1, typename F2, typename F3, typename F4,
ypename F5, typename F6, typename F5, typename F6, typename F7>
typename F7> void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7 , const F4& f4,
) { const F5& f5, const F6& f6, const F7& f7)
{
task_group_context context; task_group_context context;
parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context); parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
} }
// nine arguments // nine arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t template<typename F0, typename F1, typename F2, typename F3, typename F4,
ypename F5, typename F6, typename F5, typename F6, typename F7, typename F8>
typename F7, typename F8> void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7 , const F4& f4,
, F8 f8) { const F5& f5, const F6& f6, const F7& f7, const F8& f8
)
{
task_group_context context; task_group_context context;
parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context); parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
} }
// ten arguments // ten arguments
template<typename F0, typename F1, typename F2, typename F3, typename F4, t template<typename F0, typename F1, typename F2, typename F3, typename F4,
ypename F5, typename F6, typename F5, typename F6, typename F7, typename F8, typename F9>
typename F7, typename F8, typename F9> void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3
void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7 , const F4& f4,
, F8 f8, F9 f9) { const F5& f5, const F6& f6, const F7& f7, const F8& f8
, const F9& f9)
{
task_group_context context; task_group_context context;
parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context); parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
} }
//@} //@}
} // namespace } // namespace
#endif /* __TBB_parallel_invoke_H */ #endif /* __TBB_parallel_invoke_H */
 End of changes. 27 change blocks. 
61 lines changed or deleted 86 lines changed or added


 parallel_reduce.h   parallel_reduce.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 68 skipping to change at line 68
return static_cast<T*>(itt_load_pointer_with_acquire_v3(&src)); return static_cast<T*>(itt_load_pointer_with_acquire_v3(&src));
#else #else
return __TBB_load_with_acquire(src); return __TBB_load_with_acquire(src);
#endif /* TBB_USE_THREADING_TOOLS */ #endif /* TBB_USE_THREADING_TOOLS */
} }
//! 0 if root, 1 if a left child, 2 if a right child. //! 0 if root, 1 if a left child, 2 if a right child.
/** Represented as a char, not enum, for compactness. */ /** Represented as a char, not enum, for compactness. */
typedef char reduction_context; typedef char reduction_context;
//! Task type use to combine the partial results of parallel_reduce wit h affinity_partitioner. //! Task type use to combine the partial results of parallel_reduce.
/** @ingroup algorithms */ /** @ingroup algorithms */
template<typename Body> template<typename Body>
class finish_reduce: public task { class finish_reduce: public task {
//! Pointer to body, or NULL if the left child has not yet finished . //! Pointer to body, or NULL if the left child has not yet finished .
Body* my_body; Body* my_body;
bool has_right_zombie; bool has_right_zombie;
const reduction_context my_context; const reduction_context my_context;
aligned_space<Body,1> zombie_space; aligned_space<Body,1> zombie_space;
finish_reduce( char context ) : finish_reduce( char context_ ) :
my_body(NULL), my_body(NULL),
has_right_zombie(false), has_right_zombie(false),
my_context(context) my_context(context_)
{ {
} }
task* execute() { task* execute() {
if( has_right_zombie ) { if( has_right_zombie ) {
// Right child was stolen. // Right child was stolen.
Body* s = zombie_space.begin(); Body* s = zombie_space.begin();
my_body->join( *s ); my_body->join( *s );
s->~Body(); s->~Body();
} }
if( my_context==1 ) if( my_context==1 )
parallel_reduce_store_body( static_cast<finish_reduce*>(par ent())->my_body, my_body ); parallel_reduce_store_body( static_cast<finish_reduce*>(par ent())->my_body, my_body );
return NULL; return NULL;
} }
template<typename Range,typename Body_, typename Partitioner> template<typename Range,typename Body_, typename Partitioner>
friend class start_reduce; friend class start_reduce;
}; };
//! Task type used to split the work of parallel_reduce with affinity_p artitioner. //! Task type used to split the work of parallel_reduce.
/** @ingroup algorithms */ /** @ingroup algorithms */
template<typename Range, typename Body, typename Partitioner> template<typename Range, typename Body, typename Partitioner>
class start_reduce: public task { class start_reduce: public task {
typedef finish_reduce<Body> finish_type; typedef finish_reduce<Body> finish_type;
Body* my_body; Body* my_body;
Range my_range; Range my_range;
typename Partitioner::partition_type my_partition; typename Partitioner::partition_type my_partition;
reduction_context my_context; reduction_context my_context;
/*override*/ task* execute(); /*override*/ task* execute();
template<typename Body_> template<typename Body_>
skipping to change at line 121 skipping to change at line 121
//! Constructor used for root task //! Constructor used for root task
start_reduce( const Range& range, Body* body, Partitioner& partitio ner ) : start_reduce( const Range& range, Body* body, Partitioner& partitio ner ) :
my_body(body), my_body(body),
my_range(range), my_range(range),
my_partition(partitioner), my_partition(partitioner),
my_context(0) my_context(0)
{ {
} }
//! Splitting constructor used to generate children. //! Splitting constructor used to generate children.
/** this becomes left child. Newly constructed object is right chi ld. */ /** this becomes left child. Newly constructed object is right chi ld. */
start_reduce( start_reduce& parent, split ) : start_reduce( start_reduce& parent_, split ) :
my_body(parent.my_body), my_body(parent_.my_body),
my_range(parent.my_range,split()), my_range(parent_.my_range,split()),
my_partition(parent.my_partition,split()), my_partition(parent_.my_partition,split()),
my_context(2) my_context(2)
{ {
my_partition.set_affinity(*this); my_partition.set_affinity(*this);
parent.my_context = 1; parent_.my_context = 1;
} }
//! Update affinity info, if any //! Update affinity info, if any
/*override*/ void note_affinity( affinity_id id ) { /*override*/ void note_affinity( affinity_id id ) {
my_partition.note_affinity( id ); my_partition.note_affinity( id );
} }
public: public:
static void run( const Range& range, Body& body, Partitioner& parti tioner ) { static void run( const Range& range, Body& body, Partitioner& parti tioner ) {
if( !range.empty() ) { if( !range.empty() ) {
#if !__TBB_EXCEPTIONS || TBB_JOIN_OUTER_TASK_GROUP #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
task::spawn_root_and_wait( *new(task::allocate_root()) star t_reduce(range,&body,partitioner) ); task::spawn_root_and_wait( *new(task::allocate_root()) star t_reduce(range,&body,partitioner) );
#else #else
// Bound context prevents exceptions from body to affect ne sting or sibling algorithms, // Bound context prevents exceptions from body to affect ne sting or sibling algorithms,
// and allows users to handle exceptions safely by wrapping parallel_for in the try-block. // and allows users to handle exceptions safely by wrapping parallel_for in the try-block.
task_group_context context; task_group_context context;
task::spawn_root_and_wait( *new(task::allocate_root(context )) start_reduce(range,&body,partitioner) ); task::spawn_root_and_wait( *new(task::allocate_root(context )) start_reduce(range,&body,partitioner) );
#endif /* __TBB_EXCEPTIONS && !TBB_JOIN_OUTER_TASK_GROUP */ #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */
} }
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
static void run( const Range& range, Body& body, Partitioner& parti tioner, task_group_context& context ) { static void run( const Range& range, Body& body, Partitioner& parti tioner, task_group_context& context ) {
if( !range.empty() ) if( !range.empty() )
task::spawn_root_and_wait( *new(task::allocate_root(context )) start_reduce(range,&body,partitioner) ); task::spawn_root_and_wait( *new(task::allocate_root(context )) start_reduce(range,&body,partitioner) );
} }
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
}; };
template<typename Range, typename Body, typename Partitioner> template<typename Range, typename Body, typename Partitioner>
task* start_reduce<Range,Body,Partitioner>::execute() { task* start_reduce<Range,Body,Partitioner>::execute() {
if( my_context==2 ) { if( my_context==2 ) {
finish_type* p = static_cast<finish_type*>(parent() ); finish_type* p = static_cast<finish_type*>(parent() );
if( !parallel_reduce_load_body(p->my_body) ) { if( !parallel_reduce_load_body(p->my_body) ) {
my_body = new( p->zombie_space.begin() ) Body(*my_body,spli t()); my_body = new( p->zombie_space.begin() ) Body(*my_body,spli t());
p->has_right_zombie = true; p->has_right_zombie = true;
} }
} }
if( !my_range.is_divisible() || my_partition.should_execute_range(* this) ) { if( !my_range.is_divisible() || my_partition.should_execute_range(* this) ) {
(*my_body)( my_range ); (*my_body)( my_range );
if( my_context==1 ) if( my_context==1 )
parallel_reduce_store_body(static_cast<finish_type*>(parent ())->my_body, my_body ); parallel_reduce_store_body(static_cast<finish_type*>(parent ())->my_body, my_body );
return my_partition.continue_after_execute_range(*this); return my_partition.continue_after_execute_range();
} else { } else {
finish_type& c = *new( allocate_continuation()) finish_type(my_ context); finish_type& c = *new( allocate_continuation()) finish_type(my_ context);
recycle_as_child_of(c); recycle_as_child_of(c);
c.set_ref_count(2); c.set_ref_count(2);
bool delay = my_partition.decide_whether_to_delay(); bool delay = my_partition.decide_whether_to_delay();
start_reduce& b = *new( c.allocate_child() ) start_reduce(*this ,split()); start_reduce& b = *new( c.allocate_child() ) start_reduce(*this ,split());
my_partition.spawn_or_delay(delay,*this,b); my_partition.spawn_or_delay(delay,b);
return this; return this;
} }
} }
//! Auxiliary class for parallel_reduce; for internal use only. //! Auxiliary class for parallel_reduce; for internal use only.
/** The adaptor class that implements \ref parallel_reduce_body_req "pa rallel_reduce Body" /** The adaptor class that implements \ref parallel_reduce_body_req "pa rallel_reduce Body"
using given \ref parallel_reduce_lambda_req "anonymous function obj ects". using given \ref parallel_reduce_lambda_req "anonymous function obj ects".
**/ **/
/** @ingroup algorithms */ /** @ingroup algorithms */
template<typename Range, typename Value, typename RealBody, typename Re duction> template<typename Range, typename Value, typename RealBody, typename Re duction>
skipping to change at line 279 skipping to change at line 279
internal::start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner ); internal::start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner );
} }
//! Parallel iteration with reduction and affinity_partitioner //! Parallel iteration with reduction and affinity_partitioner
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner ) { void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner ) {
internal::start_reduce<Range,Body,affinity_partitioner>::run( range, bo dy, partitioner ); internal::start_reduce<Range,Body,affinity_partitioner>::run( range, bo dy, partitioner );
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Parallel iteration with reduction, simple partitioner and user-supplied context. //! Parallel iteration with reduction, simple partitioner and user-supplied context.
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_reduce( const Range& range, Body& body, const simple_partitio ner& partitioner, task_group_context& context ) { void parallel_reduce( const Range& range, Body& body, const simple_partitio ner& partitioner, task_group_context& context ) {
internal::start_reduce<Range,Body,const simple_partitioner>::run( range , body, partitioner, context ); internal::start_reduce<Range,Body,const simple_partitioner>::run( range , body, partitioner, context );
} }
//! Parallel iteration with reduction, auto_partitioner and user-supplied c ontext //! Parallel iteration with reduction, auto_partitioner and user-supplied c ontext
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_reduce( const Range& range, Body& body, const auto_partitione r& partitioner, task_group_context& context ) { void parallel_reduce( const Range& range, Body& body, const auto_partitione r& partitioner, task_group_context& context ) {
internal::start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner, context ); internal::start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner, context );
} }
//! Parallel iteration with reduction, affinity_partitioner and user-suppli ed context //! Parallel iteration with reduction, affinity_partitioner and user-suppli ed context
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner, task_group_context& context ) { void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
internal::start_reduce<Range,Body,affinity_partitioner>::run( range, bo dy, partitioner, context ); internal::start_reduce<Range,Body,affinity_partitioner>::run( range, bo dy, partitioner, context );
} }
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
/** parallel_reduce overloads that work with anonymous function objects /** parallel_reduce overloads that work with anonymous function objects
(see also \ref parallel_reduce_lambda_req "requirements on parallel_red uce anonymous function objects"). **/ (see also \ref parallel_reduce_lambda_req "requirements on parallel_red uce anonymous function objects"). **/
//! Parallel iteration with reduction and default partitioner. //! Parallel iteration with reduction and default partitioner.
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduct ion> template<typename Range, typename Value, typename RealBody, typename Reduct ion>
Value parallel_reduce( const Range& range, const Value& identity, const Rea lBody& real_body, const Reduction& reduction ) { Value parallel_reduce( const Range& range, const Value& identity, const Rea lBody& real_body, const Reduction& reduction ) {
internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(ident ity, real_body, reduction); internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(ident ity, real_body, reduction);
internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,R ealBody,Reduction>,const __TBB_DEFAULT_PARTITIONER> internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,R ealBody,Reduction>,const __TBB_DEFAULT_PARTITIONER>
skipping to change at line 348 skipping to change at line 348
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduct ion> template<typename Range, typename Value, typename RealBody, typename Reduct ion>
Value parallel_reduce( const Range& range, const Value& identity, const Rea lBody& real_body, const Reduction& reduction, Value parallel_reduce( const Range& range, const Value& identity, const Rea lBody& real_body, const Reduction& reduction,
affinity_partitioner& partitioner ) { affinity_partitioner& partitioner ) {
internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(ident ity, real_body, reduction); internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(ident ity, real_body, reduction);
internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,R ealBody,Reduction>,affinity_partitioner> internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,R ealBody,Reduction>,affinity_partitioner>
::run( range, body, partitioner ); ::run( range, body, partitioner );
return body.result(); return body.result();
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Parallel iteration with reduction, simple partitioner and user-supplied context. //! Parallel iteration with reduction, simple partitioner and user-supplied context.
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduct ion> template<typename Range, typename Value, typename RealBody, typename Reduct ion>
Value parallel_reduce( const Range& range, const Value& identity, const Rea lBody& real_body, const Reduction& reduction, Value parallel_reduce( const Range& range, const Value& identity, const Rea lBody& real_body, const Reduction& reduction,
const simple_partitioner& partitioner, task_group_co ntext& context ) { const simple_partitioner& partitioner, task_group_co ntext& context ) {
internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(ident ity, real_body, reduction); internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(ident ity, real_body, reduction);
internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,R ealBody,Reduction>,const simple_partitioner> internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,R ealBody,Reduction>,const simple_partitioner>
::run( range, body, partitioner, context ); ::run( range, body, partitioner, context );
return body.result(); return body.result();
} }
skipping to change at line 381 skipping to change at line 381
//! Parallel iteration with reduction, affinity_partitioner and user-suppli ed context //! Parallel iteration with reduction, affinity_partitioner and user-suppli ed context
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduct ion> template<typename Range, typename Value, typename RealBody, typename Reduct ion>
Value parallel_reduce( const Range& range, const Value& identity, const Rea lBody& real_body, const Reduction& reduction, Value parallel_reduce( const Range& range, const Value& identity, const Rea lBody& real_body, const Reduction& reduction,
affinity_partitioner& partitioner, task_group_contex t& context ) { affinity_partitioner& partitioner, task_group_contex t& context ) {
internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(ident ity, real_body, reduction); internal::lambda_reduce_body<Range,Value,RealBody,Reduction> body(ident ity, real_body, reduction);
internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,R ealBody,Reduction>,affinity_partitioner> internal::start_reduce<Range,internal::lambda_reduce_body<Range,Value,R ealBody,Reduction>,affinity_partitioner>
::run( range, body, partitioner, co ntext ); ::run( range, body, partitioner, co ntext );
return body.result(); return body.result();
} }
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
//@} //@}
} // namespace tbb } // namespace tbb
#endif /* __TBB_parallel_reduce_H */ #endif /* __TBB_parallel_reduce_H */
 End of changes. 17 change blocks. 
20 lines changed or deleted 20 lines changed or added


 parallel_scan.h   parallel_scan.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 112 skipping to change at line 112
left_sum(NULL), left_sum(NULL),
left(NULL), left(NULL),
right(NULL), right(NULL),
left_is_final(left_is_final_), left_is_final(left_is_final_),
range(range_) 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(body);
poison_pointer(incoming); poison_pointer(incoming);
} }
task* create_child( const Range& range, final_sum_type& f, sum_node * 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->body = &f;
n->incoming = incoming; n->incoming = incoming_;
n->stuff_last = stuff_last; n->stuff_last = stuff_last_;
return n; return n;
} }
} }
/*override*/ task* execute() { /*override*/ task* execute() {
if( body ) { if( body ) {
if( incoming ) if( incoming )
left_sum->body.reverse_join( incoming->body ); left_sum->body.reverse_join( incoming->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 ht,left_sum,stuff_last); task* b = c.create_child(Range(range,split()),*left_sum,rig ht,left_sum,stuff_last);
skipping to change at line 188 skipping to change at line 188
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_), sum(sum_),
return_slot(return_slot_), return_slot(return_slot_),
right_zombie(NULL), right_zombie(NULL),
result(result_) result(result_)
{ {
__TBB_ASSERT( !return_slot, NULL ); __TBB_ASSERT( !return_slot, NULL );
} }
~finish_scan(){ ~finish_scan(){
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
if (is_cancelled()) { if (is_cancelled()) {
if (result.ref_count() == 0) destroy(result); if (result.ref_count() == 0) destroy(result);
if (right_zombie) destroy(*right_zombie); if (right_zombie) destroy(*right_zombie);
} }
#endif #endif
} }
}; };
//! Initial task to split the work //! Initial task to split the work
/** @ingroup algorithms */ /** @ingroup algorithms */
skipping to change at line 214 skipping to change at line 214
/** Non-null if caller is requesting total. */ /** Non-null if caller is requesting total. */
final_sum_type** sum; final_sum_type** sum;
sum_node_type** return_slot; sum_node_type** return_slot;
/** Null if computing root. */ /** Null if computing root. */
sum_node_type* parent_sum; sum_node_type* parent_sum;
bool is_final; bool is_final;
bool is_right_child; bool is_right_child;
Range range; Range range;
typename Partitioner::partition_type partition; typename Partitioner::partition_type partition;
/*override*/ task* execute(); /*override*/ task* execute();
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
tbb::task_group_context &my_context; tbb::task_group_context &my_context;
#endif #endif
// The class is intended to destroy allocated tasks if exception oc
curs
class task_cleaner: internal::no_copy {
typedef internal::start_scan<Range,Body,Partitioner> start_pass
1_type;
internal::sum_node<Range,Body>* my_root;
final_sum_type* my_temp_body;
const Range& my_range;
Body& my_body;
start_pass1_type* my_pass1;
public:
bool do_clean; // Set to true if cleanup is required.
task_cleaner(internal::sum_node<Range,Body>* root, final_sum_ty
pe* temp_body, const Range& range, Body& body, start_pass1_type* pass1)
: my_root(root), my_temp_body(temp_body), my_range(range),
my_body(body), my_pass1(pass1), do_clean(true) {}
~task_cleaner(){
if (do_clean) {
my_body.assign(my_temp_body->body);
my_temp_body->finish_construction( my_range, NULL );
my_temp_body->destroy(*my_temp_body);
}
}
};
public: public:
start_scan( sum_node_type*& return_slot_, start_scan& parent, sum_n start_scan( sum_node_type*& return_slot_, start_scan& parent_, sum_
ode_type* parent_sum_ node_type* parent_sum_
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, tbb::task_group_context &_context , tbb::task_group_context &context_
#endif #endif
) : ) :
body(parent.body), body(parent_.body),
sum(parent.sum), sum(parent_.sum),
return_slot(&return_slot_), return_slot(&return_slot_),
parent_sum(parent_sum_), parent_sum(parent_sum_),
is_final(parent.is_final), is_final(parent_.is_final),
is_right_child(false), is_right_child(false),
range(parent.range,split()), range(parent_.range,split()),
partition(parent.partition,split()) partition(parent_.partition,split())
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, my_context (_context) , my_context(context_)
#endif #endif
{ {
__TBB_ASSERT( !*return_slot, NULL ); __TBB_ASSERT( !*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_
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, tbb::task_group_context &_context , tbb::task_group_context &_context
#endif #endif
) : ) :
body(&body_), body(&body_),
sum(NULL), sum(NULL),
return_slot(&return_slot_), return_slot(&return_slot_),
parent_sum(NULL), parent_sum(NULL),
is_final(true), is_final(true),
is_right_child(false), is_right_child(false),
range(range_), range(range_),
partition(partitioner_) partition(partitioner_)
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, my_context (_context) , my_context (_context)
#endif #endif
{ {
__TBB_ASSERT( !*return_slot, NULL ); __TBB_ASSERT( !*return_slot, NULL );
} }
static void run( const Range& range, Body& body, const Partitioner & partitioner static void run( const Range& range, Body& body, const Partitioner & partitioner
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, task_group_context& context , task_group_context& context
#endif #endif
) { ) {
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;
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
final_sum_type* temp_body = new(task::allocate_root(context )) final_sum_type( body ); final_sum_type* temp_body = new(task::allocate_root(context )) final_sum_type( body );
start_pass1_type& pass1 = *new(task::allocate_root(context) ) start_pass1_type( start_pass1_type& pass1 = *new(task::allocate_root(context) ) start_pass1_type(
/*return_slot=*/root, /*return_slot=*/root,
range, range,
*temp_body, *temp_body,
partitioner, partitioner,
context context
); );
#else #else
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, /*return_slot=*/root,
range, range,
*temp_body, *temp_body,
partitioner ); partitioner );
#endif #endif
// The class is intended to destroy allocated tasks if exce
ption occurs
class task_cleaner: internal::no_copy {
internal::sum_node<Range,Body>* my_root;
final_sum_type* my_temp_body;
const Range& my_range;
Body& my_body;
start_pass1_type* my_pass1;
public:
bool do_clean; // Set to true if cleanup is required.
task_cleaner(internal::sum_node<Range,Body>* _root, fin
al_sum_type* _temp_body, const Range& _range, Body& _body, start_pass1_type
* _pass1)
: my_root(_root), my_temp_body(_temp_body), my_rang
e(_range), my_body(_body), my_pass1(_pass1), do_clean(true) {}
~task_cleaner(){
if (do_clean) {
my_body.assign(my_temp_body->body);
my_temp_body->finish_construction( my_range, NU
LL );
my_temp_body->destroy(*my_temp_body);
}
}
};
task_cleaner my_cleaner(root, temp_body, range, body, &pass 1); task_cleaner my_cleaner(root, temp_body, range, body, &pass 1);
task::spawn_root_and_wait( pass1 ); task::spawn_root_and_wait( pass1 );
my_cleaner.do_clean = false;
if( root ) { if( root ) {
my_cleaner.do_clean = false;
root->body = temp_body; root->body = temp_body;
root->incoming = NULL; root->incoming = NULL;
root->stuff_last = &body; root->stuff_last = &body;
task::spawn_root_and_wait( *root ); task::spawn_root_and_wait( *root );
} else {
my_cleaner.do_clean = true;
} }
} }
} }
}; };
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 = parent_sum ? static_cast<finish_pass1_type*> ( 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 = is_right_child && (is_stolen_task() || body! =p->result.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
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
p->right_zombie = body = new( allocate_root(my_context) ) final _sum_type(body->body); p->right_zombie = body = new( allocate_root(my_context) ) final _sum_type(body->body);
#else #else
p->right_zombie = body = new( allocate_root() ) final_sum_type( body->body); p->right_zombie = body = new( allocate_root() ) final_sum_type( body->body);
#endif #endif
is_final = false; is_final = false;
} }
task* next_task = NULL; task* next_task = NULL;
if( (is_right_child && !treat_as_stolen) || !range.is_divisible() | | partition.should_execute_range(*this) ) { if( (is_right_child && !treat_as_stolen) || !range.is_divisible() | | partition.should_execute_range(*this) ) {
if( is_final ) if( is_final )
(body->body)( range, final_scan_tag() ); (body->body)( range, final_scan_tag() );
else if( sum ) else if( sum )
(body->body)( range, pre_scan_tag() ); (body->body)( range, pre_scan_tag() );
if( sum ) if( sum )
*sum = body; *sum = body;
__TBB_ASSERT( !*return_slot, NULL ); __TBB_ASSERT( !*return_slot, NULL );
} else { } else {
sum_node_type* result; sum_node_type* result;
if( parent_sum ) if( parent_sum )
result = new(allocate_additional_child_of(*parent_sum)) sum _node_type(range,/*left_is_final=*/is_final); result = new(allocate_additional_child_of(*parent_sum)) sum _node_type(range,/*left_is_final=*/is_final);
else else
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
result = new(task::allocate_root(my_context)) sum_node_type (range,/*left_is_final=*/is_final); result = new(task::allocate_root(my_context)) sum_node_type (range,/*left_is_final=*/is_final);
#else #else
result = new(task::allocate_root()) sum_node_type(range,/*l eft_is_final=*/is_final); result = new(task::allocate_root()) sum_node_type(range,/*l eft_is_final=*/is_final);
#endif #endif
finish_pass1_type& c = *new( allocate_continuation()) finish_pa ss1_type(*return_slot,sum,*result); finish_pass1_type& c = *new( allocate_continuation()) finish_pa ss1_type(*return_slot,sum,*result);
// Split off right child // Split off right child
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
start_scan& b = *new( c.allocate_child() ) start_scan( /*return _slot=*/result->right, *this, result, my_context ); start_scan& b = *new( c.allocate_child() ) start_scan( /*return _slot=*/result->right, *this, result, my_context );
#else #else
start_scan& b = *new( c.allocate_child() ) start_scan( /*return _slot=*/result->right, *this, result ); start_scan& b = *new( c.allocate_child() ) start_scan( /*return _slot=*/result->right, *this, result );
#endif #endif
b.is_right_child = true; b.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);
skipping to change at line 405 skipping to change at line 407
**/ **/
/** \name parallel_scan /** \name parallel_scan
See also requirements on \ref range_req "Range" and \ref parallel_scan_ body_req "parallel_scan Body". **/ See also requirements on \ref range_req "Range" and \ref parallel_scan_ body_req "parallel_scan Body". **/
//@{ //@{
//! Parallel prefix with default partitioner //! Parallel prefix with default partitioner
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_scan( const Range& range, Body& body ) { void parallel_scan( const Range& range, Body& body ) {
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
task_group_context context; task_group_context context;
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
internal::start_scan<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,b ody,__TBB_DEFAULT_PARTITIONER() internal::start_scan<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,b ody,__TBB_DEFAULT_PARTITIONER()
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, context , context
#endif #endif
); );
} }
//! Parallel prefix with simple_partitioner //! Parallel prefix with simple_partitioner
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_scan( const Range& range, Body& body, const simple_partitione r& partitioner ) { void parallel_scan( const Range& range, Body& body, const simple_partitione r& partitioner ) {
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
task_group_context context; task_group_context context;
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
internal::start_scan<Range,Body,simple_partitioner>::run(range,body,par titioner internal::start_scan<Range,Body,simple_partitioner>::run(range,body,par titioner
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, context , context
#endif #endif
); );
} }
//! Parallel prefix with auto_partitioner //! Parallel prefix with auto_partitioner
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_scan( const Range& range, Body& body, const auto_partitioner& partitioner ) { void parallel_scan( const Range& range, Body& body, const auto_partitioner& partitioner ) {
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
task_group_context context; task_group_context context;
#endif // __TBB_EXCEPTIONS #endif // __TBB_TASK_GROUP_CONTEXT
internal::start_scan<Range,Body,auto_partitioner>::run(range,body,parti tioner internal::start_scan<Range,Body,auto_partitioner>::run(range,body,parti tioner
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
, context , context
#endif #endif
); );
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Parallel prefix with simple_partitioner and user-supplied context //! Parallel prefix with simple_partitioner and user-supplied context
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
void parallel_scan( const Range& range, Body& body, const simple_partitione r& partitioner, tbb::task_group_context & context ) { void parallel_scan( const Range& range, Body& body, const simple_partitione r& partitioner, tbb::task_group_context & context ) {
internal::start_scan<Range,Body,simple_partitioner>::run(range,body,par titioner,context); internal::start_scan<Range,Body,simple_partitioner>::run(range,body,par titioner,context);
} }
//! Parallel prefix with auto_partitioner and user-supplied context //! Parallel prefix with auto_partitioner and user-supplied context
/** @ingroup algorithms **/ /** @ingroup algorithms **/
template<typename Range, typename Body> template<typename Range, typename Body>
 End of changes. 32 change blocks. 
62 lines changed or deleted 63 lines changed or added


 parallel_sort.h   parallel_sort.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 parallel_while.h   parallel_while.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 partitioner.h   partitioner.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 65 skipping to change at line 65
/** Retains values if resulting size is the same. */ /** Retains values if resulting size is the same. */
void __TBB_EXPORTED_METHOD resize( unsigned factor ); void __TBB_EXPORTED_METHOD resize( unsigned factor );
friend class affinity_partition_type; friend class affinity_partition_type;
}; };
//! Provides default methods for partition objects without affinity. //! Provides default methods for partition objects without affinity.
class partition_type_base { class partition_type_base {
public: public:
void set_affinity( task & ) {} void set_affinity( task & ) {}
void note_affinity( task::affinity_id ) {} void note_affinity( task::affinity_id ) {}
task* continue_after_execute_range( task& ) {return NULL;} task* continue_after_execute_range() {return NULL;}
bool decide_whether_to_delay() {return false;} bool decide_whether_to_delay() {return false;}
void spawn_or_delay( bool, task& a, task& b ) { void spawn_or_delay( bool, task& b ) {
a.spawn(b); task::spawn(b);
} }
}; };
class affinity_partition_type; class affinity_partition_type;
template<typename Range, typename Body, typename Partitioner> class start_f or; template<typename Range, typename Body, typename Partitioner> class start_f or;
template<typename Range, typename Body, typename Partitioner> class start_r educe; template<typename Range, typename Body, typename Partitioner> class start_r educe;
template<typename Range, typename Body> class start_reduce_with_affinity; template<typename Range, typename Body> class start_reduce_with_affinity;
template<typename Range, typename Body, typename Partitioner> class start_s can; template<typename Range, typename Body, typename Partitioner> class start_s can;
skipping to change at line 191 skipping to change at line 191
} }
void set_affinity( task &t ) { void set_affinity( task &t ) {
if( map_begin<map_end ) if( map_begin<map_end )
t.set_affinity( my_array[map_begin] ); t.set_affinity( my_array[map_begin] );
} }
void note_affinity( task::affinity_id id ) { void note_affinity( task::affinity_id id ) {
if( map_begin<map_end ) if( map_begin<map_end )
my_array[map_begin] = id; my_array[map_begin] = id;
} }
task* continue_after_execute_range( task& t ) { task* continue_after_execute_range() {
task* first = NULL; task* first = NULL;
if( !delay_list.empty() ) { if( !delay_list.empty() ) {
first = &delay_list.pop_front(); first = &delay_list.pop_front();
while( !delay_list.empty() ) { while( !delay_list.empty() ) {
t.spawn(*first); task::spawn(*first);
first = &delay_list.pop_front(); first = &delay_list.pop_front();
} }
} }
return first; return first;
} }
bool decide_whether_to_delay() { bool decide_whether_to_delay() {
// The possible underflow caused by "-1u" is deliberate // The possible underflow caused by "-1u" is deliberate
return (map_begin&(factor-1))==0 && map_end-map_begin-1u<factor; return (map_begin&(factor-1))==0 && map_end-map_begin-1u<factor;
} }
void spawn_or_delay( bool delay, task& a, task& b ) { void spawn_or_delay( bool delay, task& b ) {
if( delay ) if( delay )
delay_list.push_back(b); delay_list.push_back(b);
else else
a.spawn(b); task::spawn(b);
} }
~affinity_partition_type() { ~affinity_partition_type() {
// The delay_list can be non-empty if an exception is thrown. // The delay_list can be non-empty if an exception is thrown.
while( !delay_list.empty() ) { while( !delay_list.empty() ) {
task& t = delay_list.pop_front(); task& t = delay_list.pop_front();
t.destroy(t); t.destroy(t);
} }
} }
}; };
 End of changes. 7 change blocks. 
8 lines changed or deleted 8 lines changed or added


 pipeline.h   pipeline.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 62 skipping to change at line 62
class pipeline_cleaner; class pipeline_cleaner;
} // namespace internal } // namespace internal
//! @endcond //! @endcond
//! A stage in a pipeline. //! A stage in a pipeline.
/** @ingroup algorithms */ /** @ingroup algorithms */
class filter: internal::no_copy { class filter: internal::no_copy {
private: private:
//! Value used to mark "not in pipeline" //! Value used to mark "not in pipeline"
static filter* not_in_pipeline() {return reinterpret_cast<filter*>(inte rnal::intptr(-1));} static filter* not_in_pipeline() {return reinterpret_cast<filter*>(intp tr_t(-1));}
//! The lowest bit 0 is for parallel vs. serial //! The lowest bit 0 is for parallel vs. serial
static const unsigned char filter_is_serial = 0x1; static const unsigned char filter_is_serial = 0x1;
//! 4th bit distinguishes ordered vs unordered filters. //! 4th bit distinguishes ordered vs unordered filters.
/** The bit was not set for parallel filters in TBB 2.1 and earlier, /** The bit was not set for parallel filters in TBB 2.1 and earlier,
but is_ordered() function always treats parallel filters as out of order. */ but is_ordered() function always treats parallel filters as out of order. */
static const unsigned char filter_is_out_of_order = 0x1<<4; static const unsigned char filter_is_out_of_order = 0x1<<4;
//! 5th bit distinguishes thread-bound and regular filters. //! 5th bit distinguishes thread-bound and regular filters.
skipping to change at line 131 skipping to change at line 131
} }
//! Operate on an item from the input stream, and return item for outpu t stream. //! Operate on an item from the input stream, and return item for outpu t stream.
/** Returns NULL if filter is a sink. */ /** Returns NULL if filter is a sink. */
virtual void* operator()( void* item ) = 0; virtual void* operator()( void* item ) = 0;
//! Destroy filter. //! Destroy filter.
/** If the filter was added to a pipeline, the pipeline must be destroy ed first. */ /** If the filter was added to a pipeline, the pipeline must be destroy ed first. */
virtual __TBB_EXPORTED_METHOD ~filter(); virtual __TBB_EXPORTED_METHOD ~filter();
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Destroys item if pipeline was cancelled. //! Destroys item if pipeline was cancelled.
/** Required to prevent memory leaks. /** Required to prevent memory leaks.
Note it can be called concurrently even for serial filters.*/ Note it can be called concurrently even for serial filters.*/
virtual void finalize( void* /*item*/ ) {}; virtual void finalize( void* /*item*/ ) {};
#endif #endif
private: private:
//! Pointer to next filter in the pipeline. //! Pointer to next filter in the pipeline.
filter* next_filter_in_pipeline; filter* next_filter_in_pipeline;
skipping to change at line 219 skipping to change at line 219
/** Though the current implementation declares the destructor virtual, do not rely on this /** Though the current implementation declares the destructor virtual, do not rely on this
detail. The virtualness is deprecated and may disappear in future versions of TBB. */ detail. The virtualness is deprecated and may disappear in future versions of TBB. */
virtual __TBB_EXPORTED_METHOD ~pipeline(); virtual __TBB_EXPORTED_METHOD ~pipeline();
//! Add filter to end of pipeline. //! Add filter to end of pipeline.
void __TBB_EXPORTED_METHOD add_filter( filter& filter_ ); void __TBB_EXPORTED_METHOD add_filter( filter& filter_ );
//! Run the pipeline to completion. //! Run the pipeline to completion.
void __TBB_EXPORTED_METHOD run( size_t max_number_of_live_tokens ); void __TBB_EXPORTED_METHOD run( size_t max_number_of_live_tokens );
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Run the pipeline to completion with user-supplied context. //! Run the pipeline to completion with user-supplied context.
void __TBB_EXPORTED_METHOD run( size_t max_number_of_live_tokens, tbb:: task_group_context& context ); void __TBB_EXPORTED_METHOD run( size_t max_number_of_live_tokens, tbb:: task_group_context& context );
#endif #endif
//! Remove all filters from the pipeline. //! Remove all filters from the pipeline.
void __TBB_EXPORTED_METHOD clear(); void __TBB_EXPORTED_METHOD clear();
private: private:
friend class internal::stage_task; friend class internal::stage_task;
friend class internal::pipeline_root_task; friend class internal::pipeline_root_task;
skipping to change at line 261 skipping to change at line 261
//! True if the pipeline contains a thread-bound filter; false otherwis e. //! True if the pipeline contains a thread-bound filter; false otherwis e.
bool has_thread_bound_filters; bool has_thread_bound_filters;
//! Remove filter from pipeline. //! Remove filter from pipeline.
void remove_filter( filter& filter_ ); void remove_filter( filter& filter_ );
//! Not used, but retained to satisfy old export files. //! Not used, but retained to satisfy old export files.
void __TBB_EXPORTED_METHOD inject_token( task& self ); void __TBB_EXPORTED_METHOD inject_token( task& self );
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Does clean up if pipeline is cancelled or exception occured //! Does clean up if pipeline is cancelled or exception occured
void clear_filters(); void clear_filters();
#endif #endif
}; };
} // tbb } // tbb
#endif /* __TBB_pipeline_H */ #endif /* __TBB_pipeline_H */
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 ppl.h   ppl.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 36 skipping to change at line 36
the GNU General Public License. the GNU General Public License.
*/ */
#ifndef __TBB_compat_ppl_H #ifndef __TBB_compat_ppl_H
#define __TBB_compat_ppl_H #define __TBB_compat_ppl_H
#include "../task_group.h" #include "../task_group.h"
#include "../parallel_invoke.h" #include "../parallel_invoke.h"
#include "../parallel_for_each.h" #include "../parallel_for_each.h"
#include "../parallel_for.h" #include "../parallel_for.h"
#include "../tbb_exception.h"
#include "../critical_section.h"
#include "../reader_writer_lock.h"
#include "../combinable.h"
namespace Concurrency { namespace Concurrency {
using tbb::task_handle; using tbb::task_handle;
using tbb::task_group_status; using tbb::task_group_status;
using tbb::task_group; using tbb::task_group;
using tbb::structured_task_group; using tbb::structured_task_group;
using tbb::invalid_multiple_scheduling;
using tbb::missing_wait; using tbb::missing_wait;
using tbb::make_task;
using tbb::not_complete; using tbb::not_complete;
using tbb::complete; using tbb::complete;
using tbb::canceled; using tbb::canceled;
using tbb::is_current_task_group_canceling; using tbb::is_current_task_group_canceling;
using tbb::parallel_invoke; using tbb::parallel_invoke;
using tbb::strict_ppl::parallel_for; using tbb::strict_ppl::parallel_for;
using tbb::parallel_for_each; using tbb::parallel_for_each;
using tbb::critical_section;
using tbb::reader_writer_lock;
using tbb::combinable;
using tbb::improper_lock;
} // namespace Concurrency } // namespace Concurrency
#endif /* __TBB_compat_ppl_H */ #endif /* __TBB_compat_ppl_H */
 End of changes. 5 change blocks. 
1 lines changed or deleted 12 lines changed or added


 queuing_mutex.h   queuing_mutex.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 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_queuing_mutex_H #ifndef __TBB_queuing_mutex_H
#define __TBB_queuing_mutex_H #define __TBB_queuing_mutex_H
#include "tbb_config.h"
#if !TBB_USE_EXCEPTIONS && _MSC_VER
// Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers
#pragma warning (push)
#pragma warning (disable: 4530)
#endif
#include <cstring> #include <cstring>
#if !TBB_USE_EXCEPTIONS && _MSC_VER
#pragma warning (pop)
#endif
#include "atomic.h" #include "atomic.h"
#include "tbb_profiling.h" #include "tbb_profiling.h"
namespace tbb { namespace tbb {
//! Queuing lock with local-only spinning. //! Queuing lock with local-only spinning.
/** @ingroup synchronization */ /** @ingroup synchronization */
class queuing_mutex { class queuing_mutex {
public: public:
//! Construct unacquired mutex. //! Construct unacquired mutex.
skipping to change at line 67 skipping to change at line 80
#if TBB_USE_ASSERT #if TBB_USE_ASSERT
internal::poison_pointer(next); internal::poison_pointer(next);
#endif /* TBB_USE_ASSERT */ #endif /* TBB_USE_ASSERT */
} }
public: public:
//! Construct lock that has not acquired a mutex. //! Construct lock that has not acquired a mutex.
/** Equivalent to zero-initialization of *this. */ /** Equivalent to zero-initialization of *this. */
scoped_lock() {initialize();} scoped_lock() {initialize();}
//! Acquire lock on given mutex. //! Acquire lock on given mutex.
/** Upon entry, *this should not be in the "have acquired a mutex" state. */
scoped_lock( queuing_mutex& m ) { scoped_lock( queuing_mutex& m ) {
initialize(); initialize();
acquire(m); acquire(m);
} }
//! Release lock (if lock is held). //! Release lock (if lock is held).
~scoped_lock() { ~scoped_lock() {
if( mutex ) release(); if( mutex ) release();
} }
 End of changes. 4 change blocks. 
2 lines changed or deleted 15 lines changed or added


 queuing_rw_mutex.h   queuing_rw_mutex.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 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_queuing_rw_mutex_H #ifndef __TBB_queuing_rw_mutex_H
#define __TBB_queuing_rw_mutex_H #define __TBB_queuing_rw_mutex_H
#include "tbb_config.h"
#if !TBB_USE_EXCEPTIONS && _MSC_VER
// Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers
#pragma warning (push)
#pragma warning (disable: 4530)
#endif
#include <cstring> #include <cstring>
#if !TBB_USE_EXCEPTIONS && _MSC_VER
#pragma warning (pop)
#endif
#include "atomic.h" #include "atomic.h"
#include "tbb_profiling.h" #include "tbb_profiling.h"
namespace tbb { namespace tbb {
//! Reader-writer lock with local-only spinning. //! Reader-writer lock with local-only spinning.
/** Adapted from Krieger, Stumm, et al. pseudocode at /** Adapted from Krieger, Stumm, et al. pseudocode at
http://www.eecg.toronto.edu/parallel/pubs_abs.html#Krieger_etal_ICPP93 http://www.eecg.toronto.edu/parallel/pubs_abs.html#Krieger_etal_ICPP93
@ingroup synchronization */ @ingroup synchronization */
class queuing_rw_mutex { class queuing_rw_mutex {
skipping to change at line 81 skipping to change at line 94
internal::poison_pointer(next); internal::poison_pointer(next);
internal::poison_pointer(prev); internal::poison_pointer(prev);
#endif /* TBB_USE_ASSERT */ #endif /* TBB_USE_ASSERT */
} }
public: public:
//! Construct lock that has not acquired a mutex. //! Construct lock that has not acquired a mutex.
/** Equivalent to zero-initialization of *this. */ /** Equivalent to zero-initialization of *this. */
scoped_lock() {initialize();} scoped_lock() {initialize();}
//! Acquire lock on given mutex. //! Acquire lock on given mutex.
/** Upon entry, *this should not be in the "have acquired a mutex" state. */
scoped_lock( queuing_rw_mutex& m, bool write=true ) { scoped_lock( queuing_rw_mutex& m, bool write=true ) {
initialize(); initialize();
acquire(m,write); acquire(m,write);
} }
//! Release lock (if lock is held). //! Release lock (if lock is held).
~scoped_lock() { ~scoped_lock() {
if( mutex ) release(); if( mutex ) release();
} }
 End of changes. 4 change blocks. 
2 lines changed or deleted 15 lines changed or added


 recursive_mutex.h   recursive_mutex.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 33 skipping to change at line 33
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_recursive_mutex_H #ifndef __TBB_recursive_mutex_H
#define __TBB_recursive_mutex_H #define __TBB_recursive_mutex_H
#if _WIN32||_WIN64 #if _WIN32||_WIN64
#include <windows.h>
#include <windows.h> #if !defined(_WIN32_WINNT)
#if !defined(_WIN32_WINNT) // The following Windows API function is declared explicitly;
// The following Windows API function is declared explicitly; // otherwise any user would have to specify /D_WIN32_WINNT=0x0400
// otherwise any user would have to specify /D_WIN32_WINNT=0x0400 extern "C" BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION );
extern "C" BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION ); #endif
#endif
#else /* if not _WIN32||_WIN64 */ #else /* if not _WIN32||_WIN64 */
#include <pthread.h>
#include <pthread.h>
namespace tbb { namespace internal {
// Use this internal TBB function to throw an exception
extern void handle_perror( int error_code, const char* what );
} } //namespaces
#endif /* _WIN32||_WIN64 */ #endif /* _WIN32||_WIN64 */
#include <new> #include <new>
#include "aligned_space.h" #include "aligned_space.h"
#include "tbb_stddef.h" #include "tbb_stddef.h"
#include "tbb_profiling.h" #include "tbb_profiling.h"
namespace tbb { namespace tbb {
//! Mutex that allows recursive mutex acquisition. //! Mutex that allows recursive mutex acquisition.
/** Mutex that allows recursive mutex acquisition. /** Mutex that allows recursive mutex acquisition.
skipping to change at line 223 skipping to change at line 215
s.internal_release(); s.internal_release();
#else #else
#if _WIN32||_WIN64 #if _WIN32||_WIN64
LeaveCriticalSection(&impl); LeaveCriticalSection(&impl);
#else #else
pthread_mutex_unlock(&impl); pthread_mutex_unlock(&impl);
#endif /* _WIN32||_WIN64 */ #endif /* _WIN32||_WIN64 */
#endif /* TBB_USE_ASSERT */ #endif /* TBB_USE_ASSERT */
} }
//! Return native_handle
#if _WIN32||_WIN64
typedef LPCRITICAL_SECTION native_handle_type;
#else
typedef pthread_mutex_t* native_handle_type;
#endif
native_handle_type native_handle() { return (native_handle_type) &impl;
}
private: private:
#if _WIN32||_WIN64 #if _WIN32||_WIN64
CRITICAL_SECTION impl; CRITICAL_SECTION impl;
enum state_t { enum state_t {
INITIALIZED=0x1234, INITIALIZED=0x1234,
DESTROYED=0x789A, DESTROYED=0x789A,
} state; } state;
#else #else
pthread_mutex_t impl; pthread_mutex_t impl;
#endif /* _WIN32||_WIN64 */ #endif /* _WIN32||_WIN64 */
 End of changes. 4 change blocks. 
16 lines changed or deleted 17 lines changed or added


 scalable_allocator.h   scalable_allocator.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 82 skipping to change at line 82
void * __TBB_EXPORTED_FUNC scalable_aligned_malloc (size_t size, size_t ali gnment); void * __TBB_EXPORTED_FUNC scalable_aligned_malloc (size_t size, size_t ali gnment);
/** The "_aligned_realloc" analogue. /** The "_aligned_realloc" analogue.
@ingroup memory_allocation */ @ingroup memory_allocation */
void * __TBB_EXPORTED_FUNC scalable_aligned_realloc (void* ptr, size_t size , size_t alignment); void * __TBB_EXPORTED_FUNC scalable_aligned_realloc (void* ptr, size_t size , size_t alignment);
/** The "_aligned_free" analogue. /** The "_aligned_free" analogue.
@ingroup memory_allocation */ @ingroup memory_allocation */
void __TBB_EXPORTED_FUNC scalable_aligned_free (void* ptr); void __TBB_EXPORTED_FUNC scalable_aligned_free (void* ptr);
/** The analogue of _msize/malloc_size/malloc_usable_size.
Returns the usable size of a memory block previously allocated by scala
ble_*,
or 0 (zero) if ptr does not point to such a block.
@ingroup memory_allocation */
size_t __TBB_EXPORTED_FUNC scalable_msize (void* ptr);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif /* __cplusplus */ #endif /* __cplusplus */
#ifdef __cplusplus #ifdef __cplusplus
#include <new> /* To use new with the placement argument */ #include <new> /* To use new with the placement argument */
/* Ensure that including this header does not cause implicit linkage with T BB */ /* Ensure that including this header does not cause implicit linkage with T BB */
#ifndef __TBB_NO_IMPLICIT_LINKAGE #ifndef __TBB_NO_IMPLICIT_LINKAGE
skipping to change at line 147 skipping to change at line 153
//! Free previously allocated block of memory //! Free previously allocated block of memory
void deallocate( pointer p, size_type ) { void deallocate( pointer p, size_type ) {
scalable_free( p ); scalable_free( p );
} }
//! Largest value for which method allocate might succeed. //! Largest value for which method allocate might succeed.
size_type max_size() const throw() { size_type max_size() const throw() {
size_type absolutemax = static_cast<size_type>(-1) / sizeof (value_ type); size_type absolutemax = static_cast<size_type>(-1) / sizeof (value_ type);
return (absolutemax > 0 ? absolutemax : 1); return (absolutemax > 0 ? absolutemax : 1);
} }
void construct( pointer p, const value_type& val ) { new(static_cast<vo id*>(p)) value_type(val); } void construct( pointer p, const value_type& value ) {::new((void*)(p)) value_type(value);}
void destroy( pointer p ) {p->~value_type();} void destroy( pointer p ) {p->~value_type();}
}; };
#if _MSC_VER && !defined(__INTEL_COMPILER) #if _MSC_VER && !defined(__INTEL_COMPILER)
#pragma warning (pop) #pragma warning (pop)
#endif // warning 4100 is back #endif // warning 4100 is back
//! Analogous to std::allocator<void>, as defined in ISO C++ Standard, Sect ion 20.4.1 //! Analogous to std::allocator<void>, as defined in ISO C++ Standard, Sect ion 20.4.1
/** @ingroup memory_allocation */ /** @ingroup memory_allocation */
template<> template<>
 End of changes. 3 change blocks. 
2 lines changed or deleted 9 lines changed or added


 spin_mutex.h   spin_mutex.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 spin_rw_mutex.h   spin_rw_mutex.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 95 skipping to change at line 95
}; };
#endif /* TBB_USE_ASSERT */ #endif /* TBB_USE_ASSERT */
//! The scoped locking pattern //! The scoped locking pattern
/** It helps to avoid the common problem of forgetting to release lock. /** It helps to avoid the common problem of forgetting to release lock.
It also nicely provides the "node" for queuing locks. */ It also nicely provides the "node" for queuing locks. */
class scoped_lock : internal::no_copy { class scoped_lock : internal::no_copy {
public: public:
//! Construct lock that has not acquired a mutex. //! Construct lock that has not acquired a mutex.
/** Equivalent to zero-initialization of *this. */ /** Equivalent to zero-initialization of *this. */
scoped_lock() : mutex(NULL) {} scoped_lock() : mutex(NULL), is_writer(false) {}
//! Acquire lock on given mutex. //! Acquire lock on given mutex.
/** Upon entry, *this should not be in the "have acquired a mutex" state. */
scoped_lock( spin_rw_mutex& m, bool write = true ) : mutex(NULL) { scoped_lock( spin_rw_mutex& m, bool write = true ) : mutex(NULL) {
acquire(m, write); acquire(m, write);
} }
//! Release lock (if lock is held). //! Release lock (if lock is held).
~scoped_lock() { ~scoped_lock() {
if( mutex ) release(); if( mutex ) release();
} }
//! Acquire lock on given mutex. //! Acquire lock on given mutex.
 End of changes. 3 change blocks. 
3 lines changed or deleted 2 lines changed or added


 task.h   task.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 35 skipping to change at line 35
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_task_H #ifndef __TBB_task_H
#define __TBB_task_H #define __TBB_task_H
#include "tbb_stddef.h" #include "tbb_stddef.h"
#include "tbb_machine.h" #include "tbb_machine.h"
#if __TBB_EXCEPTIONS typedef struct ___itt_caller *__itt_caller;
#include "cache_aligned_allocator.h"
#endif /* __TBB_EXCEPTIONS */
namespace tbb { namespace tbb {
class task; class task;
class task_list; class task_list;
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
class task_group_context; class task_group_context;
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
// MSVC does not allow taking the address of a member that was defined
// privately in task_base and made public in class task via a using declara
tion.
#if _MSC_VER || (__GNUC__==3 && __GNUC_MINOR__<3)
#define __TBB_TASK_BASE_ACCESS public
#else
#define __TBB_TASK_BASE_ACCESS private
#endif
namespace interface5 {
namespace internal {
//! Base class for methods that became static in TBB 3.0.
/** TBB's evolution caused the "this" argument for several methods
to become obsolete.
However, for backwards binary compatibility, the new methods ne
ed distinct names,
otherwise the One Definition Rule would be broken. Hence the n
ew methods are
defined in this private base class, and then exposed in class t
ask via
using declarations. */
class task_base: tbb::internal::no_copy {
__TBB_TASK_BASE_ACCESS:
friend class tbb::task;
#if !TBB_DEPRECATED_TASK_INTERFACE
//! Schedule task for execution when a worker becomes available
.
static void spawn( task& t );
//! Spawn multiple tasks and clear list.
static void spawn( task_list& list );
#endif /* !TBB_DEPRECATED_TASK_INTERFACE */
#if !TBB_DEPRECATED_TASK_INTERFACE || __TBB_BUILD
//! Destroy a task.
/** Usually, calling this method is unnecessary, because a task
is
implicitly deleted after its execute() method runs. Howeve
r,
sometimes a task needs to be explicitly deallocated, such a
s
when a root task is used as the parent in spawn_and_wait_fo
r_all. */
static void __TBB_EXPORTED_FUNC destroy( task& victim );
#endif /* TBB_DEPRECATED_TASK_INTERFACE || __TBB_BUILD */
};
} // internal
} // interface5
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
class scheduler: no_copy { class scheduler: no_copy {
public: public:
//! For internal use only //! For internal use only
virtual void spawn( task& first, task*& next ) = 0; virtual void spawn( task& first, task*& next ) = 0;
//! For internal use only //! For internal use only
virtual void wait_for_all( task& parent, task* child ) = 0; virtual void wait_for_all( task& parent, task* child ) = 0;
//! For internal use only //! For internal use only
virtual void spawn_root_and_wait( task& first, task*& next ) = 0; virtual void spawn_root_and_wait( task& first, task*& next ) = 0;
//! Pure virtual destructor; //! Pure virtual destructor;
// Have to have it just to shut up overzealous compilation warning s // Have to have it just to shut up overzealous compilation warning s
virtual ~scheduler() = 0; virtual ~scheduler() = 0;
#if __TBB_ARENA_PER_MASTER
//! For internal use only
virtual void enqueue( task& t, void* reserved ) = 0;
#endif /* __TBB_ARENA_PER_MASTER */
}; };
//! A reference count //! A reference count
/** Should always be non-negative. A signed type is used so that under flow can be detected. */ /** Should always be non-negative. A signed type is used so that under flow can be detected. */
typedef intptr reference_count; typedef intptr_t reference_count;
//! An id as used for specifying affinity. //! An id as used for specifying affinity.
typedef unsigned short affinity_id; typedef unsigned short affinity_id;
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
struct context_list_node_t { struct context_list_node_t {
context_list_node_t *my_prev, context_list_node_t *my_prev,
*my_next; *my_next;
}; };
class allocate_root_with_context_proxy: no_assign { class allocate_root_with_context_proxy: no_assign {
task_group_context& my_context; task_group_context& my_context;
public: public:
allocate_root_with_context_proxy ( task_group_context& ctx ) : my_c ontext(ctx) {} allocate_root_with_context_proxy ( task_group_context& ctx ) : my_c ontext(ctx) {}
task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
void __TBB_EXPORTED_METHOD free( task& ) const; void __TBB_EXPORTED_METHOD free( task& ) const;
}; };
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
class allocate_root_proxy: no_assign { class allocate_root_proxy: no_assign {
public: public:
static task& __TBB_EXPORTED_FUNC allocate( size_t size ); static task& __TBB_EXPORTED_FUNC allocate( size_t size );
static void __TBB_EXPORTED_FUNC free( task& ); static void __TBB_EXPORTED_FUNC free( task& );
}; };
class allocate_continuation_proxy: no_assign { class allocate_continuation_proxy: no_assign {
public: public:
task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
skipping to change at line 116 skipping to change at line 158
class allocate_additional_child_of_proxy: no_assign { class allocate_additional_child_of_proxy: no_assign {
task& self; task& self;
task& parent; task& parent;
public: public:
allocate_additional_child_of_proxy( task& self_, task& parent_ ) : self(self_), parent(parent_) {} allocate_additional_child_of_proxy( task& self_, task& parent_ ) : self(self_), parent(parent_) {}
task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
void __TBB_EXPORTED_METHOD free( task& ) const; void __TBB_EXPORTED_METHOD free( task& ) const;
}; };
class task_group_base;
//! Memory prefix to a task object. //! Memory prefix to a task object.
/** This class is internal to the library. /** This class is internal to the library.
Do not reference it directly, except within the library itself. Do not reference it directly, except within the library itself.
Fields are ordered in way that preserves backwards compatibility an d yields Fields are ordered in way that preserves backwards compatibility an d yields
good packing on typical 32-bit and 64-bit platforms. good packing on typical 32-bit and 64-bit platforms.
@ingroup task_scheduling */ @ingroup task_scheduling */
class task_prefix { class task_prefix {
private: private:
friend class tbb::task; friend class tbb::task;
friend class tbb::interface5::internal::task_base;
friend class tbb::task_list; friend class tbb::task_list;
friend class internal::scheduler; friend class internal::scheduler;
friend class internal::allocate_root_proxy; friend class internal::allocate_root_proxy;
friend class internal::allocate_child_proxy; friend class internal::allocate_child_proxy;
friend class internal::allocate_continuation_proxy; friend class internal::allocate_continuation_proxy;
friend class internal::allocate_additional_child_of_proxy; friend class internal::allocate_additional_child_of_proxy;
friend class internal::task_group_base;
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Shared context that is used to communicate asynchronous state c hanges //! Shared context that is used to communicate asynchronous state c hanges
/** Currently it is used to broadcast cancellation requests generat ed both /** Currently it is used to broadcast cancellation requests generat ed both
by users and as the result of unhandled exceptions in the task: :execute() by users and as the result of unhandled exceptions in the task: :execute()
methods. */ methods. */
task_group_context *context; task_group_context *context;
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
//! The scheduler that allocated the task, or NULL if the task is b ig. //! The scheduler that allocated the task, or NULL if the task is b ig.
/** Small tasks are pooled by the scheduler that allocated the task . /** Small tasks are pooled by the scheduler that allocated the task .
If a scheduler needs to free a small task allocated by another scheduler, If a scheduler needs to free a small task allocated by another scheduler,
it returns the task to that other scheduler. This policy avoid s it returns the task to that other scheduler. This policy avoid s
memory space blowup issues for memory allocators that allocate from memory space blowup issues for memory allocators that allocate from
thread-specific pools. */ thread-specific pools. */
scheduler* origin; scheduler* origin;
//! The scheduler that owns the task. //! The scheduler that owns the task.
skipping to change at line 167 skipping to change at line 207
continuation of the parent. */ continuation of the parent. */
tbb::task* parent; tbb::task* parent;
//! Reference count used for synchronization. //! Reference count used for synchronization.
/** In the "continuation-passing style" of programming, this field is /** In the "continuation-passing style" of programming, this field is
the difference of the number of allocated children minus the the difference of the number of allocated children minus the
number of children that have completed. number of children that have completed.
In the "blocking style" of programming, this field is one more than the difference. */ In the "blocking style" of programming, this field is one more than the difference. */
reference_count ref_count; reference_count ref_count;
//! Scheduling depth //! Obsolete. Used to be scheduling depth before TBB 2.2
/** Retained only for the sake of backward binary compatibility. **
/
int depth; int depth;
//! A task::state_type, stored as a byte for compactness. //! A task::state_type, stored as a byte for compactness.
/** This state is exposed to users via method task::state(). */ /** This state is exposed to users via method task::state(). */
unsigned char state; unsigned char state;
//! Miscellaneous state that is not directly visible to users, stor ed as a byte for compactness. //! Miscellaneous state that is not directly visible to users, stor ed as a byte for compactness.
/** 0x0 -> version 1.0 task /** 0x0 -> version 1.0 task
0x1 -> version 3.0 task 0x1 -> version >=2.1 task
0x2 -> task_proxy 0x20 -> task_proxy
0x40 -> task has live ref_count */ 0x40 -> task has live ref_count
0x80 -> a stolen task */
unsigned char extra_state; unsigned char extra_state;
affinity_id affinity; affinity_id affinity;
//! "next" field for list of task //! "next" field for list of task
tbb::task* next; tbb::task* next;
//! The task corresponding to this task_prefix. //! The task corresponding to this task_prefix.
tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);} tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);}
}; };
} // namespace internal } // namespace internal
//! @endcond //! @endcond
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
#if TBB_USE_CAPTURED_EXCEPTION #if TBB_USE_CAPTURED_EXCEPTION
class tbb_exception; class tbb_exception;
#else #else
namespace internal { namespace internal {
class tbb_exception_ptr; class tbb_exception_ptr;
} }
#endif /* !TBB_USE_CAPTURED_EXCEPTION */ #endif /* !TBB_USE_CAPTURED_EXCEPTION */
//! Used to form groups of tasks //! Used to form groups of tasks
skipping to change at line 224 skipping to change at line 266
The context can be bound to another one, and other contexts can be boun d to it, The context can be bound to another one, and other contexts can be boun d to it,
forming a tree-like structure: parent -> this -> children. Arrows here designate forming a tree-like structure: parent -> this -> children. Arrows here designate
cancellation propagation direction. If a task in a cancellation group i s canceled cancellation propagation direction. If a task in a cancellation group i s canceled
all the other tasks in this group and groups bound to it (as children) get canceled too. all the other tasks in this group and groups bound to it (as children) get canceled too.
IMPLEMENTATION NOTE: IMPLEMENTATION NOTE:
When adding new members to task_group_context or changing types of exis ting ones, When adding new members to task_group_context or changing types of exis ting ones,
update the size of both padding buffers (_leading_padding and _trailing _padding) update the size of both padding buffers (_leading_padding and _trailing _padding)
appropriately. See also VERSIONING NOTE at the constructor definition b elow. **/ appropriately. See also VERSIONING NOTE at the constructor definition b elow. **/
class task_group_context : internal::no_copy class task_group_context : internal::no_copy {
{
private: private:
#if TBB_USE_CAPTURED_EXCEPTION #if TBB_USE_CAPTURED_EXCEPTION
typedef tbb_exception exception_container_type; typedef tbb_exception exception_container_type;
#else #else
typedef internal::tbb_exception_ptr exception_container_type; typedef internal::tbb_exception_ptr exception_container_type;
#endif #endif
enum version_traits_word_layout { enum version_traits_word_layout {
traits_offset = 16, traits_offset = 16,
version_mask = 0xFFFF, version_mask = 0xFFFF,
skipping to change at line 271 skipping to change at line 312
}; };
//! Pointer to the context of the parent cancellation group. NULL for i solated contexts. //! Pointer to the context of the parent cancellation group. NULL for i solated contexts.
task_group_context *my_parent; task_group_context *my_parent;
//! Used to form the thread specific list of contexts without additiona l memory allocation. //! Used to form the thread specific list of contexts without additiona l memory allocation.
/** A context is included into the list of the current thread when its binding to /** A context is included into the list of the current thread when its binding to
its parent happens. Any context can be present in the list of one t hread only. **/ its parent happens. Any context can be present in the list of one t hread only. **/
internal::context_list_node_t my_node; internal::context_list_node_t my_node;
//! Used to set and maintain stack stitching point for Intel Performanc
e Tools.
__itt_caller itt_caller;
//! Leading padding protecting accesses to frequently used members from false sharing. //! Leading padding protecting accesses to frequently used members from false sharing.
/** Read accesses to the field my_cancellation_requested are on the hot path inside /** Read accesses to the field my_cancellation_requested are on the hot path inside
the scheduler. This padding ensures that this field never shares th e same cache the scheduler. This padding ensures that this field never shares th e same cache
line with a local variable that is frequently written to. **/ line with a local variable that is frequently written to. **/
char _leading_padding[internal::NFS_MaxLineSize - char _leading_padding[internal::NFS_MaxLineSize -
2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal: 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal:
:context_list_node_t)]; :context_list_node_t)
- sizeof(__itt_caller)];
//! Specifies whether cancellation was request for this task group. //! Specifies whether cancellation was request for this task group.
uintptr_t my_cancellation_requested; uintptr_t my_cancellation_requested;
//! Version for run-time checks and behavioral traits of the context. //! Version for run-time checks and behavioral traits of the context.
/** Version occupies low 16 bits, and traits (zero or more ORed enumera tors /** Version occupies low 16 bits, and traits (zero or more ORed enumera tors
from the traits_type enumerations) take the next 16 bits. from the traits_type enumerations) take the next 16 bits.
Original (zeroth) version of the context did not support any traits . **/ Original (zeroth) version of the context did not support any traits . **/
uintptr_t my_version_and_traits; uintptr_t my_version_and_traits;
skipping to change at line 382 skipping to change at line 427
//! Out-of-line part of the constructor. //! Out-of-line part of the constructor.
/** Singled out to ensure backward binary compatibility of the future v ersions. **/ /** Singled out to ensure backward binary compatibility of the future v ersions. **/
void __TBB_EXPORTED_METHOD init (); void __TBB_EXPORTED_METHOD init ();
private: private:
friend class task; friend class task;
friend class internal::allocate_root_with_context_proxy; friend class internal::allocate_root_with_context_proxy;
static const kind_type binding_required = bound; static const kind_type binding_required = bound;
static const kind_type binding_completed = kind_type(bound+1); static const kind_type binding_completed = kind_type(bound+1);
static const kind_type detached = kind_type(binding_completed+1);
static const kind_type dying = kind_type(detached+1);
//! Checks if any of the ancestors has a cancellation request outstandi ng, //! Checks if any of the ancestors has a cancellation request outstandi ng,
//! and propagates it back to descendants. //! and propagates it back to descendants.
void propagate_cancellation_from_ancestors (); void propagate_cancellation_from_ancestors ();
//! For debugging purposes only. //! For debugging purposes only.
bool is_alive () { bool is_alive () {
#if TBB_USE_DEBUG #if TBB_USE_DEBUG
return my_version_and_traits != 0xDeadBeef; return my_version_and_traits != 0xDeadBeef;
#else #else
return true; return true;
#endif /* TBB_USE_DEBUG */ #endif /* TBB_USE_DEBUG */
} }
}; // class task_group_context }; // class task_group_context
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
//! Base class for user-defined tasks. //! Base class for user-defined tasks.
/** @ingroup task_scheduling */ /** @ingroup task_scheduling */
class task: internal::no_copy { class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base {
//! Set reference count //! Set reference count
void __TBB_EXPORTED_METHOD internal_set_ref_count( int count ); void __TBB_EXPORTED_METHOD internal_set_ref_count( int count );
//! Decrement reference count and return true if non-zero. //! Decrement reference count and return its new value.
internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_ count(); internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_ count();
protected: protected:
//! Default constructor. //! Default constructor.
task() {prefix().extra_state=1;} task() {prefix().extra_state=1;}
public: public:
//! Destructor. //! Destructor.
virtual ~task() {} virtual ~task() {}
skipping to change at line 432 skipping to change at line 480
executing, executing,
//! task to be rescheduled. //! task to be rescheduled.
reexecute, reexecute,
//! task is in ready pool, or is going to be put there, or was just taken off. //! task is in ready pool, or is going to be put there, or was just taken off.
ready, ready,
//! task object is freshly allocated or recycled. //! task object is freshly allocated or recycled.
allocated, allocated,
//! task object is on free list, or is going to be put there, or wa s just taken off. //! task object is on free list, or is going to be put there, or wa s just taken off.
freed, freed,
//! task to be recycled as continuation //! task to be recycled as continuation
recycle recycle,
//! task to be scheduled for starvation-resistant execution
to_enqueue
}; };
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
// Allocating tasks // Allocating tasks
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
//! Returns proxy for overloaded new that allocates a root task. //! Returns proxy for overloaded new that allocates a root task.
static internal::allocate_root_proxy allocate_root() { static internal::allocate_root_proxy allocate_root() {
return internal::allocate_root_proxy(); return internal::allocate_root_proxy();
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Returns proxy for overloaded new that allocates a root task associa ted with user supplied context. //! Returns proxy for overloaded new that allocates a root task associa ted with user supplied context.
static internal::allocate_root_with_context_proxy allocate_root( task_g roup_context& ctx ) { static internal::allocate_root_with_context_proxy allocate_root( task_g roup_context& ctx ) {
return internal::allocate_root_with_context_proxy(ctx); return internal::allocate_root_with_context_proxy(ctx);
} }
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
//! Returns proxy for overloaded new that allocates a continuation task of *this. //! Returns proxy for overloaded new that allocates a continuation task of *this.
/** The continuation's parent becomes the parent of *this. */ /** The continuation's parent becomes the parent of *this. */
internal::allocate_continuation_proxy& allocate_continuation() { internal::allocate_continuation_proxy& allocate_continuation() {
return *reinterpret_cast<internal::allocate_continuation_proxy*>(th is); return *reinterpret_cast<internal::allocate_continuation_proxy*>(th is);
} }
//! Returns proxy for overloaded new that allocates a child task of *th is. //! Returns proxy for overloaded new that allocates a child task of *th is.
internal::allocate_child_proxy& allocate_child() { internal::allocate_child_proxy& allocate_child() {
return *reinterpret_cast<internal::allocate_child_proxy*>(this); return *reinterpret_cast<internal::allocate_child_proxy*>(this);
} }
//! Like allocate_child, except that task's parent becomes "t", not thi s. //! Like allocate_child, except that task's parent becomes "t", not thi s.
/** Typically used in conjunction with schedule_to_reexecute to impleme nt while loops. /** Typically used in conjunction with schedule_to_reexecute to impleme nt while loops.
Atomically increments the reference count of t.parent() */ Atomically increments the reference count of t.parent() */
internal::allocate_additional_child_of_proxy allocate_additional_child_ of( task& t ) { internal::allocate_additional_child_of_proxy allocate_additional_child_ of( task& t ) {
return internal::allocate_additional_child_of_proxy(*this,t); return internal::allocate_additional_child_of_proxy(*this,t);
} }
#if TBB_DEPRECATED_TASK_INTERFACE
//! Destroy a task. //! Destroy a task.
/** Usually, calling this method is unnecessary, because a task is /** Usually, calling this method is unnecessary, because a task is
implicitly deleted after its execute() method runs. However, implicitly deleted after its execute() method runs. However,
sometimes a task needs to be explicitly deallocated, such as sometimes a task needs to be explicitly deallocated, such as
when a root task is used as the parent in spawn_and_wait_for_all. * / when a root task is used as the parent in spawn_and_wait_for_all. * /
void __TBB_EXPORTED_METHOD destroy( task& victim ); void __TBB_EXPORTED_METHOD destroy( task& t );
#else
//! Define recommended static form via import from base class.
using task_base::destroy;
#endif /* TBB_DEPRECATED_TASK_INTERFACE */
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
// Recycling of tasks // Recycling of tasks
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
//! Change this to be a continuation of its former self. //! Change this to be a continuation of its former self.
/** The caller must guarantee that the task's refcount does not become zero until /** The caller must guarantee that the task's refcount does not become zero until
after the method execute() returns. Typically, this is done by hav ing after the method execute() returns. Typically, this is done by hav ing
method execute() return a pointer to a child of the task. If the g uarantee method execute() return a pointer to a child of the task. If the g uarantee
cannot be made, use method recycle_as_safe_continuation instead. cannot be made, use method recycle_as_safe_continuation instead.
Because of the hazard, this method may be deprecated in the future. */ Because of the hazard, this method may be deprecated in the future. */
void recycle_as_continuation() { void recycle_as_continuation() {
__TBB_ASSERT( prefix().state==executing, "execute not running?" ); __TBB_ASSERT( prefix().state==executing, "execute not running?" );
prefix().state = allocated; prefix().state = allocated;
} }
//! Recommended to use, safe variant of recycle_as_continuation //! Recommended to use, safe variant of recycle_as_continuation
/** For safety, it requires additional increment of ref_count. */ /** For safety, it requires additional increment of ref_count.
With no decendants and ref_count of 1, it has the semantics of recy
cle_to_reexecute. */
void recycle_as_safe_continuation() { void recycle_as_safe_continuation() {
__TBB_ASSERT( prefix().state==executing, "execute not running?" ); __TBB_ASSERT( prefix().state==executing, "execute not running?" );
prefix().state = recycle; prefix().state = recycle;
} }
//! Change this to be a child of new_parent. //! Change this to be a child of new_parent.
void recycle_as_child_of( task& new_parent ) { void recycle_as_child_of( task& new_parent ) {
internal::task_prefix& p = prefix(); internal::task_prefix& p = prefix();
__TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" ); __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" );
__TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when r ecycled as a child" ); __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when r ecycled as a child" );
__TBB_ASSERT( p.parent==NULL, "parent must be null" ); __TBB_ASSERT( p.parent==NULL, "parent must be null" );
__TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" ); __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" );
__TBB_ASSERT( new_parent.prefix().state!=freed, "parent already fre ed" ); __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already fre ed" );
p.state = allocated; p.state = allocated;
p.parent = &new_parent; p.parent = &new_parent;
p.depth = new_parent.prefix().depth+1; #if __TBB_TASK_GROUP_CONTEXT
#if __TBB_EXCEPTIONS
p.context = new_parent.prefix().context; p.context = new_parent.prefix().context;
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
} }
//! Schedule this for reexecution after current execute() returns. //! Schedule this for reexecution after current execute() returns.
/** Requires that this.execute() be running. */ /** Made obsolete by recycle_as_safe_continuation; may become deprecate d. */
void recycle_to_reexecute() { void recycle_to_reexecute() {
__TBB_ASSERT( prefix().state==executing, "execute not running, or a lready recycled" ); __TBB_ASSERT( prefix().state==executing, "execute not running, or a lready recycled" );
__TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when r ecycled for reexecution" ); __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when r ecycled for reexecution" );
prefix().state = reexecute; prefix().state = reexecute;
} }
#if __TBB_TASK_DEQUE
// All depth-related methods are obsolete, and are retained for the sak e // All depth-related methods are obsolete, and are retained for the sak e
// of backward source compatibility only // of backward source compatibility only
intptr_t depth() const {return 0;} intptr_t depth() const {return 0;}
void set_depth( intptr_t ) {} void set_depth( intptr_t ) {}
void add_to_depth( int ) {} void add_to_depth( int ) {}
#else /* !__TBB_TASK_DEQUE */
//! A scheduling depth.
/** Guaranteed to be a signed integral type. */
typedef internal::intptr depth_type;
//! Scheduling depth
depth_type depth() const {return prefix().depth;}
//! Set scheduling depth to given value.
/** The depth must be non-negative */
void set_depth( depth_type new_depth ) {
__TBB_ASSERT( state()!=ready, "cannot change depth of ready task" )
;
__TBB_ASSERT( new_depth>=0, "depth cannot be negative" );
__TBB_ASSERT( new_depth==int(new_depth), "integer overflow error");
prefix().depth = int(new_depth);
}
//! Change scheduling depth by given amount.
/** The resulting depth must be non-negative. */
void add_to_depth( int delta ) {
__TBB_ASSERT( state()!=ready, "cannot change depth of ready task" )
;
__TBB_ASSERT( prefix().depth>=-delta, "depth cannot be negative" );
prefix().depth+=delta;
}
#endif /* !__TBB_TASK_DEQUE */
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
// Spawning and blocking // Spawning and blocking
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
//! Set reference count //! Set reference count
void set_ref_count( int count ) { void set_ref_count( int count ) {
#if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
internal_set_ref_count(count); internal_set_ref_count(count);
#else #else
prefix().ref_count = count; prefix().ref_count = count;
#endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */ #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
} }
//! Atomically increment reference count. //! Atomically increment reference count.
/** Has acquire semantics */ /** Has acquire semantics */
void increment_ref_count() { void increment_ref_count() {
__TBB_FetchAndIncrementWacquire( &prefix().ref_count ); __TBB_FetchAndIncrementWacquire( &prefix().ref_count );
} }
//! Atomically decrement reference count. //! Atomically decrement reference count.
/** Has release semanics. */ /** Has release semantics. */
int decrement_ref_count() { int decrement_ref_count() {
#if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
return int(internal_decrement_ref_count()); return int(internal_decrement_ref_count());
#else #else
return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))- 1; return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))- 1;
#endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */ #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
} }
#if TBB_DEPRECATED_TASK_INTERFACE
//! Schedule task for execution when a worker becomes available. //! Schedule task for execution when a worker becomes available.
/** After all children spawned so far finish their method task::execute , /** After all children spawned so far finish their method task::execute ,
their parent's method task::execute may start running. Therefore, it their parent's method task::execute may start running. Therefore, it
is important to ensure that at least one child has not completed un til is important to ensure that at least one child has not completed un til
the parent is ready to run. */ the parent is ready to run. */
void spawn( task& child ) { void spawn( task& t );
#if !__TBB_RELAXED_OWNERSHIP
__TBB_ASSERT( is_owned_by_current_thread(), "'this' not owned by cu
rrent thread" );
#endif /* !__TBB_RELAXED_OWNERSHIP */
prefix().owner->spawn( child, child.prefix().next );
}
//! Spawn multiple tasks and clear list. //! Spawn multiple tasks and clear list.
/** All of the tasks must be at the same depth. */
void spawn( task_list& list ); void spawn( task_list& list );
#else
//! Define recommended static forms via import from base class.
using task_base::spawn;
#endif /* TBB_DEPRECATED_TASK_INTERFACE */
//! Similar to spawn followed by wait_for_all, but more efficient. //! Similar to spawn followed by wait_for_all, but more efficient.
void spawn_and_wait_for_all( task& child ) { void spawn_and_wait_for_all( task& child ) {
#if !__TBB_RELAXED_OWNERSHIP
__TBB_ASSERT( is_owned_by_current_thread(), "'this' not owned by cu
rrent thread" );
#endif /* !__TBB_RELAXED_OWNERSHIP */
prefix().owner->wait_for_all( *this, &child ); prefix().owner->wait_for_all( *this, &child );
} }
//! Similar to spawn followed by wait_for_all, but more efficient. //! Similar to spawn followed by wait_for_all, but more efficient.
void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list ); void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list );
//! Spawn task allocated by allocate_root, wait for it to complete, and deallocate it. //! Spawn task allocated by allocate_root, wait for it to complete, and deallocate it.
/** The thread that calls spawn_root_and_wait must be the same thread
that allocated the task. */
static void spawn_root_and_wait( task& root ) { static void spawn_root_and_wait( task& root ) {
#if !__TBB_RELAXED_OWNERSHIP
__TBB_ASSERT( root.is_owned_by_current_thread(), "root not owned by
current thread" );
#endif /* !__TBB_RELAXED_OWNERSHIP */
root.prefix().owner->spawn_root_and_wait( root, root.prefix().next ); root.prefix().owner->spawn_root_and_wait( root, root.prefix().next );
} }
//! Spawn root tasks on list and wait for all of them to finish. //! Spawn root tasks on list and wait for all of them to finish.
/** If there are more tasks than worker threads, the tasks are spawned in /** If there are more tasks than worker threads, the tasks are spawned in
order of front to back. */ order of front to back. */
static void spawn_root_and_wait( task_list& root_list ); static void spawn_root_and_wait( task_list& root_list );
//! Wait for reference count to become one, and set reference count to zero. //! Wait for reference count to become one, and set reference count to zero.
/** Works on tasks while waiting. */ /** Works on tasks while waiting. */
void wait_for_all() { void wait_for_all() {
#if !__TBB_RELAXED_OWNERSHIP
__TBB_ASSERT( is_owned_by_current_thread(), "'this' not owned by cu
rrent thread" );
#endif /* !__TBB_RELAXED_OWNERSHIP */
prefix().owner->wait_for_all( *this, NULL ); prefix().owner->wait_for_all( *this, NULL );
} }
#if __TBB_ARENA_PER_MASTER
//! Enqueue task for starvation-resistant execution.
static void enqueue( task& t ) {
t.prefix().owner->enqueue( t, NULL );
}
#endif /* __TBB_ARENA_PER_MASTER */
//! The innermost task being executed or destroyed by the current threa d at the moment. //! The innermost task being executed or destroyed by the current threa d at the moment.
static task& __TBB_EXPORTED_FUNC self(); static task& __TBB_EXPORTED_FUNC self();
//! task on whose behalf this task is working, or NULL if this is a roo t. //! task on whose behalf this task is working, or NULL if this is a roo t.
task* parent() const {return prefix().parent;} task* parent() const {return prefix().parent;}
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Shared context that is used to communicate asynchronous state chang es //! Shared context that is used to communicate asynchronous state chang es
task_group_context* context() {return prefix().context;} task_group_context* context() {return prefix().context;}
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
//! True if task is owned by different thread than thread that owns its parent. //! True if task was stolen from the task pool of another thread.
bool is_stolen_task() const { bool is_stolen_task() const {
#if __TBB_PROVIDE_VIRTUAL_SCHEDULER return (prefix().extra_state & 0x80)!=0;
// The virtual scheduler directly identifies stolen tasks.
int es_virtual_steal = 4;
if(prefix().extra_state & es_virtual_steal)
return true;
#endif /* TBB_PROVIDE_VIRTUAL_SCHEDULER */
internal::task_prefix& p = prefix();
internal::task_prefix& q = parent()->prefix();
return p.owner!=q.owner;
} }
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
// Debugging // Debugging
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
//! Current execution state //! Current execution state
state_type state() const {return state_type(prefix().state);} state_type state() const {return state_type(prefix().state);}
//! The internal reference count. //! The internal reference count.
int ref_count() const { int ref_count() const {
#if TBB_USE_ASSERT #if TBB_USE_ASSERT
internal::reference_count ref_count = prefix().ref_count; internal::reference_count ref_count_ = prefix().ref_count;
__TBB_ASSERT( ref_count==int(ref_count), "integer overflow error"); __TBB_ASSERT( ref_count_==int(ref_count_), "integer overflow error"
);
#endif #endif
return int(prefix().ref_count); return int(prefix().ref_count);
} }
//! True if this task is owned by the calling thread; false otherwise. //! Obsolete, and only retained for the sake of backward compatibility. Always returns true.
bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const; bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const;
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
// Affinity // Affinity
//--------------------------------------------------------------------- --- //--------------------------------------------------------------------- ---
//! An id as used for specifying affinity. //! An id as used for specifying affinity.
/** Guaranteed to be integral type. Value of 0 means no affinity. */ /** Guaranteed to be integral type. Value of 0 means no affinity. */
typedef internal::affinity_id affinity_id; typedef internal::affinity_id affinity_id;
skipping to change at line 700 skipping to change at line 715
//! Current affinity of this task //! Current affinity of this task
affinity_id affinity() const {return prefix().affinity;} affinity_id affinity() const {return prefix().affinity;}
//! Invoked by scheduler to notify task that it ran on unexpected threa d. //! Invoked by scheduler to notify task that it ran on unexpected threa d.
/** Invoked before method execute() runs, if task is stolen, or task ha s /** Invoked before method execute() runs, if task is stolen, or task ha s
affinity but will be executed on another thread. affinity but will be executed on another thread.
The default action does nothing. */ The default action does nothing. */
virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id ); virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id );
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
//! Initiates cancellation of all tasks in this cancellation group and its subordinate groups. //! Initiates cancellation of all tasks in this cancellation group and its subordinate groups.
/** \return false if cancellation has already been requested, true othe rwise. **/ /** \return false if cancellation has already been requested, true othe rwise. **/
bool cancel_group_execution () { return prefix().context->cancel_group_ execution(); } bool cancel_group_execution () { return prefix().context->cancel_group_ execution(); }
//! Returns true if the context received cancellation request. //! Returns true if the context received cancellation request.
bool is_cancelled () const { return prefix().context->is_group_executio n_cancelled(); } bool is_cancelled () const { return prefix().context->is_group_executio n_cancelled(); }
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
private: private:
friend class interface5::internal::task_base;
friend class task_list; friend class task_list;
friend class internal::scheduler; friend class internal::scheduler;
friend class internal::allocate_root_proxy; friend class internal::allocate_root_proxy;
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
friend class internal::allocate_root_with_context_proxy; friend class internal::allocate_root_with_context_proxy;
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
friend class internal::allocate_continuation_proxy; friend class internal::allocate_continuation_proxy;
friend class internal::allocate_child_proxy; friend class internal::allocate_child_proxy;
friend class internal::allocate_additional_child_of_proxy; friend class internal::allocate_additional_child_of_proxy;
friend class internal::task_group_base;
//! Get reference to corresponding task_prefix. //! Get reference to corresponding task_prefix.
/** Version tag prevents loader on Linux from using the wrong symbol in debug builds. **/ /** Version tag prevents loader on Linux from using the wrong symbol in debug builds. **/
internal::task_prefix& prefix( internal::version_tag* = NULL ) const { internal::task_prefix& prefix( internal::version_tag* = NULL ) const {
return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(t his))[-1]; return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(t his))[-1];
} }
}; // class task }; // class task
//! task that does nothing. Useful for synchronization. //! task that does nothing. Useful for synchronization.
/** @ingroup task_scheduling */ /** @ingroup task_scheduling */
class empty_task: public task { class empty_task: public task {
skipping to change at line 745 skipping to change at line 759
}; };
//! A list of children. //! A list of children.
/** Used for method task::spawn_children /** Used for method task::spawn_children
@ingroup task_scheduling */ @ingroup task_scheduling */
class task_list: internal::no_copy { class task_list: internal::no_copy {
private: private:
task* first; task* first;
task** next_ptr; task** next_ptr;
friend class task; friend class task;
friend class interface5::internal::task_base;
public: public:
//! Construct empty list //! Construct empty list
task_list() : first(NULL), next_ptr(&first) {} task_list() : first(NULL), next_ptr(&first) {}
//! Destroys the list, but does not destroy the task objects. //! Destroys the list, but does not destroy the task objects.
~task_list() {} ~task_list() {}
//! True if list if empty; false otherwise. //! True if list if empty; false otherwise.
bool empty() const {return !first;} bool empty() const {return !first;}
skipping to change at line 778 skipping to change at line 793
return *result; return *result;
} }
//! Clear the list //! Clear the list
void clear() { void clear() {
first=NULL; first=NULL;
next_ptr=&first; next_ptr=&first;
} }
}; };
inline void task::spawn( task_list& list ) { #if TBB_DEPRECATED_TASK_INTERFACE
#if !__TBB_RELAXED_OWNERSHIP inline void task::spawn( task& t )
__TBB_ASSERT( is_owned_by_current_thread(), "'this' not owned by curren #else
t thread" ); inline void interface5::internal::task_base::spawn( task& t )
#endif /* !__TBB_RELAXED_OWNERSHIP */ #endif
{
t.prefix().owner->spawn( t, t.prefix().next );
}
#if TBB_DEPRECATED_TASK_INTERFACE
inline void task::spawn( task_list& list )
#else
inline void interface5::internal::task_base::spawn( task_list& list )
#endif
{
if( task* t = list.first ) { if( task* t = list.first ) {
prefix().owner->spawn( *t, *list.next_ptr ); t->prefix().owner->spawn( *t, *list.next_ptr );
list.clear(); list.clear();
} }
} }
inline void task::spawn_root_and_wait( task_list& root_list ) { inline void task::spawn_root_and_wait( task_list& root_list ) {
if( task* t = root_list.first ) { if( task* t = root_list.first ) {
#if !__TBB_RELAXED_OWNERSHIP
__TBB_ASSERT( t->is_owned_by_current_thread(), "'this' not owned by
current thread" );
#endif /* !__TBB_RELAXED_OWNERSHIP */
t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr ); t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr );
root_list.clear(); root_list.clear();
} }
} }
} // namespace tbb } // namespace tbb
inline void *operator new( size_t bytes, const tbb::internal::allocate_root _proxy& ) { inline void *operator new( size_t bytes, const tbb::internal::allocate_root _proxy& ) {
return &tbb::internal::allocate_root_proxy::allocate(bytes); return &tbb::internal::allocate_root_proxy::allocate(bytes);
} }
inline void operator delete( void* task, const tbb::internal::allocate_root _proxy& ) { inline void operator delete( void* task, const tbb::internal::allocate_root _proxy& ) {
tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task ) ); tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task ) );
} }
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
inline void *operator new( size_t bytes, const tbb::internal::allocate_root _with_context_proxy& p ) { inline void *operator new( size_t bytes, const tbb::internal::allocate_root _with_context_proxy& p ) {
return &p.allocate(bytes); return &p.allocate(bytes);
} }
inline void operator delete( void* task, const tbb::internal::allocate_root _with_context_proxy& p ) { inline void operator delete( void* task, const tbb::internal::allocate_root _with_context_proxy& p ) {
p.free( *static_cast<tbb::task*>(task) ); p.free( *static_cast<tbb::task*>(task) );
} }
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
inline void *operator new( size_t bytes, const tbb::internal::allocate_cont inuation_proxy& p ) { inline void *operator new( size_t bytes, const tbb::internal::allocate_cont inuation_proxy& p ) {
return &p.allocate(bytes); return &p.allocate(bytes);
} }
inline void operator delete( void* task, const tbb::internal::allocate_cont inuation_proxy& p ) { inline void operator delete( void* task, const tbb::internal::allocate_cont inuation_proxy& p ) {
p.free( *static_cast<tbb::task*>(task) ); p.free( *static_cast<tbb::task*>(task) );
} }
inline void *operator new( size_t bytes, const tbb::internal::allocate_chil d_proxy& p ) { inline void *operator new( size_t bytes, const tbb::internal::allocate_chil d_proxy& p ) {
 End of changes. 62 change blocks. 
120 lines changed or deleted 149 lines changed or added


 task_group.h   task_group.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 33 skipping to change at line 33
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_task_group_H #ifndef __TBB_task_group_H
#define __TBB_task_group_H #define __TBB_task_group_H
#include "task.h" #include "task.h"
#include "tbb_exception.h"
namespace tbb { namespace tbb {
namespace internal {
template<typename F> class task_handle_task;
}
template<typename F> template<typename F>
class task_handle { class task_handle : internal::no_assign {
template<typename _F> friend class internal::task_handle_task;
static const intptr_t scheduled = 0x1;
F my_func; F my_func;
intptr_t my_state;
void mark_scheduled () {
// The check here is intentionally lax to avoid the impact of inter
locked operation
if ( my_state & scheduled )
internal::throw_exception( internal::eid_invalid_multiple_sched
uling );
my_state |= scheduled;
}
public: public:
task_handle( const F& f ) : my_func(f) {} task_handle( const F& f ) : my_func(f), my_state(0) {}
void operator()() { my_func(); } void operator() () const { my_func(); }
}; };
enum task_group_status { enum task_group_status {
not_complete, not_complete,
complete, complete,
canceled canceled
}; };
namespace internal { namespace internal {
skipping to change at line 76 skipping to change at line 92
}; };
template<typename F> template<typename F>
class task_handle_task : public task { class task_handle_task : public task {
task_handle<F>& my_handle; task_handle<F>& my_handle;
/*override*/ task* execute() { /*override*/ task* execute() {
my_handle(); my_handle();
return NULL; return NULL;
} }
public: public:
task_handle_task( task_handle<F>& h ) : my_handle(h) {} task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled (); }
}; };
class task_group_base : internal::no_copy { class task_group_base : internal::no_copy {
protected: protected:
empty_task* my_root; empty_task* my_root;
task_group_context my_context; task_group_context my_context;
#if __TBB_RELAXED_OWNERSHIP
task& owner () { return *my_root; } task& owner () { return *my_root; }
#else
task& owner () { return task::self(); }
#endif
template<typename F> template<typename F>
task_group_status internal_run_and_wait( F& f ) { task_group_status internal_run_and_wait( F& f ) {
try { __TBB_TRY {
if ( !my_context.is_group_execution_cancelled() ) if ( !my_context.is_group_execution_cancelled() )
f(); f();
} catch ( ... ) { } __TBB_CATCH( ... ) {
my_context.register_pending_exception(); my_context.register_pending_exception();
} }
return wait(); return wait();
} }
template<typename F, typename Task> template<typename F, typename Task>
void internal_run( F& f ) { void internal_run( F& f ) {
owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) ); owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) );
} }
skipping to change at line 120 skipping to change at line 132
my_root = new( task::allocate_root(my_context) ) empty_task; my_root = new( task::allocate_root(my_context) ) empty_task;
my_root->set_ref_count(1); my_root->set_ref_count(1);
} }
template<typename F> template<typename F>
void run( task_handle<F>& h ) { void run( task_handle<F>& h ) {
internal_run< task_handle<F>, internal::task_handle_task<F> >( h ); internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
} }
task_group_status wait() { task_group_status wait() {
try { __TBB_TRY {
owner().prefix().owner->wait_for_all( *my_root, NULL ); my_root->wait_for_all();
} catch ( ... ) { } __TBB_CATCH( ... ) {
my_context.reset(); my_context.reset();
throw; __TBB_RETHROW();
} }
if ( my_context.is_group_execution_cancelled() ) { if ( my_context.is_group_execution_cancelled() ) {
my_context.reset(); my_context.reset();
return canceled; return canceled;
} }
return complete; return complete;
} }
bool is_canceling() { bool is_canceling() {
return my_context.is_group_execution_cancelled(); return my_context.is_group_execution_cancelled();
skipping to change at line 148 skipping to change at line 160
my_context.cancel_group_execution(); my_context.cancel_group_execution();
} }
}; // class task_group_base }; // class task_group_base
} // namespace internal } // namespace internal
class task_group : public internal::task_group_base { class task_group : public internal::task_group_base {
public: public:
task_group () : task_group_base( task_group_context::concurrent_wait ) {} task_group () : task_group_base( task_group_context::concurrent_wait ) {}
~task_group() try { ~task_group() __TBB_TRY {
__TBB_ASSERT( my_root->ref_count() != 0, NULL ); __TBB_ASSERT( my_root->ref_count() != 0, NULL );
if( my_root->ref_count() > 1 ) if( my_root->ref_count() > 1 )
my_root->wait_for_all(); my_root->wait_for_all();
owner().destroy(*my_root); owner().destroy(*my_root);
} }
#if TBB_USE_EXCEPTIONS
catch (...) { catch (...) {
owner().destroy(*my_root); owner().destroy(*my_root);
throw; throw;
} }
#endif /* TBB_USE_EXCEPTIONS */
#if __SUNPRO_CC #if __SUNPRO_CC
template<typename F> template<typename F>
void run( task_handle<F>& h ) { void run( task_handle<F>& h ) {
internal_run< task_handle<F>, internal::task_handle_task<F> >( h ); internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
} }
#else #else
using task_group_base::run; using task_group_base::run;
#endif #endif
skipping to change at line 179 skipping to change at line 193
void run( const F& f ) { void run( const F& f ) {
internal_run< const F, internal::function_task<F> >( f ); internal_run< const F, internal::function_task<F> >( f );
} }
template<typename F> template<typename F>
task_group_status run_and_wait( const F& f ) { task_group_status run_and_wait( const F& f ) {
return internal_run_and_wait<const F>( f ); return internal_run_and_wait<const F>( f );
} }
template<typename F> template<typename F>
task_group_status run_and_wait( F& f ) { task_group_status run_and_wait( task_handle<F>& h ) {
return internal_run_and_wait<F>( f ); return internal_run_and_wait< task_handle<F> >( h );
} }
}; // class task_group }; // class task_group
class missing_wait : public std::exception {
public:
/*override*/
const char* what() const throw() { return "wait() was not called on the
structured_task_group"; }
};
class structured_task_group : public internal::task_group_base { class structured_task_group : public internal::task_group_base {
public: public:
~structured_task_group() { ~structured_task_group() {
if( my_root->ref_count() > 1 ) { if( my_root->ref_count() > 1 ) {
bool stack_unwinding_in_progress = std::uncaught_exception(); bool stack_unwinding_in_progress = std::uncaught_exception();
// Always attempt to do proper cleanup to avoid inevitable memo ry corruption // Always attempt to do proper cleanup to avoid inevitable memo ry corruption
// in case of missing wait (for the sake of better testability & debuggability) // in case of missing wait (for the sake of better testability & debuggability)
if ( !is_canceling() ) if ( !is_canceling() )
cancel(); cancel();
my_root->wait_for_all(); my_root->wait_for_all();
owner().destroy(*my_root); owner().destroy(*my_root);
if ( !stack_unwinding_in_progress ) if ( !stack_unwinding_in_progress )
throw missing_wait(); internal::throw_exception( internal::eid_missing_wait );
} }
else else {
if( my_root->ref_count() == 1 )
my_root->set_ref_count(0);
owner().destroy(*my_root); owner().destroy(*my_root);
}
} }
template<typename F> template<typename F>
task_group_status run_and_wait ( task_handle<F>& h ) { task_group_status run_and_wait ( task_handle<F>& h ) {
return internal_run_and_wait< task_handle<F> >( h ); return internal_run_and_wait< task_handle<F> >( h );
} }
task_group_status wait() { task_group_status wait() {
__TBB_ASSERT ( my_root->ref_count() != 0, "wait() can be called onl task_group_status res = task_group_base::wait();
y once during the structured_task_group lifetime" ); my_root->set_ref_count(1);
return task_group_base::wait(); return res;
} }
}; // class structured_task_group }; // class structured_task_group
inline inline
bool is_current_task_group_canceling() { bool is_current_task_group_canceling() {
return task::self().is_cancelled(); return task::self().is_cancelled();
} }
template<class F>
task_handle<F> make_task( const F& f ) {
return task_handle<F>( f );
}
} // namespace tbb } // namespace tbb
#endif /* __TBB_task_group_H */ #endif /* __TBB_task_group_H */
 End of changes. 26 change blocks. 
31 lines changed or deleted 47 lines changed or added


 task_scheduler_init.h   task_scheduler_init.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 task_scheduler_observer.h   task_scheduler_observer.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 45 skipping to change at line 45
namespace tbb { namespace tbb {
namespace internal { namespace internal {
class observer_proxy; class observer_proxy;
class task_scheduler_observer_v3 { class task_scheduler_observer_v3 {
friend class observer_proxy; friend class observer_proxy;
observer_proxy* my_proxy; observer_proxy* my_proxy;
atomic<intptr> my_busy_count; atomic<intptr_t> my_busy_count;
public: public:
//! Enable or disable observation //! Enable or disable observation
void __TBB_EXPORTED_METHOD observe( bool state=true ); void __TBB_EXPORTED_METHOD observe( bool state=true );
//! True if observation is enables; false otherwise. //! True if observation is enables; false otherwise.
bool is_observing() const {return my_proxy!=NULL;} bool is_observing() const {return my_proxy!=NULL;}
//! Construct observer with observation disabled. //! Construct observer with observation disabled.
task_scheduler_observer_v3() : my_proxy(NULL) {my_busy_count=0;} task_scheduler_observer_v3() : my_proxy(NULL) {my_busy_count=0;}
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 tbb.h   tbb.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 46 skipping to change at line 46
If you use only a few TBB constructs, consider including specific heade rs only. If you use only a few TBB constructs, consider including specific heade rs only.
Any header listed below can be included independently of others. Any header listed below can be included independently of others.
**/ **/
#include "aligned_space.h" #include "aligned_space.h"
#include "atomic.h" #include "atomic.h"
#include "blocked_range.h" #include "blocked_range.h"
#include "blocked_range2d.h" #include "blocked_range2d.h"
#include "blocked_range3d.h" #include "blocked_range3d.h"
#include "cache_aligned_allocator.h" #include "cache_aligned_allocator.h"
#include "combinable.h"
#include "concurrent_unordered_map.h"
#include "concurrent_hash_map.h" #include "concurrent_hash_map.h"
#include "concurrent_queue.h" #include "concurrent_queue.h"
#include "concurrent_vector.h" #include "concurrent_vector.h"
#include "critical_section.h"
#include "enumerable_thread_specific.h" #include "enumerable_thread_specific.h"
#include "mutex.h" #include "mutex.h"
#include "null_mutex.h" #include "null_mutex.h"
#include "null_rw_mutex.h" #include "null_rw_mutex.h"
#include "parallel_do.h" #include "parallel_do.h"
#include "parallel_for.h" #include "parallel_for.h"
#include "parallel_for_each.h" #include "parallel_for_each.h"
#include "parallel_invoke.h" #include "parallel_invoke.h"
#include "parallel_reduce.h" #include "parallel_reduce.h"
#include "parallel_scan.h" #include "parallel_scan.h"
#include "parallel_sort.h" #include "parallel_sort.h"
#include "partitioner.h" #include "partitioner.h"
#include "pipeline.h" #include "pipeline.h"
#include "queuing_mutex.h" #include "queuing_mutex.h"
#include "queuing_rw_mutex.h" #include "queuing_rw_mutex.h"
#include "reader_writer_lock.h"
#include "recursive_mutex.h" #include "recursive_mutex.h"
#include "spin_mutex.h" #include "spin_mutex.h"
#include "spin_rw_mutex.h" #include "spin_rw_mutex.h"
#include "task.h" #include "task.h"
#include "task_group.h" #include "task_group.h"
#include "task_scheduler_init.h" #include "task_scheduler_init.h"
#include "task_scheduler_observer.h" #include "task_scheduler_observer.h"
#include "tbb_allocator.h" #include "tbb_allocator.h"
#include "tbb_exception.h" #include "tbb_exception.h"
#include "tbb_thread.h" #include "tbb_thread.h"
 End of changes. 4 change blocks. 
1 lines changed or deleted 5 lines changed or added


 tbb_allocator.h   tbb_allocator.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 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_tbb_allocator_H #ifndef __TBB_tbb_allocator_H
#define __TBB_tbb_allocator_H #define __TBB_tbb_allocator_H
#include "tbb_stddef.h"
#include <new> #include <new>
#if !TBB_USE_EXCEPTIONS && _MSC_VER
// Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers
#pragma warning (push)
#pragma warning (disable: 4530)
#endif
#include <cstring> #include <cstring>
#include "tbb_stddef.h"
#if !TBB_USE_EXCEPTIONS && _MSC_VER
#pragma warning (pop)
#endif
namespace tbb { namespace tbb {
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
//! Deallocates memory using FreeHandler //! Deallocates memory using FreeHandler
/** The function uses scalable_free if scalable allocator is available and free if not*/ /** The function uses scalable_free if scalable allocator is available and free if not*/
void __TBB_EXPORTED_FUNC deallocate_via_handler_v3( void *p ); void __TBB_EXPORTED_FUNC deallocate_via_handler_v3( void *p );
skipping to change at line 110 skipping to change at line 121
internal::deallocate_via_handler_v3(p); internal::deallocate_via_handler_v3(p);
} }
//! Largest value for which method allocate might succeed. //! Largest value for which method allocate might succeed.
size_type max_size() const throw() { size_type max_size() const throw() {
size_type max = static_cast<size_type>(-1) / sizeof (value_type); size_type max = static_cast<size_type>(-1) / sizeof (value_type);
return (max > 0 ? max : 1); return (max > 0 ? max : 1);
} }
//! Copy-construct value at location pointed to by p. //! Copy-construct value at location pointed to by p.
void construct( pointer p, const value_type& value ) {new(static_cast<v oid*>(p)) value_type(value);} void construct( pointer p, const value_type& value ) {::new((void*)(p)) value_type(value);}
//! Destroy value at location pointed to by p. //! Destroy value at location pointed to by p.
void destroy( pointer p ) {p->~value_type();} void destroy( pointer p ) {p->~value_type();}
//! Returns current allocator //! Returns current allocator
static malloc_type allocator_type() { static malloc_type allocator_type() {
return internal::is_malloc_used_v3() ? standard : scalable; return internal::is_malloc_used_v3() ? standard : scalable;
} }
}; };
 End of changes. 5 change blocks. 
3 lines changed or deleted 15 lines changed or added


 tbb_config.h   tbb_config.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 75 skipping to change at line 75
#endif /* TBB_USE_THREADING_TOOLS */ #endif /* TBB_USE_THREADING_TOOLS */
#ifndef TBB_USE_PERFORMANCE_WARNINGS #ifndef TBB_USE_PERFORMANCE_WARNINGS
#ifdef TBB_PERFORMANCE_WARNINGS #ifdef TBB_PERFORMANCE_WARNINGS
#define TBB_USE_PERFORMANCE_WARNINGS TBB_PERFORMANCE_WARNINGS #define TBB_USE_PERFORMANCE_WARNINGS TBB_PERFORMANCE_WARNINGS
#else #else
#define TBB_USE_PERFORMANCE_WARNINGS TBB_USE_DEBUG #define TBB_USE_PERFORMANCE_WARNINGS TBB_USE_DEBUG
#endif /* TBB_PEFORMANCE_WARNINGS */ #endif /* TBB_PEFORMANCE_WARNINGS */
#endif /* TBB_USE_PERFORMANCE_WARNINGS */ #endif /* TBB_USE_PERFORMANCE_WARNINGS */
#if !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) && !defined(__SUNPRO_CC)
|| defined(_XBOX)
#if TBB_USE_EXCEPTIONS
#error Compilation settings do not support exception handling. Plea
se do not set TBB_USE_EXCEPTIONS macro or set it to 0.
#elif !defined(TBB_USE_EXCEPTIONS)
#define TBB_USE_EXCEPTIONS 0
#endif
#elif !defined(TBB_USE_EXCEPTIONS)
#define TBB_USE_EXCEPTIONS 1
#endif
#ifndef TBB_IMPLEMENT_CPP0X
/** By default, use C++0x classes if available **/
#if __GNUC__==4 && __GNUC_MINOR__>=4 && __GXX_EXPERIMENTAL_CXX0X__
#define TBB_IMPLEMENT_CPP0X 0
#else
#define TBB_IMPLEMENT_CPP0X 1
#endif
#endif /* TBB_IMPLEMENT_CPP0X */
/** Feature sets **/ /** Feature sets **/
#ifndef __TBB_EXCEPTIONS #ifndef __TBB_COUNT_TASK_NODES
#define __TBB_EXCEPTIONS 1 #define __TBB_COUNT_TASK_NODES TBB_USE_ASSERT
#endif /* __TBB_EXCEPTIONS */ #endif
#ifndef __TBB_TASK_GROUP_CONTEXT
#define __TBB_TASK_GROUP_CONTEXT 1
#endif /* __TBB_TASK_GROUP_CONTEXT */
#ifndef __TBB_SCHEDULER_OBSERVER #ifndef __TBB_SCHEDULER_OBSERVER
#define __TBB_SCHEDULER_OBSERVER 1 #define __TBB_SCHEDULER_OBSERVER 1
#endif /* __TBB_SCHEDULER_OBSERVER */ #endif /* __TBB_SCHEDULER_OBSERVER */
#ifndef __TBB_TASK_SCHEDULER_AUTO_INIT #ifndef __TBB_ARENA_PER_MASTER
#define __TBB_TASK_SCHEDULER_AUTO_INIT 1 #define __TBB_ARENA_PER_MASTER 1
#endif /* __TBB_TASK_SCHEDULER_AUTO_INIT */ #endif /* __TBB_ARENA_PER_MASTER */
#ifndef __TBB_TASK_DEQUE
#define __TBB_TASK_DEQUE 1
#endif /* !__TBB_TASK_DEQUE */
#if __TBB_TASK_DEQUE
#ifndef __TBB_RELAXED_OWNERSHIP
#define __TBB_RELAXED_OWNERSHIP 1
#endif /* !__TBB_RELAXED_OWNERSHIP */
#else
#ifdef __TBB_RELAXED_OWNERSHIP
#undef __TBB_RELAXED_OWNERSHIP
#endif /* __TBB_RELAXED_OWNERSHIP */
#endif /* !__TBB_TASK_DEQUE */
#ifndef __TBB_NEW_ITT_NOTIFY
#define __TBB_NEW_ITT_NOTIFY 1
#endif /* !__TBB_NEW_ITT_NOTIFY */
#ifndef __TBB_PROVIDE_VIRTUAL_SCHEDULER
#define __TBB_PROVIDE_VIRTUAL_SCHEDULER 0
#endif /* !__TBB_PROVIDE_VIRTUAL_SCHEDULER */
#if !__TBB_PROVIDE_VIRTUAL_SCHEDULER
#ifdef DO_ITT_ANNOTATE
#undef DO_ITT_ANNOTATE
#endif
#endif /* !__TBB_PROVIDE_VIRTUAL_SCHEDULER */
/* TODO: The following condition should be extended as soon as new compiler s/runtimes /* TODO: The following condition should be extended as soon as new compiler s/runtimes
with std::exception_ptr support appear. */ with std::exception_ptr support appear. */
#define __TBB_EXCEPTION_PTR_PRESENT ( _MSC_VER >= 1600 ) #define __TBB_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1600 || __GXX_EXPERIMENTA L_CXX0X__ && (__GNUC__==4 && __GNUC_MINOR__>=4))
#ifndef TBB_USE_CAPTURED_EXCEPTION #ifndef TBB_USE_CAPTURED_EXCEPTION
#if __TBB_EXCEPTION_PTR_PRESENT #if __TBB_EXCEPTION_PTR_PRESENT
#define TBB_USE_CAPTURED_EXCEPTION 0 #define TBB_USE_CAPTURED_EXCEPTION 0
#else #else
#define TBB_USE_CAPTURED_EXCEPTION 1 #define TBB_USE_CAPTURED_EXCEPTION 1
#endif #endif
#else /* defined TBB_USE_CAPTURED_EXCEPTION */ #else /* defined TBB_USE_CAPTURED_EXCEPTION */
#if !TBB_USE_CAPTURED_EXCEPTION && !__TBB_EXCEPTION_PTR_PRESENT #if !TBB_USE_CAPTURED_EXCEPTION && !__TBB_EXCEPTION_PTR_PRESENT
#error Current runtime does not support std::exception_ptr. Set TBB _USE_CAPTURED_EXCEPTION and make sure that your code is ready to catch tbb: :captured_exception. #error Current runtime does not support std::exception_ptr. Set TBB _USE_CAPTURED_EXCEPTION and make sure that your code is ready to catch tbb: :captured_exception.
skipping to change at line 145 skipping to change at line 140
/** 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
/** Default partitioner for parallel loop templates in TBB 2.2 */ /** Default partitioner for parallel loop templates in TBB 2.2 */
#define __TBB_DEFAULT_PARTITIONER tbb::auto_partitioner #define __TBB_DEFAULT_PARTITIONER tbb::auto_partitioner
#endif /* TBB_DEFAULT_PARTITIONER */ #endif /* TBB_DEFAULT_PARTITIONER */
#endif /* !defined(__TBB_DEFAULT_PARTITIONER */ #endif /* !defined(__TBB_DEFAULT_PARTITIONER */
/** Workarounds presence **/ /** Workarounds presence **/
#if __GNUC__==4 && __GNUC_MINOR__==4 #if __GNUC__==4 && __GNUC_MINOR__>=4 && !defined(__INTEL_COMPILER)
#define __TBB_GCC_WARNING_SUPPRESSION_ENABLED 1 #define __TBB_GCC_WARNING_SUPPRESSION_ENABLED 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 defined(_MSC_VER) && _MSC_VER < 0x1500 && !defined(__INTEL_COMPILER) #if _MSC_VER && __INTEL_COMPILER && (__INTEL_COMPILER<1110 || __INTEL_COMPI
/** VS2005 and earlier does not allow to declare a template class as a LER==1110 && __INTEL_COMPILER_BUILD_DATE < 20091012)
friend /** Necessary to avoid ICL error (or warning in non-strict mode):
"exception specification for implicitly declared virtual destructor
is
incompatible with that of overridden one". **/
#define __TBB_DEFAULT_DTOR_THROW_SPEC_BROKEN 1
#endif
#if defined(_MSC_VER) && _MSC_VER < 1500 && !defined(__INTEL_COMPILER)
/** VS2005 and earlier do not allow declaring template class as a frien
d
of classes defined in other namespaces. **/ of classes defined in other namespaces. **/
#define __TBB_TEMPLATE_FRIENDS_BROKEN 1 #define __TBB_TEMPLATE_FRIENDS_BROKEN 1
#endif #endif
#if __GLIBC__==2 && __GLIBC_MINOR__==3 || __MINGW32__ #if __GLIBC__==2 && __GLIBC_MINOR__==3 || __MINGW32__
//! Macro controlling EH usages in TBB tests
/** Some older versions of glibc crash when exception handling happens concurrently. **/ /** Some older versions of glibc crash when exception handling happens concurrently. **/
#define __TBB_EXCEPTION_HANDLING_BROKEN 1 #define __TBB_THROW_ACROSS_MODULE_BOUNDARY_BROKEN 1
#endif
#if (_WIN32||_WIN64) && __INTEL_COMPILER == 1110
/** That's a bug in Intel compiler 11.1.044/IA-32/Windows, that leads t
o a worker thread crash on the thread's startup. **/
#define __TBB_ICL_11_1_CODE_GEN_BROKEN 1
#endif #endif
#if __FreeBSD__ #if __FreeBSD__
/** The bug in FreeBSD 8.0 results in kernel panic when there is conten tion /** A bug in FreeBSD 8.0 results in kernel panic when there is contenti on
on a mutex created with this attribute. **/ on a mutex created with this attribute. **/
#define __TBB_PRIO_INHERIT_BROKEN 1 #define __TBB_PRIO_INHERIT_BROKEN 1
/** A bug in FreeBSD 8.0 results in test hanging when an exception occu rs /** A bug in FreeBSD 8.0 results in test hanging when an exception occu rs
during (concurrent?) object construction by means of placement new operator. **/ during (concurrent?) object construction by means of placement new operator. **/
#define __TBB_PLACEMENT_NEW_EXCEPTION_SAFETY_BROKEN 1 #define __TBB_PLACEMENT_NEW_EXCEPTION_SAFETY_BROKEN 1
#endif /* __FreeBSD__ */ #endif /* __FreeBSD__ */
#if (__linux__ || __APPLE__) && __i386__ && defined(__INTEL_COMPILER)
/** The Intel compiler for IA-32 (Linux|Mac OS X) crashes or generates
incorrect code when __asm__ arguments have a cast to volatile. **/
#define __TBB_ICC_ASM_VOLATILE_BROKEN 1
#endif
#if __LRB__ #if __LRB__
#include "tbb_config_lrb.h" #include "tbb_config_lrb.h"
#endif #endif
#endif /* __TBB_tbb_config_H */ #endif /* __TBB_tbb_config_H */
 End of changes. 11 change blocks. 
42 lines changed or deleted 61 lines changed or added


 tbb_exception.h   tbb_exception.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 33 skipping to change at line 33
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_exception_H #ifndef __TBB_exception_H
#define __TBB_exception_H #define __TBB_exception_H
#include "tbb_stddef.h" #include "tbb_stddef.h"
#if !TBB_USE_EXCEPTIONS && _MSC_VER
// Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers
#pragma warning (push)
#pragma warning (disable: 4530)
#endif
#include <stdexcept> #include <stdexcept>
#if __TBB_EXCEPTIONS && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) && ! #if !TBB_USE_EXCEPTIONS && _MSC_VER
defined(__SUNPRO_CC) #pragma warning (pop)
#error The current compilation environment does not support exception handl #endif
ing. Please set __TBB_EXCEPTIONS to 0 in tbb_config.h
#if __SUNPRO_CC
#include <string> // required to construct std exception classes
#endif #endif
namespace tbb { namespace tbb {
//! Exception for concurrent containers //! Exception for concurrent containers
class bad_last_alloc : public std::bad_alloc { class bad_last_alloc : public std::bad_alloc {
public: public:
virtual const char* what() const throw() { return "bad allocation in pr /*override*/ const char* what() const throw();
evious or concurrent attempt"; } #if __TBB_DEFAULT_DTOR_THROW_SPEC_BROKEN
virtual ~bad_last_alloc() throw() {} /*override*/ ~bad_last_alloc() throw() {}
#endif
};
//! Exception for PPL locks
class improper_lock : public std::exception {
public:
/*override*/ const char* what() const throw();
};
//! Exception for missing wait on structured_task_group
class missing_wait : public std::exception {
public:
/*override*/ const char* what() const throw();
};
//! Exception for repeated scheduling of the same task_handle
class invalid_multiple_scheduling : public std::exception {
public:
/*override*/ const char* what() const throw();
}; };
namespace internal { namespace internal {
void __TBB_EXPORTED_FUNC throw_bad_last_alloc_exception_v4() ; //! Obsolete
} // namespace internal void __TBB_EXPORTED_FUNC throw_bad_last_alloc_exception_v4();
enum exception_id {
eid_bad_alloc = 1,
eid_bad_last_alloc,
eid_nonpositive_step,
eid_out_of_range,
eid_segment_range_error,
eid_index_range_error,
eid_missing_wait,
eid_invalid_multiple_scheduling,
eid_improper_lock,
eid_possible_deadlock,
eid_operation_not_permitted,
eid_condvar_wait_failed,
eid_invalid_load_factor,
eid_invalid_buckets_number,
eid_invalid_swap,
eid_reservation_length_error,
eid_invalid_key,
//! The last enumerator tracks the number of defined IDs. It must remai
n the last one.
/** When adding new IDs, place them immediately _before_ this comment (
that is
_after_ all the existing IDs. NEVER insert new IDs between the exis
ting ones. **/
eid_max
};
//! Gathers all throw operators in one place.
/** Its purpose is to minimize code bloat that can be caused by throw opera
tors
scattered in multiple places, especially in templates. **/
void __TBB_EXPORTED_FUNC throw_exception_v4 ( exception_id );
//! Versionless convenience wrapper for throw_exception_v4()
inline void throw_exception ( exception_id eid ) { throw_exception_v4(eid);
}
} // namespace internal
} // namespace tbb } // namespace tbb
#if __TBB_EXCEPTIONS #if __TBB_TASK_GROUP_CONTEXT
#include "tbb_allocator.h" #include "tbb_allocator.h"
#include <exception> #include <exception>
#include <typeinfo> #include <typeinfo>
#include <new> #include <new>
namespace tbb { namespace tbb {
//! Interface to be implemented by all exceptions TBB recognizes and propag ates across the threads. //! Interface to be implemented by all exceptions TBB recognizes and propag ates across the threads.
/** If an unhandled exception of the type derived from tbb::tbb_exception i s intercepted /** If an unhandled exception of the type derived from tbb::tbb_exception i s intercepted
by the TBB scheduler in one of the worker threads, it is delivered to a nd re-thrown in by the TBB scheduler in one of the worker threads, it is delivered to a nd re-thrown in
skipping to change at line 83 skipping to change at line 147
NOTE: In case of nested algorithms or complex task hierarchies when the nested NOTE: In case of nested algorithms or complex task hierarchies when the nested
levels share (explicitly or by means of implicit inheritance) the task group levels share (explicitly or by means of implicit inheritance) the task group
context of the outermost level, the exception may be (re-)thrown multip le times context of the outermost level, the exception may be (re-)thrown multip le times
(ultimately - in each worker on each nesting level) before reaching the root (ultimately - in each worker on each nesting level) before reaching the root
thread at the outermost level. IMPORTANT: if you intercept an exception derived thread at the outermost level. IMPORTANT: if you intercept an exception derived
from this class on a nested level, you must re-throw it in the catch bl ock by means from this class on a nested level, you must re-throw it in the catch bl ock by means
of the "throw;" operator. of the "throw;" operator.
TBB provides two implementations of this interface: tbb::captured_excep tion and TBB provides two implementations of this interface: tbb::captured_excep tion and
template class tbb::movable_exception. See their declarations for more info. **/ template class tbb::movable_exception. See their declarations for more info. **/
class tbb_exception : public std::exception { class tbb_exception : public std::exception
{
/** No operator new is provided because the TBB usage model assumes dyn
amic
creation of the TBB exception objects only by means of applying mov
e()
operation on an exception thrown out of TBB scheduler. **/
void* operator new ( size_t );
public: public:
//! Creates and returns pointer to the deep copy of this exception obje ct. //! Creates and returns pointer to the deep copy of this exception obje ct.
/** Move semantics is allowed. **/ /** Move semantics is allowed. **/
virtual tbb_exception* move () throw() = 0; virtual tbb_exception* move () throw() = 0;
//! Destroys objects created by the move() method. //! Destroys objects created by the move() method.
/** Frees memory and calls destructor for this exception object. /** Frees memory and calls destructor for this exception object.
Can and must be used only on objects created by the move method. ** / Can and must be used only on objects created by the move method. ** /
virtual void destroy () throw() = 0; virtual void destroy () throw() = 0;
skipping to change at line 106 skipping to change at line 176
you implement or override this method on the most derived level. Th e implementation you implement or override this method on the most derived level. Th e implementation
is as simple as "throw *this;". Failure to do this will result in e xception is as simple as "throw *this;". Failure to do this will result in e xception
of a base class type being thrown. **/ of a base class type being thrown. **/
virtual void throw_self () = 0; virtual void throw_self () = 0;
//! Returns RTTI name of the originally intercepted exception //! Returns RTTI name of the originally intercepted exception
virtual const char* name() const throw() = 0; virtual const char* name() const throw() = 0;
//! Returns the result of originally intercepted exception's what() met hod. //! Returns the result of originally intercepted exception's what() met hod.
virtual const char* what() const throw() = 0; virtual const char* what() const throw() = 0;
/** Operator delete is provided only to allow using existing smart poin
ters
with TBB exception objects obtained as the result of applying move(
)
operation on an exception thrown out of TBB scheduler.
When overriding method move() make sure to override operator delete
as well
if memory is allocated not by TBB's scalable allocator. **/
void operator delete ( void* p ) {
internal::deallocate_via_handler_v3(p);
}
}; };
//! This class is used by TBB to propagate information about unhandled exce ptions into the root thread. //! This class is used by TBB to propagate information about unhandled exce ptions into the root thread.
/** Exception of this type is thrown by TBB in the root thread (thread that started a parallel /** Exception of this type is thrown by TBB in the root thread (thread that started a parallel
algorithm ) if an unhandled exception was intercepted during the algori thm execution in one algorithm ) if an unhandled exception was intercepted during the algori thm execution in one
of the workers. of the workers.
\sa tbb::tbb_exception **/ \sa tbb::tbb_exception **/
class captured_exception : public tbb_exception class captured_exception : public tbb_exception
{ {
public: public:
captured_exception ( const captured_exception& src ) captured_exception ( const captured_exception& src )
: tbb_exception(src), my_dynamic(false) : tbb_exception(src), my_dynamic(false)
{ {
set(src.my_exception_name, src.my_exception_info); set(src.my_exception_name, src.my_exception_info);
} }
captured_exception ( const char* name, const char* info ) captured_exception ( const char* name_, const char* info )
: my_dynamic(false) : my_dynamic(false)
{ {
set(name, info); set(name_, info);
} }
__TBB_EXPORTED_METHOD ~captured_exception () throw() { __TBB_EXPORTED_METHOD ~captured_exception () throw() {
clear(); clear();
} }
captured_exception& operator= ( const captured_exception& src ) { captured_exception& operator= ( const captured_exception& src ) {
if ( this != &src ) { if ( this != &src ) {
clear(); clear();
set(src.my_exception_name, src.my_exception_info); set(src.my_exception_name, src.my_exception_info);
} }
return *this; return *this;
} }
/*override*/ /*override*/
captured_exception* move () throw(); captured_exception* __TBB_EXPORTED_METHOD move () throw();
/*override*/ /*override*/
void destroy () throw(); void __TBB_EXPORTED_METHOD destroy () throw();
/*override*/ /*override*/
void throw_self () { throw *this; } void throw_self () { __TBB_THROW(*this); }
/*override*/ /*override*/
const char* __TBB_EXPORTED_METHOD name() const throw(); const char* __TBB_EXPORTED_METHOD name() const throw();
/*override*/ /*override*/
const char* __TBB_EXPORTED_METHOD what() const throw(); const char* __TBB_EXPORTED_METHOD what() const throw();
void __TBB_EXPORTED_METHOD set ( const char* name, const char* info ) t
hrow();
void __TBB_EXPORTED_METHOD clear () throw();
private: private:
//! Used only by method clone(). //! Used only by method clone().
captured_exception() {} captured_exception() {}
//! Functionally equivalent to {captured_exception e(name,info); return c.clone();} //! Functionally equivalent to {captured_exception e(name,info); return e.clone();}
static captured_exception* allocate ( const char* name, const char* inf o ); static captured_exception* allocate ( const char* name, const char* inf o );
void set ( const char* name, const char* info ) throw();
void clear () throw();
bool my_dynamic; bool my_dynamic;
const char* my_exception_name; const char* my_exception_name;
const char* my_exception_info; const char* my_exception_info;
}; };
//! Template that can be used to implement exception that transfers arbitra ry ExceptionData to the root thread //! Template that can be used to implement exception that transfers arbitra ry ExceptionData to the root thread
/** Code using TBB can instantiate this template with an arbitrary Exceptio nData type /** Code using TBB can instantiate this template with an arbitrary Exceptio nData type
and throw this exception object. Such exceptions are intercepted by the TBB scheduler and throw this exception object. Such exceptions are intercepted by the TBB scheduler
and delivered to the root thread (). and delivered to the root thread ().
\sa tbb::tbb_exception **/ \sa tbb::tbb_exception **/
template<typename ExceptionData> template<typename ExceptionData>
class movable_exception : public tbb_exception class movable_exception : public tbb_exception
{ {
typedef movable_exception<ExceptionData> self_type; typedef movable_exception<ExceptionData> self_type;
public: public:
movable_exception ( const ExceptionData& data ) movable_exception ( const ExceptionData& data_ )
: my_exception_data(data) : my_exception_data(data_)
, my_dynamic(false) , my_dynamic(false)
, my_exception_name(typeid(self_type).name()) , my_exception_name(
#if TBB_USE_EXCEPTIONS
typeid(self_type).name()
#else /* !TBB_USE_EXCEPTIONS */
"movable_exception"
#endif /* !TBB_USE_EXCEPTIONS */
)
{} {}
movable_exception ( const movable_exception& src ) throw () movable_exception ( const movable_exception& src ) throw ()
: tbb_exception(src) : tbb_exception(src)
, my_exception_data(src.my_exception_data) , my_exception_data(src.my_exception_data)
, my_dynamic(false) , my_dynamic(false)
, my_exception_name(src.my_exception_name) , my_exception_name(src.my_exception_name)
{} {}
~movable_exception () throw() {} ~movable_exception () throw() {}
skipping to change at line 216 skipping to change at line 302
const ExceptionData& data () const throw() { return my_exception_data; } const ExceptionData& data () const throw() { return my_exception_data; }
/*override*/ const char* name () const throw() { return my_exception_na me; } /*override*/ const char* name () const throw() { return my_exception_na me; }
/*override*/ const char* what () const throw() { return "tbb::movable_e xception"; } /*override*/ const char* what () const throw() { return "tbb::movable_e xception"; }
/*override*/ /*override*/
movable_exception* move () throw() { movable_exception* move () throw() {
void* e = internal::allocate_via_handler_v3(sizeof(movable_exceptio n)); void* e = internal::allocate_via_handler_v3(sizeof(movable_exceptio n));
if ( e ) { if ( e ) {
new (e) movable_exception(*this); ::new (e) movable_exception(*this);
((movable_exception*)e)->my_dynamic = true; ((movable_exception*)e)->my_dynamic = true;
} }
return (movable_exception*)e; return (movable_exception*)e;
} }
/*override*/ /*override*/
void destroy () throw() { void destroy () throw() {
__TBB_ASSERT ( my_dynamic, "Method destroy can be called only on dy namically allocated movable_exceptions" ); __TBB_ASSERT ( my_dynamic, "Method destroy can be called only on dy namically allocated movable_exceptions" );
if ( my_dynamic ) { if ( my_dynamic ) {
this->~movable_exception(); this->~movable_exception();
internal::deallocate_via_handler_v3(this); internal::deallocate_via_handler_v3(this);
} }
} }
/*override*/ /*override*/
void throw_self () { void throw_self () { __TBB_THROW( *this ); }
throw *this;
}
protected: protected:
//! User data //! User data
ExceptionData my_exception_data; ExceptionData my_exception_data;
private: private:
//! Flag specifying whether this object has been dynamically allocated (by the move method) //! Flag specifying whether this object has been dynamically allocated (by the move method)
bool my_dynamic; bool my_dynamic;
//! RTTI name of this class //! RTTI name of this class
skipping to change at line 258 skipping to change at line 342
namespace internal { namespace internal {
//! Exception container that preserves the exact copy of the original excep tion //! Exception container that preserves the exact copy of the original excep tion
/** This class can be used only when the appropriate runtime support (manda ted /** This class can be used only when the appropriate runtime support (manda ted
by C++0x) is present **/ by C++0x) is present **/
class tbb_exception_ptr { class tbb_exception_ptr {
std::exception_ptr my_ptr; std::exception_ptr my_ptr;
public: public:
static tbb_exception_ptr* allocate (); static tbb_exception_ptr* allocate ();
static tbb_exception_ptr* allocate ( const tbb_exception& ); static tbb_exception_ptr* allocate ( const tbb_exception& tag );
static tbb_exception_ptr* allocate ( const captured_exception& ); //! This overload uses move semantics (i.e. it empties src)
static tbb_exception_ptr* allocate ( captured_exception& src );
//! Destroys this objects //! Destroys this objects
/** Note that objects of this type can be created only by the allocate( ) method. **/ /** Note that objects of this type can be created only by the allocate( ) method. **/
void destroy () throw(); void destroy () throw();
//! Throws the contained exception . //! Throws the contained exception .
void throw_self () { std::rethrow_exception(my_ptr); } void throw_self () { std::rethrow_exception(my_ptr); }
private: private:
tbb_exception_ptr ( const std::exception_ptr& src ) : my_ptr(src) {} tbb_exception_ptr ( const std::exception_ptr& src ) : my_ptr(src) {}
tbb_exception_ptr ( const captured_exception& src ) : my_ptr(std::copy_ exception(src)) {} tbb_exception_ptr ( const captured_exception& src ) : my_ptr(std::copy_ exception(src)) {}
}; // class tbb::internal::tbb_exception_ptr }; // class tbb::internal::tbb_exception_ptr
} // namespace internal } // namespace internal
#endif /* !TBB_USE_CAPTURED_EXCEPTION */ #endif /* !TBB_USE_CAPTURED_EXCEPTION */
} // namespace tbb } // namespace tbb
#endif /* __TBB_EXCEPTIONS */ #endif /* __TBB_TASK_GROUP_CONTEXT */
#endif /* __TBB_exception_H */ #endif /* __TBB_exception_H */
 End of changes. 23 change blocks. 
31 lines changed or deleted 125 lines changed or added


 tbb_machine.h   tbb_machine.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 48 skipping to change at line 48
#endif #endif
#if __MINGW32__ #if __MINGW32__
#include "machine/linux_ia32.h" #include "machine/linux_ia32.h"
extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void );
#define __TBB_Yield() SwitchToThread() #define __TBB_Yield() SwitchToThread()
#elif defined(_M_IX86) #elif defined(_M_IX86)
#include "machine/windows_ia32.h" #include "machine/windows_ia32.h"
#elif defined(_M_AMD64) #elif defined(_M_AMD64)
#include "machine/windows_intel64.h" #include "machine/windows_intel64.h"
#elif _XBOX
#include "machine/xbox360_ppc.h"
#else #else
#error Unsupported platform #error Unsupported platform
#endif #endif
#ifdef _MANAGED #ifdef _MANAGED
#pragma managed(pop) #pragma managed(pop)
#endif #endif
#elif __linux__ || __FreeBSD__ #elif __linux__ || __FreeBSD__
skipping to change at line 88 skipping to change at line 90
#include "machine/ibm_aix51.h" #include "machine/ibm_aix51.h"
#elif __sun || __SUNPRO_CC #elif __sun || __SUNPRO_CC
#define __asm__ asm #define __asm__ asm
#define __volatile__ volatile #define __volatile__ volatile
#if __i386 || __i386__ #if __i386 || __i386__
#include "machine/linux_ia32.h" #include "machine/linux_ia32.h"
#elif __x86_64__ #elif __x86_64__
#include "machine/linux_intel64.h" #include "machine/linux_intel64.h"
#elif __sparc
#include "machine/sunos_sparc.h"
#endif #endif
#endif #endif
#if !defined(__TBB_CompareAndSwap4) \ #if !defined(__TBB_CompareAndSwap4) \
|| !defined(__TBB_CompareAndSwap8) \ || !defined(__TBB_CompareAndSwap8) \
|| !defined(__TBB_Yield) \ || !defined(__TBB_Yield) \
|| !defined(__TBB_release_consistency_helper) || !defined(__TBB_release_consistency_helper)
#error Minimal requirements for tbb_machine.h not satisfied #error Minimal requirements for tbb_machine.h not satisfied
#endif #endif
skipping to change at line 320 skipping to change at line 324
#endif #endif
}; };
#define __TBB_TypeWithAlignmentAtLeastAsStrict(T) tbb::internal::type_with_ alignment<tbb::internal::work_around_alignment_bug<sizeof(T),T>::alignment> #define __TBB_TypeWithAlignmentAtLeastAsStrict(T) tbb::internal::type_with_ alignment<tbb::internal::work_around_alignment_bug<sizeof(T),T>::alignment>
#elif __GNUC__ || __SUNPRO_CC #elif __GNUC__ || __SUNPRO_CC
#define __TBB_TypeWithAlignmentAtLeastAsStrict(T) tbb::internal::type_with_ alignment<__alignof__(T)> #define __TBB_TypeWithAlignmentAtLeastAsStrict(T) tbb::internal::type_with_ alignment<__alignof__(T)>
#else #else
#define __TBB_TypeWithAlignmentAtLeastAsStrict(T) __TBB_machine_type_with_s trictest_alignment #define __TBB_TypeWithAlignmentAtLeastAsStrict(T) __TBB_machine_type_with_s trictest_alignment
#endif #endif
#endif /* ____TBB_TypeWithAlignmentAtLeastAsStrict */ #endif /* ____TBB_TypeWithAlignmentAtLeastAsStrict */
// Template class here is to avoid instantiation of the static data for mod
ules that don't use it
template<typename T>
struct reverse {
static const T byte_table[256];
};
// An efficient implementation of the reverse function utilizes a 2^8 looku
p table holding the bit-reversed
// values of [0..2^8 - 1]. Those values can also be computed on the fly at
a slightly higher cost.
template<typename T>
const T reverse<T>::byte_table[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8,
0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4,
0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2,
0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA,
0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE,
0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1,
0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5,
0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD,
0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB,
0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7,
0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
0x3F, 0xBF, 0x7F, 0xFF
};
} // namespace internal } // namespace internal
} // namespace tbb } // namespace tbb
#ifndef __TBB_CompareAndSwap1 #ifndef __TBB_CompareAndSwap1
#define __TBB_CompareAndSwap1 tbb::internal::__TBB_CompareAndSwapGeneric<1, uint8_t> #define __TBB_CompareAndSwap1 tbb::internal::__TBB_CompareAndSwapGeneric<1, uint8_t>
#endif #endif
#ifndef __TBB_CompareAndSwap2 #ifndef __TBB_CompareAndSwap2
#define __TBB_CompareAndSwap2 tbb::internal::__TBB_CompareAndSwapGeneric<2, uint16_t> #define __TBB_CompareAndSwap2 tbb::internal::__TBB_CompareAndSwapGeneric<2, uint16_t>
#endif #endif
skipping to change at line 592 skipping to change at line 623
if ( !__TBB_TryLockByte(flag) ) { if ( !__TBB_TryLockByte(flag) ) {
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_ReverseByte
inline unsigned char __TBB_ReverseByte(unsigned char src) {
return tbb::internal::reverse<unsigned char>::byte_table[src];
}
#endif
template<typename T>
T __TBB_ReverseBits(T src)
{
T dst;
unsigned char *original = (unsigned char *) &src;
unsigned char *reversed = (unsigned char *) &dst;
for( int i = sizeof(T)-1; i >= 0; i-- )
reversed[i] = __TBB_ReverseByte( original[sizeof(T)-i-1] );
return dst;
}
#endif /* __TBB_machine_H */ #endif /* __TBB_machine_H */
 End of changes. 5 change blocks. 
1 lines changed or deleted 70 lines changed or added


 tbb_profiling.h   tbb_profiling.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 tbb_stddef.h   tbb_stddef.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 33 skipping to change at line 33
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_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 2 #define TBB_VERSION_MAJOR 3
#define TBB_VERSION_MINOR 2 #define TBB_VERSION_MINOR 0
// Engineering-focused interface version // Engineering-focused interface version
#define TBB_INTERFACE_VERSION 4001 #define TBB_INTERFACE_VERSION 5000
#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 162 skipping to change at line 162
#include <cstddef> /* Need size_t and ptrdiff_t (the latter on Windows only) from here. */ #include <cstddef> /* Need size_t and ptrdiff_t (the latter on Windows only) from here. */
#if _MSC_VER #if _MSC_VER
#define __TBB_tbb_windef_H #define __TBB_tbb_windef_H
#include "_tbb_windef.h" #include "_tbb_windef.h"
#undef __TBB_tbb_windef_H #undef __TBB_tbb_windef_H
#endif #endif
#include "tbb_config.h" #include "tbb_config.h"
//! The namespace tbb contains all components of the library.
namespace tbb { namespace tbb {
//! Type for an assertion handler //! Type for an assertion handler
typedef void(*assertion_handler_type)( const char* filename, int line, const char* expression, const char * comment ); typedef void(*assertion_handler_type)( const char* filename, int line, const char* expression, const char * comment );
}
#if TBB_USE_ASSERT #if TBB_USE_ASSERT
//! Assert that x is true. //! Assert that x is true.
/** If x is false, print assertion failure message. /** If x is false, print assertion failure message.
If the comment argument is not NULL, it is printed as part of the failu re message. If the comment argument is not NULL, it is printed as part of the failu re message.
The comment argument has no other effect. */ The comment argument has no other effect. */
#define __TBB_ASSERT(predicate,message) ((predicate)?((void)0):tbb::asserti on_failure(__FILE__,__LINE__,#predicate,message)) #define __TBB_ASSERT(predicate,message) ((predicate)?((void)0):tbb::asserti on_failure(__FILE__,__LINE__,#predicate,message))
#define __TBB_ASSERT_EX __TBB_ASSERT #define __TBB_ASSERT_EX __TBB_ASSERT
namespace tbb {
//! Set assertion handler and return previous value of it. //! Set assertion handler and return previous value of it.
assertion_handler_type __TBB_EXPORTED_FUNC set_assertion_handler( asser tion_handler_type new_handler ); assertion_handler_type __TBB_EXPORTED_FUNC set_assertion_handler( asser tion_handler_type new_handler );
//! Process an assertion failure. //! Process an assertion failure.
/** Normally called from __TBB_ASSERT macro. /** Normally called from __TBB_ASSERT macro.
If assertion handler is null, print message for assertion failure a nd abort. If assertion handler is null, print message for assertion failure a nd abort.
Otherwise call the assertion handler. */ Otherwise call the assertion handler. */
void __TBB_EXPORTED_FUNC assertion_failure( const char* filename, int l ine, const char* expression, const char* comment ); void __TBB_EXPORTED_FUNC assertion_failure( const char* filename, int l ine, const char* expression, const char* comment );
} // namespace tbb
#else #else
//! No-op version of __TBB_ASSERT. //! No-op version of __TBB_ASSERT.
#define __TBB_ASSERT(predicate,comment) ((void)0) #define __TBB_ASSERT(predicate,comment) ((void)0)
//! "Extended" version is useful to suppress warnings if a variable is only used with an assert //! "Extended" version is useful to suppress warnings if a variable is only used with an assert
#define __TBB_ASSERT_EX(predicate,comment) ((void)(1 && (predicate))) #define __TBB_ASSERT_EX(predicate,comment) ((void)(1 && (predicate)))
#endif /* TBB_USE_ASSERT */ #endif /* TBB_USE_ASSERT */
//! The namespace tbb contains all components of the library.
namespace tbb {
//! The function returns the interface version of the TBB shared library be ing used. //! The function returns the interface version of the TBB shared library be ing used.
/** /**
* The version it returns is determined at runtime, not at compile/link tim e. * The version it returns is determined at runtime, not at compile/link tim e.
* So it can be different than the value of TBB_INTERFACE_VERSION obtained at compile time. * So it can be different than the value of TBB_INTERFACE_VERSION obtained at compile time.
*/ */
extern "C" int __TBB_EXPORTED_FUNC TBB_runtime_interface_version(); extern "C" int __TBB_EXPORTED_FUNC TBB_runtime_interface_version();
//! Dummy type that distinguishes splitting constructor from copy construct or. //! Dummy type that distinguishes splitting constructor from copy construct or.
/** /**
* See description of parallel_for and parallel_reduce for example usages. * See description of parallel_for and parallel_reduce for example usages.
skipping to change at line 227 skipping to change at line 222
*/ */
namespace internal { namespace internal {
using std::size_t; using std::size_t;
//! An unsigned integral type big enough to hold a pointer. //! An unsigned integral type big enough to hold a pointer.
/** There's no guarantee by the C++ standard that a size_t is really big en ough, /** There's no guarantee by the C++ standard that a size_t is really big en ough,
but it happens to be for all platforms of interest. */ but it happens to be for all platforms of interest. */
typedef size_t uintptr; typedef size_t uintptr;
//! A signed integral type big enough to hold a pointer. //! Compile-time constant that is upper bound on cache line/sector size.
/** There's no guarantee by the C++ standard that a ptrdiff_t is really big /** It should be used only in situations where having a compile-time upper
enough, bound is more useful than a run-time exact answer.
but it happens to be for all platforms of interest. */ @ingroup memory_allocation */
typedef std::ptrdiff_t intptr; const size_t NFS_MaxLineSize = 128;
template<class T, int S>
struct padded_base : T {
char pad[NFS_MaxLineSize - sizeof(T) % NFS_MaxLineSize];
};
template<class T> struct padded_base<T, 0> : T {};
//! Pads type T to fill out to a multiple of cache line size.
template<class T>
struct padded : padded_base<T, sizeof(T)> {};
//! Extended variant of the standard offsetof macro
/** The standard offsetof macro is not sufficient for TBB as it can be used
for
POD-types only. The constant 0x1000 (not NULL) is necessary to appease
GCC. **/
#define __TBB_offsetof(class_name, member_name) \
((ptrdiff_t)&(reinterpret_cast<class_name*>(0x1000)->member_name) - 0x1
000)
//! Returns address of the object containing a member with the given name a
nd address
#define __TBB_get_object_ref(class_name, member_name, member_addr) \
(*reinterpret_cast<class_name*>((char*)member_addr - __TBB_offsetof(cla
ss_name, member_name)))
//! Throws std::runtime_error with what() returning error_code description
prefixed with aux_info
void __TBB_EXPORTED_FUNC handle_perror( int error_code, const char* aux_inf
o );
#if TBB_USE_EXCEPTIONS
#define __TBB_TRY try
#define __TBB_CATCH(e) catch(e)
#define __TBB_THROW(e) throw e
#define __TBB_RETHROW() throw
#else /* !TBB_USE_EXCEPTIONS */
inline bool __TBB_false() { return false; }
#define __TBB_TRY
#define __TBB_CATCH(e) if ( tbb::internal::__TBB_false() )
#define __TBB_THROW(e) ((void)0)
#define __TBB_RETHROW() ((void)0)
#endif /* !TBB_USE_EXCEPTIONS */
//! Report a runtime warning. //! Report a runtime warning.
void __TBB_EXPORTED_FUNC runtime_warning( const char* format, ... ); void __TBB_EXPORTED_FUNC runtime_warning( const char* format, ... );
#if TBB_USE_ASSERT #if TBB_USE_ASSERT
//! Set p to invalid pointer value. //! Set p to invalid pointer value.
template<typename T> template<typename T>
inline void poison_pointer( T* & p ) { inline void poison_pointer( T* & p ) {
p = reinterpret_cast<T*>(-1); p = reinterpret_cast<T*>(-1);
} }
 End of changes. 9 change blocks. 
15 lines changed or deleted 53 lines changed or added


 tbb_thread.h   tbb_thread.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 42 skipping to change at line 42
#if _WIN32||_WIN64 #if _WIN32||_WIN64
#include <windows.h> #include <windows.h>
#define __TBB_NATIVE_THREAD_ROUTINE unsigned WINAPI #define __TBB_NATIVE_THREAD_ROUTINE unsigned WINAPI
#define __TBB_NATIVE_THREAD_ROUTINE_PTR(r) unsigned (WINAPI* r)( void* ) #define __TBB_NATIVE_THREAD_ROUTINE_PTR(r) unsigned (WINAPI* r)( void* )
#else #else
#define __TBB_NATIVE_THREAD_ROUTINE void* #define __TBB_NATIVE_THREAD_ROUTINE void*
#define __TBB_NATIVE_THREAD_ROUTINE_PTR(r) void* (*r)( void* ) #define __TBB_NATIVE_THREAD_ROUTINE_PTR(r) void* (*r)( void* )
#include <pthread.h> #include <pthread.h>
#endif // _WIN32||_WIN64 #endif // _WIN32||_WIN64
#include <iosfwd>
#include <exception> // Need std::terminate from here.
#include "tbb_stddef.h" #include "tbb_stddef.h"
#include "tick_count.h" #include "tick_count.h"
#include <exception> // Need std::terminate from here.
#if !TBB_USE_EXCEPTIONS && _MSC_VER
// Suppress "C++ exception handler used, but unwind semantics are not e
nabled" warning in STL headers
#pragma warning (push)
#pragma warning (disable: 4530)
#endif
#include <iosfwd>
#if !TBB_USE_EXCEPTIONS && _MSC_VER
#pragma warning (pop)
#endif
namespace tbb { namespace tbb {
//! @cond INTERNAL //! @cond INTERNAL
namespace internal { namespace internal {
class tbb_thread_v3; class tbb_thread_v3;
} // namespace internal } // namespace internal
skipping to change at line 75 skipping to change at line 86
struct thread_closure_base { struct thread_closure_base {
void* operator new( size_t size ) {return allocate_closure_v3(size) ;} void* operator new( size_t size ) {return allocate_closure_v3(size) ;}
void operator delete( void* ptr ) {free_closure_v3(ptr);} void operator delete( void* ptr ) {free_closure_v3(ptr);}
}; };
template<class F> struct thread_closure_0: thread_closure_base { template<class F> struct thread_closure_0: thread_closure_base {
F function; F function;
static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) { static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) {
thread_closure_0 *self = static_cast<thread_closure_0*>(c); thread_closure_0 *self = static_cast<thread_closure_0*>(c);
try { __TBB_TRY {
self->function(); self->function();
} catch ( ... ) { } __TBB_CATCH( ... ) {
std::terminate(); std::terminate();
} }
delete self; delete self;
return 0; return 0;
} }
thread_closure_0( const F& f ) : function(f) {} thread_closure_0( const F& f ) : function(f) {}
}; };
//! Structure used to pass user function with 1 argument to thread. //! Structure used to pass user function with 1 argument to thread.
template<class F, class X> struct thread_closure_1: thread_closure_base { template<class F, class X> struct thread_closure_1: thread_closure_base {
F function; F function;
X arg1; X arg1;
//! Routine passed to Windows's _beginthreadex by thread::internal_ start() inside tbb.dll //! Routine passed to Windows's _beginthreadex by thread::internal_ start() inside tbb.dll
static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) { static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) {
thread_closure_1 *self = static_cast<thread_closure_1*>(c); thread_closure_1 *self = static_cast<thread_closure_1*>(c);
try { __TBB_TRY {
self->function(self->arg1); self->function(self->arg1);
} catch ( ... ) { } __TBB_CATCH( ... ) {
std::terminate(); std::terminate();
} }
delete self; delete self;
return 0; return 0;
} }
thread_closure_1( const F& f, const X& x ) : function(f), arg1(x) { } thread_closure_1( const F& f, const X& x ) : function(f), arg1(x) { }
}; };
template<class F, class X, class Y> struct thread_closure_2: thread_clo sure_base { template<class F, class X, class Y> struct thread_closure_2: thread_clo sure_base {
F function; F function;
X arg1; X arg1;
Y arg2; Y arg2;
//! Routine passed to Windows's _beginthreadex by thread::internal_ start() inside tbb.dll //! Routine passed to Windows's _beginthreadex by thread::internal_ start() inside tbb.dll
static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) { static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) {
thread_closure_2 *self = static_cast<thread_closure_2*>(c); thread_closure_2 *self = static_cast<thread_closure_2*>(c);
try { __TBB_TRY {
self->function(self->arg1, self->arg2); self->function(self->arg1, self->arg2);
} catch ( ... ) { } __TBB_CATCH( ... ) {
std::terminate(); std::terminate();
} }
delete self; delete self;
return 0; return 0;
} }
thread_closure_2( const F& f, const X& x, const Y& y ) : function(f ), arg1(x), arg2(y) {} thread_closure_2( const F& f, const X& x, const Y& y ) : function(f ), arg1(x), arg2(y) {}
}; };
//! Versioned thread class. //! Versioned thread class.
class tbb_thread_v3 { class tbb_thread_v3 {
skipping to change at line 164 skipping to change at line 175
tbb_thread_v3& operator=(tbb_thread_v3& x) { tbb_thread_v3& operator=(tbb_thread_v3& x) {
if (joinable()) detach(); if (joinable()) detach();
my_handle = x.my_handle; my_handle = x.my_handle;
x.my_handle = 0; x.my_handle = 0;
#if _WIN32||_WIN64 #if _WIN32||_WIN64
my_thread_id = x.my_thread_id; my_thread_id = x.my_thread_id;
x.my_thread_id = 0; x.my_thread_id = 0;
#endif // _WIN32||_WIN64 #endif // _WIN32||_WIN64
return *this; return *this;
} }
void swap( tbb_thread_v3& t ) {tbb::swap( *this, t );}
bool joinable() const {return my_handle!=0; } bool joinable() const {return my_handle!=0; }
//! The completion of the thread represented by *this happens befor e join() returns. //! The completion of the thread represented by *this happens befor e join() returns.
void __TBB_EXPORTED_METHOD join(); void __TBB_EXPORTED_METHOD join();
//! When detach() returns, *this no longer represents the possibly continuing thread of execution. //! When detach() returns, *this no longer represents the possibly continuing thread of execution.
void __TBB_EXPORTED_METHOD detach(); void __TBB_EXPORTED_METHOD detach();
~tbb_thread_v3() {if( joinable() ) detach();} ~tbb_thread_v3() {if( joinable() ) detach();}
inline id get_id() const; inline id get_id() const;
native_handle_type native_handle() { return my_handle; } native_handle_type native_handle() { return my_handle; }
//! The number of hardware thread contexts. //! The number of hardware thread contexts.
skipping to change at line 191 skipping to change at line 203
/** Runs start_routine(closure) on another thread and sets my_handl e to the handle of the created thread. */ /** Runs start_routine(closure) on another thread and sets my_handl e to the handle of the created thread. */
void __TBB_EXPORTED_METHOD internal_start( __TBB_NATIVE_THREAD_ROUT INE_PTR(start_routine), void __TBB_EXPORTED_METHOD internal_start( __TBB_NATIVE_THREAD_ROUT INE_PTR(start_routine),
void* closure ); void* closure );
friend void __TBB_EXPORTED_FUNC move_v3( tbb_thread_v3& t1, tbb_thr ead_v3& t2 ); friend void __TBB_EXPORTED_FUNC move_v3( tbb_thread_v3& t1, tbb_thr ead_v3& t2 );
friend void tbb::swap( tbb_thread_v3& t1, tbb_thread_v3& t2 ); friend void tbb::swap( tbb_thread_v3& t1, tbb_thread_v3& t2 );
}; };
class tbb_thread_v3::id { class tbb_thread_v3::id {
#if _WIN32||_WIN64 #if _WIN32||_WIN64
DWORD my_id; DWORD my_id;
id( DWORD my_id ) : my_id(my_id) {} id( DWORD id_ ) : my_id(id_) {}
#else #else
pthread_t my_id; pthread_t my_id;
id( pthread_t my_id ) : my_id(my_id) {} id( pthread_t id_ ) : my_id(id_) {}
#endif // _WIN32||_WIN64 #endif // _WIN32||_WIN64
friend class tbb_thread_v3; friend class tbb_thread_v3;
public: public:
id() : my_id(0) {} id() : my_id(0) {}
friend bool operator==( tbb_thread_v3::id x, tbb_thread_v3::id y ); friend bool operator==( tbb_thread_v3::id x, tbb_thread_v3::id y );
friend bool operator!=( tbb_thread_v3::id x, tbb_thread_v3::id y ); friend bool operator!=( tbb_thread_v3::id x, tbb_thread_v3::id y );
friend bool operator<( tbb_thread_v3::id x, tbb_thread_v3::id y ); friend bool operator<( tbb_thread_v3::id x, tbb_thread_v3::id y );
friend bool operator<=( tbb_thread_v3::id x, tbb_thread_v3::id y ); friend bool operator<=( tbb_thread_v3::id x, tbb_thread_v3::id y );
friend bool operator>( tbb_thread_v3::id x, tbb_thread_v3::id y ); friend bool operator>( tbb_thread_v3::id x, tbb_thread_v3::id y );
 End of changes. 12 change blocks. 
11 lines changed or deleted 24 lines changed or added


 tbbmalloc_proxy.h   tbbmalloc_proxy.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 tick_count.h   tick_count.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 windows_ia32.h   windows_ia32.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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 154 skipping to change at line 154
__asm mov A, value \ __asm mov A, value \
__asm lock xchg [edx], A \ __asm lock xchg [edx], A \
__asm mov result, A \ __asm mov result, A \
} \ } \
__TBB_release_consistency_helper(); \ __TBB_release_consistency_helper(); \
return result; \ return result; \
} }
__TBB_DEFINE_ATOMICS(1, __int8, __int8, al, cl) __TBB_DEFINE_ATOMICS(1, __int8, __int8, al, cl)
__TBB_DEFINE_ATOMICS(2, __int16, __int16, ax, cx) __TBB_DEFINE_ATOMICS(2, __int16, __int16, ax, cx)
__TBB_DEFINE_ATOMICS(4, __int32, ptrdiff_t, eax, ecx) __TBB_DEFINE_ATOMICS(4, __int32, __int32, eax, ecx)
__TBB_DEFINE_ATOMICS(W, ptrdiff_t, ptrdiff_t, eax, ecx)
static inline __int32 __TBB_machine_lg( unsigned __int64 i ) { static inline __int32 __TBB_machine_lg( unsigned __int64 i ) {
unsigned __int32 j; unsigned __int32 j;
__asm __asm
{ {
bsr eax, i bsr eax, i
mov j, eax mov j, eax
} }
return j; return j;
} }
skipping to change at line 200 skipping to change at line 201
add eax, -1 add eax, -1
jne L1 jne L1
} }
return; return;
} }
#define __TBB_CompareAndSwap1(P,V,C) __TBB_machine_cmpswp1(P,V,C) #define __TBB_CompareAndSwap1(P,V,C) __TBB_machine_cmpswp1(P,V,C)
#define __TBB_CompareAndSwap2(P,V,C) __TBB_machine_cmpswp2(P,V,C) #define __TBB_CompareAndSwap2(P,V,C) __TBB_machine_cmpswp2(P,V,C)
#define __TBB_CompareAndSwap4(P,V,C) __TBB_machine_cmpswp4(P,V,C) #define __TBB_CompareAndSwap4(P,V,C) __TBB_machine_cmpswp4(P,V,C)
#define __TBB_CompareAndSwap8(P,V,C) __TBB_machine_cmpswp8(P,V,C) #define __TBB_CompareAndSwap8(P,V,C) __TBB_machine_cmpswp8(P,V,C)
#define __TBB_CompareAndSwapW(P,V,C) __TBB_machine_cmpswp4(P,V,C) #define __TBB_CompareAndSwapW(P,V,C) __TBB_machine_cmpswpW(P,V,C)
#define __TBB_FetchAndAdd1(P,V) __TBB_machine_fetchadd1(P,V) #define __TBB_FetchAndAdd1(P,V) __TBB_machine_fetchadd1(P,V)
#define __TBB_FetchAndAdd2(P,V) __TBB_machine_fetchadd2(P,V) #define __TBB_FetchAndAdd2(P,V) __TBB_machine_fetchadd2(P,V)
#define __TBB_FetchAndAdd4(P,V) __TBB_machine_fetchadd4(P,V) #define __TBB_FetchAndAdd4(P,V) __TBB_machine_fetchadd4(P,V)
#define __TBB_FetchAndAdd8(P,V) __TBB_machine_fetchadd8(P,V) #define __TBB_FetchAndAdd8(P,V) __TBB_machine_fetchadd8(P,V)
#define __TBB_FetchAndAddW(P,V) __TBB_machine_fetchadd4(P,V) #define __TBB_FetchAndAddW(P,V) __TBB_machine_fetchaddW(P,V)
#define __TBB_FetchAndStore1(P,V) __TBB_machine_fetchstore1(P,V) #define __TBB_FetchAndStore1(P,V) __TBB_machine_fetchstore1(P,V)
#define __TBB_FetchAndStore2(P,V) __TBB_machine_fetchstore2(P,V) #define __TBB_FetchAndStore2(P,V) __TBB_machine_fetchstore2(P,V)
#define __TBB_FetchAndStore4(P,V) __TBB_machine_fetchstore4(P,V) #define __TBB_FetchAndStore4(P,V) __TBB_machine_fetchstore4(P,V)
#define __TBB_FetchAndStore8(P,V) __TBB_machine_fetchstore8(P,V) #define __TBB_FetchAndStore8(P,V) __TBB_machine_fetchstore8(P,V)
#define __TBB_FetchAndStoreW(P,V) __TBB_machine_fetchstore4(P,V) #define __TBB_FetchAndStoreW(P,V) __TBB_machine_fetchstoreW(P,V)
// Should define this: // Should define this:
#define __TBB_Store8(P,V) __TBB_machine_store8(P,V) #define __TBB_Store8(P,V) __TBB_machine_store8(P,V)
#define __TBB_Load8(P) __TBB_machine_load8(P) #define __TBB_Load8(P) __TBB_machine_load8(P)
#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)
// Definition of other functions // Definition of other functions
extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void );
#define __TBB_Yield() SwitchToThread() #define __TBB_Yield() SwitchToThread()
 End of changes. 5 change blocks. 
5 lines changed or deleted 6 lines changed or added


 windows_intel64.h   windows_intel64.h 
/* /*
Copyright 2005-2009 Intel Corporation. All Rights Reserved. Copyright 2005-2010 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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/