_flow_graph_impl.h | _flow_graph_impl.h | |||
---|---|---|---|---|
skipping to change at line 42 | skipping to change at line 42 | |||
#ifndef __TBB_flow_graph_H | #ifndef __TBB_flow_graph_H | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
namespace internal { | namespace internal { | |||
namespace graph_policy_namespace { | namespace graph_policy_namespace { | |||
enum graph_buffer_policy { rejecting, reserving, queueing, tag_matc hing }; | enum graph_buffer_policy { rejecting, reserving, queueing, tag_matc hing }; | |||
} | } | |||
// -------------- function_body containers ---------------------- | ||||
//! A functor that takes no input and generates a value of type Output | //! A functor that takes no input and generates a value of type Output | |||
template< typename Output > | template< typename Output > | |||
class source_body : tbb::internal::no_assign { | class source_body : tbb::internal::no_assign { | |||
public: | public: | |||
virtual ~source_body() {} | virtual ~source_body() {} | |||
virtual bool operator()(Output &output) = 0; | virtual bool operator()(Output &output) = 0; | |||
virtual source_body* clone() = 0; | virtual source_body* clone() = 0; | |||
}; | }; | |||
//! The leaf for source_body | //! The leaf for source_body | |||
skipping to change at line 158 | skipping to change at line 160 | |||
virtual void operator()(const Input &/* input*/, OutputSet &/*oset* /) = 0; | virtual void operator()(const Input &/* input*/, OutputSet &/*oset* /) = 0; | |||
virtual multifunction_body* clone() = 0; | virtual multifunction_body* clone() = 0; | |||
}; | }; | |||
//! leaf for multifunction. OutputSet can be a std::tuple or a vector. | //! leaf for multifunction. OutputSet can be a std::tuple or a vector. | |||
template<typename Input, typename OutputSet, typename B> | template<typename Input, typename OutputSet, typename B> | |||
class multifunction_body_leaf : public multifunction_body<Input, Output Set> { | class multifunction_body_leaf : public multifunction_body<Input, Output Set> { | |||
public: | public: | |||
multifunction_body_leaf(const B &_body) : body(_body), init_body(_b ody) { } | multifunction_body_leaf(const B &_body) : body(_body), init_body(_b ody) { } | |||
void operator()(const Input &input, OutputSet &oset) { | void operator()(const Input &input, OutputSet &oset) { | |||
body(input, oset); // body should explicitly put() to one or mo re of oset. | body(input, oset); // body may explicitly put() to one or more of oset. | |||
} | } | |||
B get_body() { return body; } | B get_body() { return body; } | |||
/*override*/ multifunction_body_leaf* clone() { | /*override*/ multifunction_body_leaf* clone() { | |||
return new multifunction_body_leaf<Input, OutputSet,B>(init_bod y); | return new multifunction_body_leaf<Input, OutputSet,B>(init_bod y); | |||
} | } | |||
private: | private: | |||
B body; | B body; | |||
B init_body; | B init_body; | |||
}; | }; | |||
//! A task that calls a node's forward function | // --------------------------- end of function_body containers ------------ | |||
------------ | ||||
// --------------------------- node task bodies --------------------------- | ||||
------------ | ||||
//! A task that calls a node's forward_task function | ||||
template< typename NodeType > | template< typename NodeType > | |||
class forward_task : public task { | class forward_task_bypass : public task { | |||
NodeType &my_node; | NodeType &my_node; | |||
public: | public: | |||
forward_task( NodeType &n ) : my_node(n) {} | forward_task_bypass( NodeType &n ) : my_node(n) {} | |||
task *execute() { | task *execute() { | |||
my_node.forward(); | task * new_task = my_node.forward_task(); | |||
return NULL; | if (new_task == SUCCESSFULLY_ENQUEUED) new_task = NULL; | |||
return new_task; | ||||
} | } | |||
}; | }; | |||
//! A task that calls a node's apply_body function, passing in an input | //! A task that calls a node's apply_body_bypass function, passing in a | |||
of type Input | n input of type Input | |||
// return the task* unless it is SUCCESSFULLY_ENQUEUED, in which case | ||||
return NULL | ||||
template< typename NodeType, typename Input > | template< typename NodeType, typename Input > | |||
class apply_body_task : public task { | class apply_body_task_bypass : public task { | |||
NodeType &my_node; | NodeType &my_node; | |||
Input my_input; | Input my_input; | |||
public: | public: | |||
apply_body_task( NodeType &n, const Input &i ) : my_node(n), my_inp ut(i) {} | apply_body_task_bypass( NodeType &n, const Input &i ) : my_node(n), my_input(i) {} | |||
task *execute() { | task *execute() { | |||
my_node.apply_body( my_input ); | task * next_task = my_node.apply_body_bypass( my_input ); | |||
return NULL; | if(next_task == SUCCESSFULLY_ENQUEUED) next_task = NULL; | |||
return next_task; | ||||
} | } | |||
}; | }; | |||
//! A task that calls a node's apply_body function with no input | //! A task that calls a node's apply_body function with no input | |||
template< typename NodeType > | template< typename NodeType > | |||
class source_task : public task { | class source_task_bypass : public task { | |||
NodeType &my_node; | NodeType &my_node; | |||
public: | public: | |||
source_task( NodeType &n ) : my_node(n) {} | source_task_bypass( NodeType &n ) : my_node(n) {} | |||
task *execute() { | task *execute() { | |||
my_node.apply_body( ); | task *new_task = my_node.apply_body_bypass( ); | |||
return NULL; | if(new_task == SUCCESSFULLY_ENQUEUED) return NULL; | |||
return new_task; | ||||
} | } | |||
}; | }; | |||
// ------------------------ end of node task bodies ----------------------- | ||||
------------ | ||||
//! An empty functor that takes an Input and returns a default construc ted Output | //! An empty functor that takes an Input and returns a default construc ted Output | |||
template< typename Input, typename Output > | template< typename Input, typename Output > | |||
struct empty_body { | struct empty_body { | |||
Output operator()( const Input & ) const { return Output(); } | Output operator()( const Input & ) const { return Output(); } | |||
}; | }; | |||
//! A node_cache maintains a std::queue of elements of type T. Each op eration is protected by a lock. | //! A node_cache maintains a std::queue of elements of type T. Each op eration is protected by a lock. | |||
template< typename T, typename M=spin_mutex > | template< typename T, typename M=spin_mutex > | |||
class node_cache { | class node_cache { | |||
public: | public: | |||
skipping to change at line 449 | skipping to change at line 461 | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
bool empty() { | bool empty() { | |||
typename my_mutex_type::scoped_lock l(my_mutex, false); | typename my_mutex_type::scoped_lock l(my_mutex, false); | |||
return my_successors.empty(); | return my_successors.empty(); | |||
} | } | |||
virtual bool try_put( const T &t ) = 0; | virtual task * try_put_task( const T &t ) = 0; | |||
}; | }; | |||
//! An abstract cache of succesors, specialized to continue_msg | //! An abstract cache of succesors, specialized to continue_msg | |||
template<> | template<> | |||
class successor_cache< continue_msg > : tbb::internal::no_copy { | class successor_cache< continue_msg > : tbb::internal::no_copy { | |||
protected: | protected: | |||
typedef spin_rw_mutex my_mutex_type; | typedef spin_rw_mutex my_mutex_type; | |||
my_mutex_type my_mutex; | my_mutex_type my_mutex; | |||
skipping to change at line 499 | skipping to change at line 511 | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
bool empty() { | bool empty() { | |||
my_mutex_type::scoped_lock l(my_mutex, false); | my_mutex_type::scoped_lock l(my_mutex, false); | |||
return my_successors.empty(); | return my_successors.empty(); | |||
} | } | |||
virtual bool try_put( const continue_msg &t ) = 0; | virtual task * try_put_task( const continue_msg &t ) = 0; | |||
}; | }; | |||
//! A cache of successors that are broadcast to | //! A cache of successors that are broadcast to | |||
template<typename T, typename M=spin_rw_mutex> | template<typename T, typename M=spin_rw_mutex> | |||
class broadcast_cache : public successor_cache<T, M> { | class broadcast_cache : public successor_cache<T, M> { | |||
typedef M my_mutex_type; | typedef M my_mutex_type; | |||
typedef std::list< receiver<T> * > my_successors_type; | typedef std::list< receiver<T> * > my_successors_type; | |||
public: | public: | |||
broadcast_cache( ) {} | broadcast_cache( ) {} | |||
bool try_put( const T &t ) { | // as above, but call try_put_task instead, and return the last tas | |||
bool msg = false; | k we received (if any) | |||
/*override*/ task * try_put_task( const T &t ) { | ||||
task * last_task = NULL; | ||||
bool upgraded = false; | bool upgraded = false; | |||
typename my_mutex_type::scoped_lock l(this->my_mutex, false); | typename my_mutex_type::scoped_lock l(this->my_mutex, false); | |||
typename my_successors_type::iterator i = this->my_successors.b egin(); | typename my_successors_type::iterator i = this->my_successors.b egin(); | |||
while ( i != this->my_successors.end() ) { | while ( i != this->my_successors.end() ) { | |||
if ( (*i)->try_put( t ) == true ) { | task *new_task = (*i)->try_put_task(t); | |||
++i; | last_task = combine_tasks(last_task, new_task); // enqueue | |||
msg = true; | if necessary | |||
} else { | if(new_task) { | |||
if ( (*i)->register_predecessor(*this->my_owner) ) { | ++i; | |||
if (!upgraded) { | } | |||
l.upgrade_to_writer(); | else { // failed | |||
upgraded = true; | if ( (*i)->register_predecessor(*this->my_owner) ) { | |||
} | if (!upgraded) { | |||
i = this->my_successors.erase(i); | l.upgrade_to_writer(); | |||
} | upgraded = true; | |||
else { | } | |||
++i; | i = this->my_successors.erase(i); | |||
} | } else { | |||
} | ++i; | |||
} | ||||
} | ||||
} | } | |||
return msg; | return last_task; | |||
} | } | |||
}; | }; | |||
//! A cache of successors that are put in a round-robin fashion | //! A cache of successors that are put in a round-robin fashion | |||
template<typename T, typename M=spin_rw_mutex > | template<typename T, typename M=spin_rw_mutex > | |||
class round_robin_cache : public successor_cache<T, M> { | class round_robin_cache : public successor_cache<T, M> { | |||
typedef size_t size_type; | typedef size_t size_type; | |||
typedef M my_mutex_type; | typedef M my_mutex_type; | |||
typedef std::list< receiver<T> * > my_successors_type; | typedef std::list< receiver<T> * > my_successors_type; | |||
public: | public: | |||
round_robin_cache( ) {} | round_robin_cache( ) {} | |||
size_type size() { | size_type size() { | |||
typename my_mutex_type::scoped_lock l(this->my_mutex, false); | typename my_mutex_type::scoped_lock l(this->my_mutex, false); | |||
return this->my_successors.size(); | return this->my_successors.size(); | |||
} | } | |||
bool try_put( const T &t ) { | /*override*/task *try_put_task( const T &t ) { | |||
bool upgraded = false; | bool upgraded = false; | |||
typename my_mutex_type::scoped_lock l(this->my_mutex, false); | typename my_mutex_type::scoped_lock l(this->my_mutex, false); | |||
typename my_successors_type::iterator i = this->my_successors.b egin(); | typename my_successors_type::iterator i = this->my_successors.b egin(); | |||
while ( i != this->my_successors.end() ) { | while ( i != this->my_successors.end() ) { | |||
if ( (*i)->try_put( t ) ) { | task *new_task = (*i)->try_put_task(t); | |||
return true; | if ( new_task ) { | |||
} else { | return new_task; | |||
if ( (*i)->register_predecessor(*this->my_owner) ) { | } else { | |||
if (!upgraded) { | if ( (*i)->register_predecessor(*this->my_owner) ) { | |||
l.upgrade_to_writer(); | if (!upgraded) { | |||
upgraded = true; | l.upgrade_to_writer(); | |||
} | upgraded = true; | |||
i = this->my_successors.erase(i); | } | |||
} | i = this->my_successors.erase(i); | |||
else { | } | |||
++i; | else { | |||
} | ++i; | |||
} | } | |||
} | ||||
} | } | |||
return false; | return NULL; | |||
} | } | |||
}; | }; | |||
template<typename T> | template<typename T> | |||
class decrementer : public continue_receiver, tbb::internal::no_copy { | class decrementer : public continue_receiver, tbb::internal::no_copy { | |||
T *my_node; | T *my_node; | |||
void execute() { | task *execute() { | |||
my_node->decrement_counter(); | return my_node->decrement_counter(); | |||
} | } | |||
public: | public: | |||
typedef continue_msg input_type; | typedef continue_msg input_type; | |||
typedef continue_msg output_type; | typedef continue_msg output_type; | |||
decrementer( int number_of_predecessors = 0 ) : continue_receiver( number_of_predecessors ) { } | decrementer( int number_of_predecessors = 0 ) : continue_receiver( number_of_predecessors ) { } | |||
void set_owner( T *node ) { my_node = node; } | void set_owner( T *node ) { my_node = node; } | |||
}; | }; | |||
End of changes. 23 change blocks. | ||||
54 lines changed or deleted | 75 lines changed or added | |||
_flow_graph_join_impl.h | _flow_graph_join_impl.h | |||
---|---|---|---|---|
skipping to change at line 46 | skipping to change at line 46 | |||
#include "tbb/internal/_flow_graph_types_impl.h" | #include "tbb/internal/_flow_graph_types_impl.h" | |||
namespace internal { | namespace internal { | |||
typedef size_t tag_value; | typedef size_t tag_value; | |||
static const tag_value NO_TAG = tag_value(-1); | static const tag_value NO_TAG = tag_value(-1); | |||
struct forwarding_base { | struct forwarding_base { | |||
forwarding_base(task *rt) : my_root_task(rt), current_tag(NO_TAG) { } | forwarding_base(task *rt) : my_root_task(rt), current_tag(NO_TAG) { } | |||
virtual ~forwarding_base() {} | virtual ~forwarding_base() {} | |||
virtual void decrement_port_count() = 0; | // decrement_port_count may create a forwarding task. If we cannot | |||
handle the task | ||||
// ourselves, ask decrement_port_count to deal with it. | ||||
virtual task * decrement_port_count(bool handle_task) = 0; | ||||
virtual void increment_port_count() = 0; | virtual void increment_port_count() = 0; | |||
virtual void increment_tag_count(tag_value /*t*/) {} | virtual task * increment_tag_count(tag_value /*t*/, bool /*handle_t ask*/) {return NULL;} | |||
// moved here so input ports can queue tasks | // moved here so input ports can queue tasks | |||
task* my_root_task; | task* my_root_task; | |||
tag_value current_tag; // so ports can refer to FE's desired items | tag_value current_tag; // so ports can refer to FE's desired items | |||
}; | }; | |||
template< int N > | template< int N > | |||
struct join_helper { | struct join_helper { | |||
template< typename TupleType, typename PortType > | template< typename TupleType, typename PortType > | |||
static inline void set_join_node_pointer(TupleType &my_input, PortT ype *port) { | static inline void set_join_node_pointer(TupleType &my_input, PortT ype *port) { | |||
std::get<N-1>( my_input ).set_join_node_pointer(port); | tbb::flow::get<N-1>( my_input ).set_join_node_pointer(port); | |||
join_helper<N-1>::set_join_node_pointer( my_input, port ); | join_helper<N-1>::set_join_node_pointer( my_input, port ); | |||
} | } | |||
template< typename TupleType > | template< typename TupleType > | |||
static inline void consume_reservations( TupleType &my_input ) { | static inline void consume_reservations( TupleType &my_input ) { | |||
std::get<N-1>( my_input ).consume(); | tbb::flow::get<N-1>( my_input ).consume(); | |||
join_helper<N-1>::consume_reservations( my_input ); | join_helper<N-1>::consume_reservations( my_input ); | |||
} | } | |||
template< typename TupleType > | template< typename TupleType > | |||
static inline void release_my_reservation( TupleType &my_input ) { | static inline void release_my_reservation( TupleType &my_input ) { | |||
std::get<N-1>( my_input ).release(); | tbb::flow::get<N-1>( my_input ).release(); | |||
} | } | |||
template <typename TupleType> | template <typename TupleType> | |||
static inline void release_reservations( TupleType &my_input) { | static inline void release_reservations( TupleType &my_input) { | |||
join_helper<N-1>::release_reservations(my_input); | join_helper<N-1>::release_reservations(my_input); | |||
release_my_reservation(my_input); | release_my_reservation(my_input); | |||
} | } | |||
template< typename InputTuple, typename OutputTuple > | template< typename InputTuple, typename OutputTuple > | |||
static inline bool reserve( InputTuple &my_input, OutputTuple &out) { | static inline bool reserve( InputTuple &my_input, OutputTuple &out) { | |||
if ( !std::get<N-1>( my_input ).reserve( std::get<N-1>( out ) ) ) return false; | if ( !tbb::flow::get<N-1>( my_input ).reserve( tbb::flow::get<N -1>( out ) ) ) return false; | |||
if ( !join_helper<N-1>::reserve( my_input, out ) ) { | if ( !join_helper<N-1>::reserve( my_input, out ) ) { | |||
release_my_reservation( my_input ); | release_my_reservation( my_input ); | |||
return false; | return false; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
template<typename InputTuple, typename OutputTuple> | template<typename InputTuple, typename OutputTuple> | |||
static inline bool get_my_item( InputTuple &my_input, OutputTuple & out) { | static inline bool get_my_item( InputTuple &my_input, OutputTuple & out) { | |||
bool res = std::get<N-1>(my_input).get_item(std::get<N-1>(out) ); // may fail | bool res = tbb::flow::get<N-1>(my_input).get_item(tbb::flow::ge t<N-1>(out) ); // may fail | |||
return join_helper<N-1>::get_my_item(my_input, out) && res; // do get on other inputs before returning | return join_helper<N-1>::get_my_item(my_input, out) && res; // do get on other inputs before returning | |||
} | } | |||
template<typename InputTuple, typename OutputTuple> | template<typename InputTuple, typename OutputTuple> | |||
static inline bool get_items(InputTuple &my_input, OutputTuple &out ) { | static inline bool get_items(InputTuple &my_input, OutputTuple &out ) { | |||
return get_my_item(my_input, out); | return get_my_item(my_input, out); | |||
} | } | |||
template<typename InputTuple> | template<typename InputTuple> | |||
static inline void reset_my_port(InputTuple &my_input) { | static inline void reset_my_port(InputTuple &my_input) { | |||
join_helper<N-1>::reset_my_port(my_input); | join_helper<N-1>::reset_my_port(my_input); | |||
std::get<N-1>(my_input).reset_port(); | tbb::flow::get<N-1>(my_input).reset_port(); | |||
} | } | |||
template<typename InputTuple> | template<typename InputTuple> | |||
static inline void reset_ports(InputTuple& my_input) { | static inline void reset_ports(InputTuple& my_input) { | |||
reset_my_port(my_input); | reset_my_port(my_input); | |||
} | } | |||
template<typename InputTuple, typename TagFuncTuple> | template<typename InputTuple, typename TagFuncTuple> | |||
static inline void set_tag_func(InputTuple &my_input, TagFuncTuple &my_tag_funcs) { | static inline void set_tag_func(InputTuple &my_input, TagFuncTuple &my_tag_funcs) { | |||
std::get<N-1>(my_input).set_my_original_tag_func(std::get<N-1>( | tbb::flow::get<N-1>(my_input).set_my_original_tag_func(tbb::flo | |||
my_tag_funcs)); | w::get<N-1>(my_tag_funcs)); | |||
std::get<N-1>(my_input).set_my_tag_func(std::get<N-1>(my_input) | tbb::flow::get<N-1>(my_input).set_my_tag_func(tbb::flow::get<N- | |||
.my_original_func()->clone()); | 1>(my_input).my_original_func()->clone()); | |||
std::get<N-1>(my_tag_funcs) = NULL; | tbb::flow::get<N-1>(my_tag_funcs) = NULL; | |||
join_helper<N-1>::set_tag_func(my_input, my_tag_funcs); | join_helper<N-1>::set_tag_func(my_input, my_tag_funcs); | |||
} | } | |||
template< typename TagFuncTuple1, typename TagFuncTuple2> | template< typename TagFuncTuple1, typename TagFuncTuple2> | |||
static inline void copy_tag_functors(TagFuncTuple1 &my_inputs, TagF uncTuple2 &other_inputs) { | static inline void copy_tag_functors(TagFuncTuple1 &my_inputs, TagF uncTuple2 &other_inputs) { | |||
if(std::get<N-1>(other_inputs).my_original_func()) { | if(tbb::flow::get<N-1>(other_inputs).my_original_func()) { | |||
std::get<N-1>(my_inputs).set_my_tag_func(std::get<N-1>(othe | tbb::flow::get<N-1>(my_inputs).set_my_tag_func(tbb::flow::g | |||
r_inputs).my_original_func()->clone()); | et<N-1>(other_inputs).my_original_func()->clone()); | |||
std::get<N-1>(my_inputs).set_my_original_tag_func(std::get< | tbb::flow::get<N-1>(my_inputs).set_my_original_tag_func(tbb | |||
N-1>(other_inputs).my_original_func()->clone()); | ::flow::get<N-1>(other_inputs).my_original_func()->clone()); | |||
} | } | |||
join_helper<N-1>::copy_tag_functors(my_inputs, other_inputs); | join_helper<N-1>::copy_tag_functors(my_inputs, other_inputs); | |||
} | } | |||
template<typename InputTuple> | template<typename InputTuple> | |||
static inline void reset_inputs(InputTuple &my_input) { | static inline void reset_inputs(InputTuple &my_input) { | |||
join_helper<N-1>::reset_inputs(my_input); | join_helper<N-1>::reset_inputs(my_input); | |||
std::get<N-1>(my_input).reinitialize_port(); | tbb::flow::get<N-1>(my_input).reinitialize_port(); | |||
} | } | |||
}; | }; | |||
template< > | template< > | |||
struct join_helper<1> { | struct join_helper<1> { | |||
template< typename TupleType, typename PortType > | template< typename TupleType, typename PortType > | |||
static inline void set_join_node_pointer(TupleType &my_input, PortT ype *port) { | static inline void set_join_node_pointer(TupleType &my_input, PortT ype *port) { | |||
std::get<0>( my_input ).set_join_node_pointer(port); | tbb::flow::get<0>( my_input ).set_join_node_pointer(port); | |||
} | } | |||
template< typename TupleType > | template< typename TupleType > | |||
static inline void consume_reservations( TupleType &my_input ) { | static inline void consume_reservations( TupleType &my_input ) { | |||
std::get<0>( my_input ).consume(); | tbb::flow::get<0>( my_input ).consume(); | |||
} | } | |||
template< typename TupleType > | template< typename TupleType > | |||
static inline void release_my_reservation( TupleType &my_input ) { | static inline void release_my_reservation( TupleType &my_input ) { | |||
std::get<0>( my_input ).release(); | tbb::flow::get<0>( my_input ).release(); | |||
} | } | |||
template<typename TupleType> | template<typename TupleType> | |||
static inline void release_reservations( TupleType &my_input) { | static inline void release_reservations( TupleType &my_input) { | |||
release_my_reservation(my_input); | release_my_reservation(my_input); | |||
} | } | |||
template< typename InputTuple, typename OutputTuple > | template< typename InputTuple, typename OutputTuple > | |||
static inline bool reserve( InputTuple &my_input, OutputTuple &out) { | static inline bool reserve( InputTuple &my_input, OutputTuple &out) { | |||
return std::get<0>( my_input ).reserve( std::get<0>( out ) ); | return tbb::flow::get<0>( my_input ).reserve( tbb::flow::get<0> ( out ) ); | |||
} | } | |||
template<typename InputTuple, typename OutputTuple> | template<typename InputTuple, typename OutputTuple> | |||
static inline bool get_my_item( InputTuple &my_input, OutputTuple & out) { | static inline bool get_my_item( InputTuple &my_input, OutputTuple & out) { | |||
return std::get<0>(my_input).get_item(std::get<0>(out)); | return tbb::flow::get<0>(my_input).get_item(tbb::flow::get<0>(o ut)); | |||
} | } | |||
template<typename InputTuple, typename OutputTuple> | template<typename InputTuple, typename OutputTuple> | |||
static inline bool get_items(InputTuple &my_input, OutputTuple &out ) { | static inline bool get_items(InputTuple &my_input, OutputTuple &out ) { | |||
return get_my_item(my_input, out); | return get_my_item(my_input, out); | |||
} | } | |||
template<typename InputTuple> | template<typename InputTuple> | |||
static inline void reset_my_port(InputTuple &my_input) { | static inline void reset_my_port(InputTuple &my_input) { | |||
std::get<0>(my_input).reset_port(); | tbb::flow::get<0>(my_input).reset_port(); | |||
} | } | |||
template<typename InputTuple> | template<typename InputTuple> | |||
static inline void reset_ports(InputTuple& my_input) { | static inline void reset_ports(InputTuple& my_input) { | |||
reset_my_port(my_input); | reset_my_port(my_input); | |||
} | } | |||
template<typename InputTuple, typename TagFuncTuple> | template<typename InputTuple, typename TagFuncTuple> | |||
static inline void set_tag_func(InputTuple &my_input, TagFuncTuple &my_tag_funcs) { | static inline void set_tag_func(InputTuple &my_input, TagFuncTuple &my_tag_funcs) { | |||
std::get<0>(my_input).set_my_original_tag_func(std::get<0>(my_t | tbb::flow::get<0>(my_input).set_my_original_tag_func(tbb::flow: | |||
ag_funcs)); | :get<0>(my_tag_funcs)); | |||
std::get<0>(my_input).set_my_tag_func(std::get<0>(my_input).my_ | tbb::flow::get<0>(my_input).set_my_tag_func(tbb::flow::get<0>(m | |||
original_func()->clone()); | y_input).my_original_func()->clone()); | |||
std::get<0>(my_tag_funcs) = NULL; | tbb::flow::get<0>(my_tag_funcs) = NULL; | |||
} | } | |||
template< typename TagFuncTuple1, typename TagFuncTuple2> | template< typename TagFuncTuple1, typename TagFuncTuple2> | |||
static inline void copy_tag_functors(TagFuncTuple1 &my_inputs, TagF uncTuple2 &other_inputs) { | static inline void copy_tag_functors(TagFuncTuple1 &my_inputs, TagF uncTuple2 &other_inputs) { | |||
if(std::get<0>(other_inputs).my_original_func()) { | if(tbb::flow::get<0>(other_inputs).my_original_func()) { | |||
std::get<0>(my_inputs).set_my_tag_func(std::get<0>(other_in | tbb::flow::get<0>(my_inputs).set_my_tag_func(tbb::flow::get | |||
puts).my_original_func()->clone()); | <0>(other_inputs).my_original_func()->clone()); | |||
std::get<0>(my_inputs).set_my_original_tag_func(std::get<0> | tbb::flow::get<0>(my_inputs).set_my_original_tag_func(tbb:: | |||
(other_inputs).my_original_func()->clone()); | flow::get<0>(other_inputs).my_original_func()->clone()); | |||
} | } | |||
} | } | |||
template<typename InputTuple> | template<typename InputTuple> | |||
static inline void reset_inputs(InputTuple &my_input) { | static inline void reset_inputs(InputTuple &my_input) { | |||
std::get<0>(my_input).reinitialize_port(); | tbb::flow::get<0>(my_input).reinitialize_port(); | |||
} | } | |||
}; | }; | |||
//! The two-phase join port | //! The two-phase join port | |||
template< typename T > | template< typename T > | |||
class reserving_port : public receiver<T> { | class reserving_port : public receiver<T> { | |||
public: | public: | |||
typedef T input_type; | typedef T input_type; | |||
typedef sender<T> predecessor_type; | typedef sender<T> predecessor_type; | |||
private: | private: | |||
skipping to change at line 244 | skipping to change at line 246 | |||
reserving_port_operation *current; | reserving_port_operation *current; | |||
bool no_predecessors; | bool no_predecessors; | |||
while(op_list) { | while(op_list) { | |||
current = op_list; | current = op_list; | |||
op_list = op_list->next; | op_list = op_list->next; | |||
switch(current->type) { | switch(current->type) { | |||
case reg_pred: | case reg_pred: | |||
no_predecessors = my_predecessors.empty(); | no_predecessors = my_predecessors.empty(); | |||
my_predecessors.add(*(current->my_pred)); | my_predecessors.add(*(current->my_pred)); | |||
if ( no_predecessors ) { | if ( no_predecessors ) { | |||
my_join->decrement_port_count( ); // may try to for ward | (void) my_join->decrement_port_count(true); // may try to forward | |||
} | } | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
case rem_pred: | case rem_pred: | |||
my_predecessors.remove(*(current->my_pred)); | my_predecessors.remove(*(current->my_pred)); | |||
if(my_predecessors.empty()) my_join->increment_port_cou nt(); | if(my_predecessors.empty()) my_join->increment_port_cou nt(); | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
case res_item: | case res_item: | |||
if ( reserved ) { | if ( reserved ) { | |||
skipping to change at line 281 | skipping to change at line 283 | |||
break; | break; | |||
case con_res: | case con_res: | |||
reserved = false; | reserved = false; | |||
my_predecessors.try_consume( ); | my_predecessors.try_consume( ); | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
protected: | ||||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_c | ||||
ache; | ||||
template<typename X, typename Y> friend class internal::round_robin | ||||
_cache; | ||||
task *try_put_task( const T & ) { | ||||
return NULL; | ||||
} | ||||
public: | public: | |||
//! Constructor | //! Constructor | |||
reserving_port() : reserved(false) { | reserving_port() : reserved(false) { | |||
my_join = NULL; | my_join = NULL; | |||
my_predecessors.set_owner( this ); | my_predecessors.set_owner( this ); | |||
my_aggregator.initialize_handler(my_handler(this)); | my_aggregator.initialize_handler(my_handler(this)); | |||
} | } | |||
// copy constructor | // copy constructor | |||
skipping to change at line 302 | skipping to change at line 312 | |||
reserved = false; | reserved = false; | |||
my_join = NULL; | my_join = NULL; | |||
my_predecessors.set_owner( this ); | my_predecessors.set_owner( this ); | |||
my_aggregator.initialize_handler(my_handler(this)); | my_aggregator.initialize_handler(my_handler(this)); | |||
} | } | |||
void set_join_node_pointer(forwarding_base *join) { | void set_join_node_pointer(forwarding_base *join) { | |||
my_join = join; | my_join = join; | |||
} | } | |||
// always rejects, so arc is reversed (and reserves can be done.) | ||||
bool try_put( const T & ) { | ||||
return false; | ||||
} | ||||
//! Add a predecessor | //! Add a predecessor | |||
bool register_predecessor( sender<T> &src ) { | bool register_predecessor( sender<T> &src ) { | |||
reserving_port_operation op_data(src, reg_pred); | reserving_port_operation op_data(src, reg_pred); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return op_data.status == SUCCEEDED; | return op_data.status == SUCCEEDED; | |||
} | } | |||
//! Remove a predecessor | //! Remove a predecessor | |||
bool remove_predecessor( sender<T> &src ) { | bool remove_predecessor( sender<T> &src ) { | |||
reserving_port_operation op_data(src, rem_pred); | reserving_port_operation op_data(src, rem_pred); | |||
skipping to change at line 367 | skipping to change at line 372 | |||
//! queueing join_port | //! queueing join_port | |||
template<typename T> | template<typename T> | |||
class queueing_port : public receiver<T>, public item_buffer<T> { | class queueing_port : public receiver<T>, public item_buffer<T> { | |||
public: | public: | |||
typedef T input_type; | typedef T input_type; | |||
typedef sender<T> predecessor_type; | typedef sender<T> predecessor_type; | |||
typedef queueing_port<T> my_node_type; | typedef queueing_port<T> my_node_type; | |||
// ----------- Aggregator ------------ | // ----------- Aggregator ------------ | |||
private: | private: | |||
enum op_type { try__put, get__item, res_port }; | enum op_type { get__item, res_port, try__put_task }; | |||
enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |||
typedef queueing_port<T> my_class; | typedef queueing_port<T> my_class; | |||
class queueing_port_operation : public aggregated_operation<queuein g_port_operation> { | class queueing_port_operation : public aggregated_operation<queuein g_port_operation> { | |||
public: | public: | |||
char type; | char type; | |||
T my_val; | T my_val; | |||
T *my_arg; | T *my_arg; | |||
task * bypass_t; | ||||
// constructor for value parameter | // constructor for value parameter | |||
queueing_port_operation(const T& e, op_type t) : | queueing_port_operation(const T& e, op_type t) : | |||
// type(char(t)), my_val(const_cast<T>(e)) {} | type(char(t)), my_val(e) | |||
type(char(t)), my_val(e) {} | , bypass_t(NULL) | |||
{} | ||||
// constructor for pointer parameter | // constructor for pointer parameter | |||
queueing_port_operation(const T* p, op_type t) : | queueing_port_operation(const T* p, op_type t) : | |||
type(char(t)), my_arg(const_cast<T*>(p)) {} | type(char(t)), my_arg(const_cast<T*>(p)) | |||
, bypass_t(NULL) | ||||
{} | ||||
// constructor with no parameter | // constructor with no parameter | |||
queueing_port_operation(op_type t) : type(char(t)) {} | queueing_port_operation(op_type t) : type(char(t)) | |||
, bypass_t(NULL) | ||||
{} | ||||
}; | }; | |||
typedef internal::aggregating_functor<my_class, queueing_port_opera tion> my_handler; | typedef internal::aggregating_functor<my_class, queueing_port_opera tion> my_handler; | |||
friend class internal::aggregating_functor<my_class, queueing_port_ operation>; | friend class internal::aggregating_functor<my_class, queueing_port_ operation>; | |||
aggregator<my_handler, queueing_port_operation> my_aggregator; | aggregator<my_handler, queueing_port_operation> my_aggregator; | |||
void handle_operations(queueing_port_operation* op_list) { | void handle_operations(queueing_port_operation* op_list) { | |||
queueing_port_operation *current; | queueing_port_operation *current; | |||
bool was_empty; | bool was_empty; | |||
while(op_list) { | while(op_list) { | |||
current = op_list; | current = op_list; | |||
op_list = op_list->next; | op_list = op_list->next; | |||
switch(current->type) { | switch(current->type) { | |||
case try__put: | case try__put_task: { | |||
was_empty = this->buffer_empty(); | task *rtask = NULL; | |||
this->push_back(current->my_val); | was_empty = this->buffer_empty(); | |||
if (was_empty) my_join->decrement_port_count(); | this->push_back(current->my_val); | |||
__TBB_store_with_release(current->status, SUCCEEDED); | if (was_empty) rtask = my_join->decrement_port_coun | |||
t(false); | ||||
else | ||||
rtask = SUCCESSFULLY_ENQUEUED; | ||||
current->bypass_t = rtask; | ||||
__TBB_store_with_release(current->status, SUCCEEDED | ||||
); | ||||
} | ||||
break; | break; | |||
case get__item: | case get__item: | |||
if(!this->buffer_empty()) { | if(!this->buffer_empty()) { | |||
this->fetch_front(*(current->my_arg)); | this->fetch_front(*(current->my_arg)); | |||
__TBB_store_with_release(current->status, SUCCEEDED ); | __TBB_store_with_release(current->status, SUCCEEDED ); | |||
} | } | |||
else { | else { | |||
__TBB_store_with_release(current->status, FAILED); | __TBB_store_with_release(current->status, FAILED); | |||
} | } | |||
break; | break; | |||
case res_port: | case res_port: | |||
__TBB_ASSERT(this->item_valid(this->my_head), "No item to reset"); | __TBB_ASSERT(this->item_valid(this->my_head), "No item to reset"); | |||
this->invalidate_front(); ++(this->my_head); | this->invalidate_front(); ++(this->my_head); | |||
if(this->item_valid(this->my_head)) { | if(this->item_valid(this->my_head)) { | |||
my_join->decrement_port_count(); | (void)my_join->decrement_port_count(true); | |||
} | } | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
// ------------ End Aggregator --------------- | // ------------ End Aggregator --------------- | |||
protected: | ||||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_c | ||||
ache; | ||||
template<typename X, typename Y> friend class internal::round_robin | ||||
_cache; | ||||
/*override*/task *try_put_task(const T &v) { | ||||
queueing_port_operation op_data(v, try__put_task); | ||||
my_aggregator.execute(&op_data); | ||||
__TBB_ASSERT(op_data.status == SUCCEEDED || !op_data.bypass_t, | ||||
"inconsistent return from aggregator"); | ||||
if(!op_data.bypass_t) return SUCCESSFULLY_ENQUEUED; | ||||
return op_data.bypass_t; | ||||
} | ||||
public: | public: | |||
//! Constructor | //! Constructor | |||
queueing_port() : item_buffer<T>() { | queueing_port() : item_buffer<T>() { | |||
my_join = NULL; | my_join = NULL; | |||
my_aggregator.initialize_handler(my_handler(this)); | my_aggregator.initialize_handler(my_handler(this)); | |||
} | } | |||
//! copy constructor | //! copy constructor | |||
queueing_port(const queueing_port& /* other */) : receiver<T>(), it em_buffer<T>() { | queueing_port(const queueing_port& /* other */) : receiver<T>(), it em_buffer<T>() { | |||
my_join = NULL; | my_join = NULL; | |||
my_aggregator.initialize_handler(my_handler(this)); | my_aggregator.initialize_handler(my_handler(this)); | |||
} | } | |||
//! record parent for tallying available items | //! record parent for tallying available items | |||
void set_join_node_pointer(forwarding_base *join) { | void set_join_node_pointer(forwarding_base *join) { | |||
my_join = join; | my_join = join; | |||
} | } | |||
/*override*/bool try_put(const T &v) { | ||||
queueing_port_operation op_data(v, try__put); | ||||
my_aggregator.execute(&op_data); | ||||
return op_data.status == SUCCEEDED; | ||||
} | ||||
bool get_item( T &v ) { | bool get_item( T &v ) { | |||
queueing_port_operation op_data(&v, get__item); | queueing_port_operation op_data(&v, get__item); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return op_data.status == SUCCEEDED; | return op_data.status == SUCCEEDED; | |||
} | } | |||
// reset_port is called when item is accepted by successor, but | // reset_port is called when item is accepted by successor, but | |||
// is initiated by join_node. | // is initiated by join_node. | |||
void reset_port() { | void reset_port() { | |||
queueing_port_operation op_data(res_port); | queueing_port_operation op_data(res_port); | |||
skipping to change at line 503 | skipping to change at line 526 | |||
typedef tag_matching_port<T> my_class; | typedef tag_matching_port<T> my_class; | |||
class tag_matching_port_operation : public aggregated_operation<tag _matching_port_operation> { | class tag_matching_port_operation : public aggregated_operation<tag _matching_port_operation> { | |||
public: | public: | |||
char type; | char type; | |||
T my_val; | T my_val; | |||
T *my_arg; | T *my_arg; | |||
tag_value my_tag_value; | tag_value my_tag_value; | |||
// constructor for value parameter | // constructor for value parameter | |||
tag_matching_port_operation(const T& e, op_type t) : | tag_matching_port_operation(const T& e, op_type t) : | |||
// type(char(t)), my_val(const_cast<T>(e)) {} | ||||
type(char(t)), my_val(e) {} | type(char(t)), my_val(e) {} | |||
// constructor for pointer parameter | // constructor for pointer parameter | |||
tag_matching_port_operation(const T* p, op_type t) : | tag_matching_port_operation(const T* p, op_type t) : | |||
type(char(t)), my_arg(const_cast<T*>(p)) {} | type(char(t)), my_arg(const_cast<T*>(p)) {} | |||
// constructor with no parameter | // constructor with no parameter | |||
tag_matching_port_operation(op_type t) : type(char(t)) {} | tag_matching_port_operation(op_type t) : type(char(t)) {} | |||
}; | }; | |||
typedef internal::aggregating_functor<my_class, tag_matching_port_o peration> my_handler; | typedef internal::aggregating_functor<my_class, tag_matching_port_o peration> my_handler; | |||
friend class internal::aggregating_functor<my_class, tag_matching_p ort_operation>; | friend class internal::aggregating_functor<my_class, tag_matching_p ort_operation>; | |||
skipping to change at line 544 | skipping to change at line 566 | |||
break; | break; | |||
case res_port: | case res_port: | |||
// use current_tag from FE for item | // use current_tag from FE for item | |||
this->tagged_delete(my_join->current_tag); | this->tagged_delete(my_join->current_tag); | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
// ------------ End Aggregator --------------- | // ------------ End Aggregator --------------- | |||
protected: | ||||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_c | ||||
ache; | ||||
template<typename X, typename Y> friend class internal::round_robin | ||||
_cache; | ||||
/*override*/task *try_put_task(const T& v) { | ||||
tag_matching_port_operation op_data(v, try__put); | ||||
op_data.my_tag_value = (*my_tag_func)(v); | ||||
task *rtask = NULL; | ||||
my_aggregator.execute(&op_data); | ||||
if(op_data.status == SUCCEEDED) { | ||||
rtask = my_join->increment_tag_count(op_data.my_tag_value, | ||||
false); // may spawn | ||||
// rtask has to reflect the return status of the try_put | ||||
if(!rtask) rtask = SUCCESSFULLY_ENQUEUED; | ||||
} | ||||
return rtask; | ||||
} | ||||
public: | public: | |||
tag_matching_port() : receiver<T>(), tagged_buffer<tag_value, T, NO _TAG>() { | tag_matching_port() : receiver<T>(), tagged_buffer<tag_value, T, NO _TAG>() { | |||
my_join = NULL; | my_join = NULL; | |||
my_tag_func = NULL; | my_tag_func = NULL; | |||
my_original_tag_func = NULL; | my_original_tag_func = NULL; | |||
my_aggregator.initialize_handler(my_handler(this)); | my_aggregator.initialize_handler(my_handler(this)); | |||
} | } | |||
// copy constructor | // copy constructor | |||
skipping to change at line 579 | skipping to change at line 618 | |||
} | } | |||
void set_my_original_tag_func(my_tag_func_type *f) { | void set_my_original_tag_func(my_tag_func_type *f) { | |||
my_original_tag_func = f; | my_original_tag_func = f; | |||
} | } | |||
void set_my_tag_func(my_tag_func_type *f) { | void set_my_tag_func(my_tag_func_type *f) { | |||
my_tag_func = f; | my_tag_func = f; | |||
} | } | |||
/*override*/bool try_put(const T& v) { | ||||
tag_matching_port_operation op_data(v, try__put); | ||||
op_data.my_tag_value = (*my_tag_func)(v); | ||||
my_aggregator.execute(&op_data); | ||||
if(op_data.status == SUCCEEDED) { | ||||
// the assertion in the aggregator above will ensure we do | ||||
not call with the same | ||||
// tag twice. We have to exit the aggregator to keep lock- | ||||
ups from happening; | ||||
// the increment of the tag hash table in the FE is under a | ||||
separate aggregator, | ||||
// so that is serialized. | ||||
// is a race possible? I do not believe so; the increment | ||||
may cause a build of | ||||
// an output tuple, but its component is already in the has | ||||
h table for the port. | ||||
my_join->increment_tag_count(op_data.my_tag_value); // may | ||||
spawn | ||||
} | ||||
return op_data.status == SUCCEEDED; | ||||
} | ||||
bool get_item( T &v ) { | bool get_item( T &v ) { | |||
tag_matching_port_operation op_data(&v, get__item); | tag_matching_port_operation op_data(&v, get__item); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return op_data.status == SUCCEEDED; | return op_data.status == SUCCEEDED; | |||
} | } | |||
// reset_port is called when item is accepted by successor, but | // reset_port is called when item is accepted by successor, but | |||
// is initiated by join_node. | // is initiated by join_node. | |||
void reset_port() { | void reset_port() { | |||
tag_matching_port_operation op_data(res_port); | tag_matching_port_operation op_data(res_port); | |||
skipping to change at line 642 | skipping to change at line 664 | |||
template<graph_buffer_policy JP, typename InputTuple, typename OutputTu ple> | template<graph_buffer_policy JP, typename InputTuple, typename OutputTu ple> | |||
class join_node_base; | class join_node_base; | |||
//! join_node_FE : implements input port policy | //! join_node_FE : implements input port policy | |||
template<graph_buffer_policy JP, typename InputTuple, typename OutputTu ple> | template<graph_buffer_policy JP, typename InputTuple, typename OutputTu ple> | |||
class join_node_FE; | class join_node_FE; | |||
template<typename InputTuple, typename OutputTuple> | template<typename InputTuple, typename OutputTuple> | |||
class join_node_FE<reserving, InputTuple, OutputTuple> : public forward ing_base { | class join_node_FE<reserving, InputTuple, OutputTuple> : public forward ing_base { | |||
public: | public: | |||
static const int N = std::tuple_size<OutputTuple>::value; | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
typedef InputTuple input_type; | typedef InputTuple input_type; | |||
typedef join_node_base<reserving, InputTuple, OutputTuple> my_node_ type; // for forwarding | typedef join_node_base<reserving, InputTuple, OutputTuple> my_node_ type; // for forwarding | |||
join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NU LL) { | join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NU LL) { | |||
ports_with_no_inputs = N; | ports_with_no_inputs = N; | |||
join_helper<N>::set_join_node_pointer(my_inputs, this); | join_helper<N>::set_join_node_pointer(my_inputs, this); | |||
} | } | |||
join_node_FE(const join_node_FE& other) : forwarding_base(other.my_ root_task), my_node(NULL) { | join_node_FE(const join_node_FE& other) : forwarding_base(other.my_ root_task), my_node(NULL) { | |||
skipping to change at line 664 | skipping to change at line 686 | |||
join_helper<N>::set_join_node_pointer(my_inputs, this); | join_helper<N>::set_join_node_pointer(my_inputs, this); | |||
} | } | |||
void set_my_node(my_node_type *new_my_node) { my_node = new_my_node ; } | void set_my_node(my_node_type *new_my_node) { my_node = new_my_node ; } | |||
void increment_port_count() { | void increment_port_count() { | |||
++ports_with_no_inputs; | ++ports_with_no_inputs; | |||
} | } | |||
// if all input_ports have predecessors, spawn forward to try and c onsume tuples | // if all input_ports have predecessors, spawn forward to try and c onsume tuples | |||
void decrement_port_count() { | task * decrement_port_count(bool handle_task) { | |||
if(ports_with_no_inputs.fetch_and_decrement() == 1) { | if(ports_with_no_inputs.fetch_and_decrement() == 1) { | |||
task::enqueue( * new ( task::allocate_additional_child_of( | task *rtask = new ( task::allocate_additional_child_of( *(t | |||
*(this->my_root_task) ) ) | his->my_root_task) ) ) | |||
forward_task<my_node_type>(*my_node) ); | forward_task_bypass | |||
<my_node_type>(*my_node); | ||||
if(!handle_task) return rtask; | ||||
task::enqueue(*rtask); | ||||
} | } | |||
return NULL; | ||||
} | } | |||
input_type &input_ports() { return my_inputs; } | input_type &input_ports() { return my_inputs; } | |||
protected: | protected: | |||
void reset() { | void reset() { | |||
// called outside of parallel contexts | // called outside of parallel contexts | |||
ports_with_no_inputs = N; | ports_with_no_inputs = N; | |||
join_helper<N>::reset_inputs(my_inputs); | join_helper<N>::reset_inputs(my_inputs); | |||
skipping to change at line 707 | skipping to change at line 733 | |||
} | } | |||
input_type my_inputs; | input_type my_inputs; | |||
my_node_type *my_node; | my_node_type *my_node; | |||
atomic<size_t> ports_with_no_inputs; | atomic<size_t> ports_with_no_inputs; | |||
}; | }; | |||
template<typename InputTuple, typename OutputTuple> | template<typename InputTuple, typename OutputTuple> | |||
class join_node_FE<queueing, InputTuple, OutputTuple> : public forwardi ng_base { | class join_node_FE<queueing, InputTuple, OutputTuple> : public forwardi ng_base { | |||
public: | public: | |||
static const int N = std::tuple_size<OutputTuple>::value; | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
typedef InputTuple input_type; | typedef InputTuple input_type; | |||
typedef join_node_base<queueing, InputTuple, OutputTuple> my_node_t ype; // for forwarding | typedef join_node_base<queueing, InputTuple, OutputTuple> my_node_t ype; // for forwarding | |||
join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NU LL) { | join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NU LL) { | |||
ports_with_no_items = N; | ports_with_no_items = N; | |||
join_helper<N>::set_join_node_pointer(my_inputs, this); | join_helper<N>::set_join_node_pointer(my_inputs, this); | |||
} | } | |||
join_node_FE(const join_node_FE& other) : forwarding_base(other.my_ root_task), my_node(NULL) { | join_node_FE(const join_node_FE& other) : forwarding_base(other.my_ root_task), my_node(NULL) { | |||
skipping to change at line 730 | skipping to change at line 756 | |||
} | } | |||
// needed for forwarding | // needed for forwarding | |||
void set_my_node(my_node_type *new_my_node) { my_node = new_my_node ; } | void set_my_node(my_node_type *new_my_node) { my_node = new_my_node ; } | |||
void reset_port_count() { | void reset_port_count() { | |||
ports_with_no_items = N; | ports_with_no_items = N; | |||
} | } | |||
// if all input_ports have items, spawn forward to try and consume tuples | // if all input_ports have items, spawn forward to try and consume tuples | |||
void decrement_port_count() { | task * decrement_port_count(bool handle_task) | |||
{ | ||||
if(ports_with_no_items.fetch_and_decrement() == 1) { | if(ports_with_no_items.fetch_and_decrement() == 1) { | |||
task::enqueue( * new ( task::allocate_additional_child_of( | task *rtask = new ( task::allocate_additional_child_of( *(t | |||
*(this->my_root_task) ) ) | his->my_root_task) ) ) | |||
forward_task<my_node_type>(*my_node) ); | forward_task_bypass | |||
<my_node_type>(*my_node); | ||||
if(!handle_task) return rtask; | ||||
task::enqueue( *rtask); | ||||
} | } | |||
return NULL; | ||||
} | } | |||
void increment_port_count() { __TBB_ASSERT(false, NULL); } // shou ld never be called | void increment_port_count() { __TBB_ASSERT(false, NULL); } // shou ld never be called | |||
input_type &input_ports() { return my_inputs; } | input_type &input_ports() { return my_inputs; } | |||
protected: | protected: | |||
void reset() { | void reset() { | |||
reset_port_count(); | reset_port_count(); | |||
skipping to change at line 775 | skipping to change at line 806 | |||
} | } | |||
input_type my_inputs; | input_type my_inputs; | |||
my_node_type *my_node; | my_node_type *my_node; | |||
atomic<size_t> ports_with_no_items; | atomic<size_t> ports_with_no_items; | |||
}; | }; | |||
// tag_matching join input port. | // tag_matching join input port. | |||
template<typename InputTuple, typename OutputTuple> | template<typename InputTuple, typename OutputTuple> | |||
class join_node_FE<tag_matching, InputTuple, OutputTuple> : public forw arding_base, | class join_node_FE<tag_matching, InputTuple, OutputTuple> : public forw arding_base, | |||
// buffer of tag value counts buffer of output items | ||||
public tagged_buffer<tag_value, size_t, NO_TAG>, public item_b uffer<OutputTuple> { | public tagged_buffer<tag_value, size_t, NO_TAG>, public item_b uffer<OutputTuple> { | |||
public: | public: | |||
static const int N = std::tuple_size<OutputTuple>::value; | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
typedef InputTuple input_type; | typedef InputTuple input_type; | |||
typedef tagged_buffer<tag_value, size_t, NO_TAG> my_tag_buffer; | typedef tagged_buffer<tag_value, size_t, NO_TAG> my_tag_buffer; | |||
typedef item_buffer<output_type> output_buffer_type; | typedef item_buffer<output_type> output_buffer_type; | |||
typedef join_node_base<tag_matching, InputTuple, OutputTuple> my_no de_type; // for forwarding | typedef join_node_base<tag_matching, InputTuple, OutputTuple> my_no de_type; // for forwarding | |||
// ----------- Aggregator ------------ | // ----------- Aggregator ------------ | |||
// the aggregator is only needed to serialize the access to the has h table. | // the aggregator is only needed to serialize the access to the has h table. | |||
// and the output_buffer_type base class | // and the output_buffer_type base class | |||
private: | private: | |||
skipping to change at line 799 | skipping to change at line 831 | |||
enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |||
typedef join_node_FE<tag_matching, InputTuple, OutputTuple> my_clas s; | typedef join_node_FE<tag_matching, InputTuple, OutputTuple> my_clas s; | |||
class tag_matching_FE_operation : public aggregated_operation<tag_m atching_FE_operation> { | class tag_matching_FE_operation : public aggregated_operation<tag_m atching_FE_operation> { | |||
public: | public: | |||
char type; | char type; | |||
union { | union { | |||
tag_value my_val; | tag_value my_val; | |||
output_type* my_output; | output_type* my_output; | |||
}; | }; | |||
task *bypass_t; | ||||
bool enqueue_task; | ||||
// constructor for value parameter | // constructor for value parameter | |||
tag_matching_FE_operation(const tag_value& e, op_type t) : | tag_matching_FE_operation(const tag_value& e , bool q_task , op | |||
// type(char(t)), my_val(const_cast<T>(e)) {} | _type t) : type(char(t)), my_val(e), | |||
type(char(t)), my_val(e) {} | bypass_t(NULL), enqueue_task(q_task) {} | |||
tag_matching_FE_operation(output_type *p, op_type t) : | tag_matching_FE_operation(output_type *p, op_type t) : type(cha | |||
type(char(t)), my_output(p) {} | r(t)), my_output(p), bypass_t(NULL), | |||
enqueue_task(true) {} | ||||
// constructor with no parameter | // constructor with no parameter | |||
tag_matching_FE_operation(op_type t) : type(char(t)) {} | tag_matching_FE_operation(op_type t) : type(char(t)), bypass_t( NULL), enqueue_task(true) {} | |||
}; | }; | |||
typedef internal::aggregating_functor<my_class, tag_matching_FE_ope ration> my_handler; | typedef internal::aggregating_functor<my_class, tag_matching_FE_ope ration> my_handler; | |||
friend class internal::aggregating_functor<my_class, tag_matching_F E_operation>; | friend class internal::aggregating_functor<my_class, tag_matching_F E_operation>; | |||
aggregator<my_handler, tag_matching_FE_operation> my_aggregator; | aggregator<my_handler, tag_matching_FE_operation> my_aggregator; | |||
// called from aggregator, so serialized | // called from aggregator, so serialized | |||
void fill_output_buffer(bool should_enqueue) { | // construct as many output objects as possible. | |||
// returns a task pointer if the a task would have been enqueued bu | ||||
t we asked that | ||||
// it be returned. Otherwise returns NULL. | ||||
task * fill_output_buffer(bool should_enqueue, bool handle_task) { | ||||
output_type l_out; | output_type l_out; | |||
task *rtask = NULL; | ||||
bool do_fwd = should_enqueue && this->buffer_empty(); | bool do_fwd = should_enqueue && this->buffer_empty(); | |||
while(find_value_tag(this->current_tag,N)) { | while(find_value_tag(this->current_tag,N)) { // while there ar | |||
this->tagged_delete(this->current_tag); | e completed items | |||
this->tagged_delete(this->current_tag); // remove the tag | ||||
if(join_helper<N>::get_items(my_inputs, l_out)) { // <== call back | if(join_helper<N>::get_items(my_inputs, l_out)) { // <== call back | |||
this->push_back(l_out); | this->push_back(l_out); | |||
if(do_fwd) { | if(do_fwd) { // we enqueue if receiving an item from p | |||
task::enqueue( * new ( task::allocate_additional_ch | redecessor, not if successor asks for item | |||
ild_of( *(this->my_root_task) ) ) | rtask = new ( task::allocate_additional_child_of( * | |||
forward_task<my_node_type>(*my_node) ); | (this->my_root_task) ) ) | |||
forward_task_bypass<my_node_type>(*my_node); | ||||
if(handle_task) { | ||||
task::enqueue(*rtask); | ||||
rtask = NULL; | ||||
} | ||||
do_fwd = false; | do_fwd = false; | |||
} | } | |||
// retire the input values | // retire the input values | |||
join_helper<N>::reset_ports(my_inputs); // <== call b ack | join_helper<N>::reset_ports(my_inputs); // <== call b ack | |||
this->current_tag = NO_TAG; | this->current_tag = NO_TAG; | |||
} | } | |||
else { | else { | |||
__TBB_ASSERT(false, "should have had something to push" ); | __TBB_ASSERT(false, "should have had something to push" ); | |||
} | } | |||
} | } | |||
return rtask; | ||||
} | } | |||
void handle_operations(tag_matching_FE_operation* op_list) { | void handle_operations(tag_matching_FE_operation* op_list) { | |||
tag_matching_FE_operation *current; | tag_matching_FE_operation *current; | |||
while(op_list) { | while(op_list) { | |||
current = op_list; | current = op_list; | |||
op_list = op_list->next; | op_list = op_list->next; | |||
switch(current->type) { | switch(current->type) { | |||
case res_count: // called from BE | case res_count: // called from BE | |||
{ | { | |||
output_type l_out; | output_type l_out; | |||
this->pop_front(l_out); // don't care about return ed value. | this->pop_front(l_out); // don't care about return ed value. | |||
// buffer as many tuples as we can make | // buffer as many tuples as we can make | |||
fill_output_buffer(true); | (void)fill_output_buffer(true, true); | |||
__TBB_store_with_release(current->status, SUCCEEDED ); | __TBB_store_with_release(current->status, SUCCEEDED ); | |||
} | } | |||
break; | break; | |||
case inc_count: { // called from input ports | case inc_count: { // called from input ports | |||
size_t *p = 0; | size_t *p = 0; | |||
tag_value t = current->my_val; | tag_value t = current->my_val; | |||
bool do_enqueue = current->enqueue_task; | ||||
if(!(this->tagged_find_ref(t,p))) { | if(!(this->tagged_find_ref(t,p))) { | |||
this->tagged_insert(t, 0); | this->tagged_insert(t, 0); | |||
if(!(this->tagged_find_ref(t,p))) { | if(!(this->tagged_find_ref(t,p))) { | |||
__TBB_ASSERT(false, NULL); | __TBB_ASSERT(false, "should find tag after inserting it"); | |||
} | } | |||
} | } | |||
if(++(*p) == size_t(N)) { | if(++(*p) == size_t(N)) { | |||
task::enqueue( * new ( task::allocate_additiona | task *rtask = fill_output_buffer(true, do_enque | |||
l_child_of( *(this->my_root_task) ) ) | ue); | |||
forward_task<my_node_type>(*my_node) ); | __TBB_ASSERT(!rtask || !do_enqueue, "task shoul | |||
d not be returned"); | ||||
current->bypass_t = rtask; | ||||
} | } | |||
} | } | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
case may_succeed: // called from BE | case may_succeed: // called from BE | |||
fill_output_buffer(false); | (void)fill_output_buffer(false, /*handle_task*/true); // handle_task not used | |||
__TBB_store_with_release(current->status, this->buffer_ empty() ? FAILED : SUCCEEDED); | __TBB_store_with_release(current->status, this->buffer_ empty() ? FAILED : SUCCEEDED); | |||
break; | break; | |||
case try_make: // called from BE | case try_make: // called from BE | |||
if(this->buffer_empty()) { | if(this->buffer_empty()) { | |||
__TBB_store_with_release(current->status, FAILED); | __TBB_store_with_release(current->status, FAILED); | |||
} | } | |||
else { | else { | |||
this->fetch_front(*(current->my_output)); | this->fetch_front(*(current->my_output)); | |||
__TBB_store_with_release(current->status, SUCCEEDED ); | __TBB_store_with_release(current->status, SUCCEEDED ); | |||
} | } | |||
skipping to change at line 911 | skipping to change at line 955 | |||
// needed for forwarding | // needed for forwarding | |||
void set_my_node(my_node_type *new_my_node) { my_node = new_my_node ; } | void set_my_node(my_node_type *new_my_node) { my_node = new_my_node ; } | |||
void reset_port_count() { // called from BE | void reset_port_count() { // called from BE | |||
tag_matching_FE_operation op_data(res_count); | tag_matching_FE_operation op_data(res_count); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return; | return; | |||
} | } | |||
// if all input_ports have items, spawn forward to try and consume tuples | // if all input_ports have items, spawn forward to try and consume tuples | |||
void increment_tag_count(tag_value t) { // called from input_ports | // return a task if we are asked and did create one. | |||
tag_matching_FE_operation op_data(t, inc_count); | task *increment_tag_count(tag_value t, bool handle_task) { // call | |||
ed from input_ports | ||||
tag_matching_FE_operation op_data(t, handle_task, inc_count); | ||||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return; | return op_data.bypass_t; | |||
} | } | |||
void decrement_port_count() { __TBB_ASSERT(false, NULL); } | /*override*/ task *decrement_port_count(bool /*handle_task*/) { __T BB_ASSERT(false, NULL); return NULL; } | |||
void increment_port_count() { __TBB_ASSERT(false, NULL); } // shou ld never be called | void increment_port_count() { __TBB_ASSERT(false, NULL); } // shou ld never be called | |||
input_type &input_ports() { return my_inputs; } | input_type &input_ports() { return my_inputs; } | |||
protected: | protected: | |||
void reset() { | void reset() { | |||
// called outside of parallel contexts | // called outside of parallel contexts | |||
join_helper<N>::reset_inputs(my_inputs); | join_helper<N>::reset_inputs(my_inputs); | |||
skipping to change at line 966 | skipping to change at line 1011 | |||
} | } | |||
input_type my_inputs; // input ports | input_type my_inputs; // input ports | |||
my_node_type *my_node; | my_node_type *my_node; | |||
}; // join_node_FE<tag_matching, InputTuple, OutputTuple> | }; // join_node_FE<tag_matching, InputTuple, OutputTuple> | |||
//! join_node_base | //! join_node_base | |||
template<graph_buffer_policy JP, typename InputTuple, typename OutputTu ple> | template<graph_buffer_policy JP, typename InputTuple, typename OutputTu ple> | |||
class join_node_base : public graph_node, public join_node_FE<JP, Input Tuple, OutputTuple>, | class join_node_base : public graph_node, public join_node_FE<JP, Input Tuple, OutputTuple>, | |||
public sender<OutputTuple> { | public sender<OutputTuple> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
typedef receiver<output_type> successor_type; | typedef receiver<output_type> successor_type; | |||
typedef join_node_FE<JP, InputTuple, OutputTuple> input_ports_type; | typedef join_node_FE<JP, InputTuple, OutputTuple> input_ports_type; | |||
using input_ports_type::tuple_build_may_succeed; | using input_ports_type::tuple_build_may_succeed; | |||
using input_ports_type::try_to_make_tuple; | using input_ports_type::try_to_make_tuple; | |||
using input_ports_type::tuple_accepted; | using input_ports_type::tuple_accepted; | |||
using input_ports_type::tuple_rejected; | using input_ports_type::tuple_rejected; | |||
private: | private: | |||
// ----------- Aggregator ------------ | // ----------- Aggregator ------------ | |||
enum op_type { reg_succ, rem_succ, try__get, do_fwrd }; | enum op_type { reg_succ, rem_succ, try__get, do_fwrd, do_fwrd_bypas s }; | |||
enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |||
typedef join_node_base<JP,InputTuple,OutputTuple> my_class; | typedef join_node_base<JP,InputTuple,OutputTuple> my_class; | |||
class join_node_base_operation : public aggregated_operation<join_n ode_base_operation> { | class join_node_base_operation : public aggregated_operation<join_n ode_base_operation> { | |||
public: | public: | |||
char type; | char type; | |||
union { | union { | |||
output_type *my_arg; | output_type *my_arg; | |||
successor_type *my_succ; | successor_type *my_succ; | |||
}; | }; | |||
join_node_base_operation(const output_type& e, op_type t) : | task *bypass_t; | |||
type(char(t)), my_arg(const_cast<output_type*>(&e)) {} | join_node_base_operation(const output_type& e, op_type t) : typ | |||
e(char(t)), | ||||
my_arg(const_cast<output_type*>(&e)), bypass_t(NULL) {} | ||||
join_node_base_operation(const successor_type &s, op_type t) : type(char(t)), | join_node_base_operation(const successor_type &s, op_type t) : type(char(t)), | |||
my_succ(const_cast<successor_type *>(&s)) {} | my_succ(const_cast<successor_type *>(&s)), bypass_t(NULL) { | |||
join_node_base_operation(op_type t) : type(char(t)) {} | } | |||
join_node_base_operation(op_type t) : type(char(t)), bypass_t(N | ||||
ULL) {} | ||||
}; | }; | |||
typedef internal::aggregating_functor<my_class, join_node_base_oper ation> my_handler; | typedef internal::aggregating_functor<my_class, join_node_base_oper ation> my_handler; | |||
friend class internal::aggregating_functor<my_class, join_node_base _operation>; | friend class internal::aggregating_functor<my_class, join_node_base _operation>; | |||
bool forwarder_busy; | bool forwarder_busy; | |||
aggregator<my_handler, join_node_base_operation> my_aggregator; | aggregator<my_handler, join_node_base_operation> my_aggregator; | |||
void handle_operations(join_node_base_operation* op_list) { | void handle_operations(join_node_base_operation* op_list) { | |||
join_node_base_operation *current; | join_node_base_operation *current; | |||
while(op_list) { | while(op_list) { | |||
current = op_list; | current = op_list; | |||
op_list = op_list->next; | op_list = op_list->next; | |||
switch(current->type) { | switch(current->type) { | |||
case reg_succ: | case reg_succ: | |||
my_successors.register_successor(*(current->my_succ)); | my_successors.register_successor(*(current->my_succ)); | |||
if(tuple_build_may_succeed() && !forwarder_busy) { | if(tuple_build_may_succeed() && !forwarder_busy) { | |||
task::enqueue( * new ( task::allocate_additional_ch | task *rtask = new ( task::allocate_additional_child | |||
ild_of(*(this->my_root_task)) ) | _of(*(this->my_root_task)) ) | |||
forward_task<join_node_base<JP,InputTuple,O | forward_task_bypass | |||
utputTuple> >(*this)); | <join_node_base<JP,InputTuple,OutputTuple> | |||
>(*this); | ||||
task::enqueue(*rtask); | ||||
forwarder_busy = true; | forwarder_busy = true; | |||
} | } | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
case rem_succ: | case rem_succ: | |||
my_successors.remove_successor(*(current->my_succ)); | my_successors.remove_successor(*(current->my_succ)); | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
case try__get: | case try__get: | |||
if(tuple_build_may_succeed()) { | if(tuple_build_may_succeed()) { | |||
if(try_to_make_tuple(*(current->my_arg))) { | if(try_to_make_tuple(*(current->my_arg))) { | |||
tuple_accepted(); | tuple_accepted(); | |||
__TBB_store_with_release(current->status, SUCCE EDED); | __TBB_store_with_release(current->status, SUCCE EDED); | |||
} | } | |||
else __TBB_store_with_release(current->status, FAIL ED); | else __TBB_store_with_release(current->status, FAIL ED); | |||
} | } | |||
else __TBB_store_with_release(current->status, FAILED); | else __TBB_store_with_release(current->status, FAILED); | |||
break; | break; | |||
case do_fwrd: { | case do_fwrd_bypass: { | |||
bool build_succeeded; | bool build_succeeded; | |||
task *last_task = NULL; | ||||
output_type out; | output_type out; | |||
if(tuple_build_may_succeed()) { | if(tuple_build_may_succeed()) { | |||
do { | do { | |||
build_succeeded = try_to_make_tuple(out); | build_succeeded = try_to_make_tuple(out); | |||
if(build_succeeded) { | if(build_succeeded) { | |||
if(my_successors.try_put(out)) { | task *new_task = my_successors.try_put_ | |||
task(out); | ||||
last_task = combine_tasks(last_task, ne | ||||
w_task); | ||||
if(new_task) { | ||||
tuple_accepted(); | tuple_accepted(); | |||
} | } | |||
else { | else { | |||
tuple_rejected(); | tuple_rejected(); | |||
build_succeeded = false; | build_succeeded = false; | |||
} | } | |||
} | } | |||
} while(build_succeeded); | } while(build_succeeded); | |||
} | } | |||
current->bypass_t = last_task; | ||||
__TBB_store_with_release(current->status, SUCCEEDED ); | __TBB_store_with_release(current->status, SUCCEEDED ); | |||
forwarder_busy = false; | forwarder_busy = false; | |||
} | } | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
// ---------- end aggregator ----------- | // ---------- end aggregator ----------- | |||
public: | public: | |||
join_node_base(graph &g) : graph_node(g), input_ports_type(g), forw arder_busy(false) { | join_node_base(graph &g) : graph_node(g), input_ports_type(g), forw arder_busy(false) { | |||
skipping to change at line 1105 | skipping to change at line 1158 | |||
protected: | protected: | |||
/*override*/void reset() { | /*override*/void reset() { | |||
input_ports_type::reset(); | input_ports_type::reset(); | |||
} | } | |||
private: | private: | |||
broadcast_cache<output_type, null_rw_mutex> my_successors; | broadcast_cache<output_type, null_rw_mutex> my_successors; | |||
friend class forward_task< join_node_base<JP, InputTuple, OutputTup | friend class forward_task_bypass< join_node_base<JP, InputTuple, Ou | |||
le> >; | tputTuple> >; | |||
task *forward_task() { | ||||
void forward() { | join_node_base_operation op_data(do_fwrd_bypass); | |||
join_node_base_operation op_data(do_fwrd); | ||||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return op_data.bypass_t; | ||||
} | } | |||
}; | }; | |||
// join base class type generator | // join base class type generator | |||
template<int N, template<class> class PT, typename OutputTuple, graph_b uffer_policy JP> | template<int N, template<class> class PT, typename OutputTuple, graph_b uffer_policy JP> | |||
struct join_base { | struct join_base { | |||
typedef typename internal::join_node_base<JP, typename wrap_tuple_e lements<N,PT,OutputTuple>::type, OutputTuple> type; | typedef typename internal::join_node_base<JP, typename wrap_tuple_e lements<N,PT,OutputTuple>::type, OutputTuple> type; | |||
}; | }; | |||
//! unfolded_join_node : passes input_ports_type to join_node_base. We build the input port type | //! unfolded_join_node : passes input_ports_type to join_node_base. We build the input port type | |||
// using tuple_element. The class PT is the port type (reserving_port , queueing_port, tag_matching_port) | // using tuple_element. The class PT is the port type (reserving_port , queueing_port, tag_matching_port) | |||
skipping to change at line 1141 | skipping to change at line 1195 | |||
unfolded_join_node(graph &g) : base_type(g) {} | unfolded_join_node(graph &g) : base_type(g) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
// tag_matching unfolded_join_node. This must be a separate specializa tion because the constructors | // tag_matching unfolded_join_node. This must be a separate specializa tion because the constructors | |||
// differ. | // differ. | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<2,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<2,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<2,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<2,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<2,tag_matching_port,OutputTupl e>::type input_ports_type; | typedef typename wrap_tuple_elements<2,tag_matching_port,OutputTupl e>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename std::tuple< f0_p, f1_p > func_initializer_type; | typedef typename tbb::flow::tuple< f0_p, f1_p > func_initializer_ty pe; | |||
public: | public: | |||
template<typename B0, typename B1> | template<typename B0, typename B1> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1) : base_type(g, | unfolded_join_node(graph &g, B0 b0, B1 b1) : base_type(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) | new internal::function_body_leaf<T1, tag_value, B1>(b1) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<3,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<3,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<3,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<3,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
typedef typename std::tuple_element<2, OutputTuple>::type T2; | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<3, tag_matching_port, OutputTu ple>::type input_ports_type; | typedef typename wrap_tuple_elements<3, tag_matching_port, OutputTu ple>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename internal::function_body<T2, tag_value> *f2_p; | typedef typename internal::function_body<T2, tag_value> *f2_p; | |||
typedef typename std::tuple< f0_p, f1_p, f2_p > func_initializer_ty pe; | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p > func_initiali zer_type; | |||
public: | public: | |||
template<typename B0, typename B1, typename B2> | template<typename B0, typename B1, typename B2> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2) : base_type(g, | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2) : base_type(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) , | new internal::function_body_leaf<T1, tag_value, B1>(b1) , | |||
new internal::function_body_leaf<T2, tag_value, B2>(b2) | new internal::function_body_leaf<T2, tag_value, B2>(b2) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<4,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<4,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<4,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<4,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
typedef typename std::tuple_element<2, OutputTuple>::type T2; | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |||
typedef typename std::tuple_element<3, OutputTuple>::type T3; | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<4, tag_matching_port, OutputTu ple>::type input_ports_type; | typedef typename wrap_tuple_elements<4, tag_matching_port, OutputTu ple>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename internal::function_body<T2, tag_value> *f2_p; | typedef typename internal::function_body<T2, tag_value> *f2_p; | |||
typedef typename internal::function_body<T3, tag_value> *f3_p; | typedef typename internal::function_body<T3, tag_value> *f3_p; | |||
typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p > func_initiali zer_type; | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p > func_in itializer_type; | |||
public: | public: | |||
template<typename B0, typename B1, typename B2, typename B3> | template<typename B0, typename B1, typename B2, typename B3> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : base_typ e(g, | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : base_typ e(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) , | new internal::function_body_leaf<T1, tag_value, B1>(b1) , | |||
new internal::function_body_leaf<T2, tag_value, B2>(b2) , | new internal::function_body_leaf<T2, tag_value, B2>(b2) , | |||
new internal::function_body_leaf<T3, tag_value, B3>(b3) | new internal::function_body_leaf<T3, tag_value, B3>(b3) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<5,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<5,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<5,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<5,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
typedef typename std::tuple_element<2, OutputTuple>::type T2; | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |||
typedef typename std::tuple_element<3, OutputTuple>::type T3; | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |||
typedef typename std::tuple_element<4, OutputTuple>::type T4; | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<5, tag_matching_port, OutputTu ple>::type input_ports_type; | typedef typename wrap_tuple_elements<5, tag_matching_port, OutputTu ple>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename internal::function_body<T2, tag_value> *f2_p; | typedef typename internal::function_body<T2, tag_value> *f2_p; | |||
typedef typename internal::function_body<T3, tag_value> *f3_p; | typedef typename internal::function_body<T3, tag_value> *f3_p; | |||
typedef typename internal::function_body<T4, tag_value> *f4_p; | typedef typename internal::function_body<T4, tag_value> *f4_p; | |||
typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p > func_in itializer_type; | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p > f unc_initializer_type; | |||
public: | public: | |||
template<typename B0, typename B1, typename B2, typename B3, typena me B4> | template<typename B0, typename B1, typename B2, typename B3, typena me B4> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) : b ase_type(g, | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) : b ase_type(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) , | new internal::function_body_leaf<T1, tag_value, B1>(b1) , | |||
new internal::function_body_leaf<T2, tag_value, B2>(b2) , | new internal::function_body_leaf<T2, tag_value, B2>(b2) , | |||
new internal::function_body_leaf<T3, tag_value, B3>(b3) , | new internal::function_body_leaf<T3, tag_value, B3>(b3) , | |||
new internal::function_body_leaf<T4, tag_value, B4>(b4) | new internal::function_body_leaf<T4, tag_value, B4>(b4) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
#if __TBB_VARIADIC_MAX >= 6 | #if __TBB_VARIADIC_MAX >= 6 | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<6,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<6,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<6,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<6,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
typedef typename std::tuple_element<2, OutputTuple>::type T2; | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |||
typedef typename std::tuple_element<3, OutputTuple>::type T3; | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |||
typedef typename std::tuple_element<4, OutputTuple>::type T4; | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |||
typedef typename std::tuple_element<5, OutputTuple>::type T5; | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<6, tag_matching_port, OutputTu ple>::type input_ports_type; | typedef typename wrap_tuple_elements<6, tag_matching_port, OutputTu ple>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename internal::function_body<T2, tag_value> *f2_p; | typedef typename internal::function_body<T2, tag_value> *f2_p; | |||
typedef typename internal::function_body<T3, tag_value> *f3_p; | typedef typename internal::function_body<T3, tag_value> *f3_p; | |||
typedef typename internal::function_body<T4, tag_value> *f4_p; | typedef typename internal::function_body<T4, tag_value> *f4_p; | |||
typedef typename internal::function_body<T5, tag_value> *f5_p; | typedef typename internal::function_body<T5, tag_value> *f5_p; | |||
typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p > f unc_initializer_type; | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5 _p > func_initializer_type; | |||
public: | public: | |||
template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5> | template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5) : base_type(g, | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5) : base_type(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) , | new internal::function_body_leaf<T1, tag_value, B1>(b1) , | |||
new internal::function_body_leaf<T2, tag_value, B2>(b2) , | new internal::function_body_leaf<T2, tag_value, B2>(b2) , | |||
new internal::function_body_leaf<T3, tag_value, B3>(b3) , | new internal::function_body_leaf<T3, tag_value, B3>(b3) , | |||
new internal::function_body_leaf<T4, tag_value, B4>(b4) , | new internal::function_body_leaf<T4, tag_value, B4>(b4) , | |||
new internal::function_body_leaf<T5, tag_value, B5>(b5) | new internal::function_body_leaf<T5, tag_value, B5>(b5) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
#endif | #endif | |||
#if __TBB_VARIADIC_MAX >= 7 | #if __TBB_VARIADIC_MAX >= 7 | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<7,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<7,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<7,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<7,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
typedef typename std::tuple_element<2, OutputTuple>::type T2; | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |||
typedef typename std::tuple_element<3, OutputTuple>::type T3; | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |||
typedef typename std::tuple_element<4, OutputTuple>::type T4; | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |||
typedef typename std::tuple_element<5, OutputTuple>::type T5; | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |||
typedef typename std::tuple_element<6, OutputTuple>::type T6; | typedef typename tbb::flow::tuple_element<6, OutputTuple>::type T6; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<7, tag_matching_port, OutputTu ple>::type input_ports_type; | typedef typename wrap_tuple_elements<7, tag_matching_port, OutputTu ple>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename internal::function_body<T2, tag_value> *f2_p; | typedef typename internal::function_body<T2, tag_value> *f2_p; | |||
typedef typename internal::function_body<T3, tag_value> *f3_p; | typedef typename internal::function_body<T3, tag_value> *f3_p; | |||
typedef typename internal::function_body<T4, tag_value> *f4_p; | typedef typename internal::function_body<T4, tag_value> *f4_p; | |||
typedef typename internal::function_body<T5, tag_value> *f5_p; | typedef typename internal::function_body<T5, tag_value> *f5_p; | |||
typedef typename internal::function_body<T6, tag_value> *f6_p; | typedef typename internal::function_body<T6, tag_value> *f6_p; | |||
typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p, f6 _p > func_initializer_type; | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5 _p, f6_p > func_initializer_type; | |||
public: | public: | |||
template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5, typename B6> | template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5, typename B6> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6) : base_type(g, | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6) : base_type(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) , | new internal::function_body_leaf<T1, tag_value, B1>(b1) , | |||
new internal::function_body_leaf<T2, tag_value, B2>(b2) , | new internal::function_body_leaf<T2, tag_value, B2>(b2) , | |||
new internal::function_body_leaf<T3, tag_value, B3>(b3) , | new internal::function_body_leaf<T3, tag_value, B3>(b3) , | |||
new internal::function_body_leaf<T4, tag_value, B4>(b4) , | new internal::function_body_leaf<T4, tag_value, B4>(b4) , | |||
new internal::function_body_leaf<T5, tag_value, B5>(b5) , | new internal::function_body_leaf<T5, tag_value, B5>(b5) , | |||
new internal::function_body_leaf<T6, tag_value, B6>(b6) | new internal::function_body_leaf<T6, tag_value, B6>(b6) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
#endif | #endif | |||
#if __TBB_VARIADIC_MAX >= 8 | #if __TBB_VARIADIC_MAX >= 8 | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<8,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<8,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<8,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<8,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
typedef typename std::tuple_element<2, OutputTuple>::type T2; | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |||
typedef typename std::tuple_element<3, OutputTuple>::type T3; | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |||
typedef typename std::tuple_element<4, OutputTuple>::type T4; | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |||
typedef typename std::tuple_element<5, OutputTuple>::type T5; | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |||
typedef typename std::tuple_element<6, OutputTuple>::type T6; | typedef typename tbb::flow::tuple_element<6, OutputTuple>::type T6; | |||
typedef typename std::tuple_element<7, OutputTuple>::type T7; | typedef typename tbb::flow::tuple_element<7, OutputTuple>::type T7; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<8, tag_matching_port, OutputTu ple>::type input_ports_type; | typedef typename wrap_tuple_elements<8, tag_matching_port, OutputTu ple>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename internal::function_body<T2, tag_value> *f2_p; | typedef typename internal::function_body<T2, tag_value> *f2_p; | |||
typedef typename internal::function_body<T3, tag_value> *f3_p; | typedef typename internal::function_body<T3, tag_value> *f3_p; | |||
typedef typename internal::function_body<T4, tag_value> *f4_p; | typedef typename internal::function_body<T4, tag_value> *f4_p; | |||
typedef typename internal::function_body<T5, tag_value> *f5_p; | typedef typename internal::function_body<T5, tag_value> *f5_p; | |||
typedef typename internal::function_body<T6, tag_value> *f6_p; | typedef typename internal::function_body<T6, tag_value> *f6_p; | |||
typedef typename internal::function_body<T7, tag_value> *f7_p; | typedef typename internal::function_body<T7, tag_value> *f7_p; | |||
typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p, f6 _p, f7_p > func_initializer_type; | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5 _p, f6_p, f7_p > func_initializer_type; | |||
public: | public: | |||
template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5, typename B6, typename B7> | template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5, typename B6, typename B7> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7) : base_type(g, | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7) : base_type(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) , | new internal::function_body_leaf<T1, tag_value, B1>(b1) , | |||
new internal::function_body_leaf<T2, tag_value, B2>(b2) , | new internal::function_body_leaf<T2, tag_value, B2>(b2) , | |||
new internal::function_body_leaf<T3, tag_value, B3>(b3) , | new internal::function_body_leaf<T3, tag_value, B3>(b3) , | |||
new internal::function_body_leaf<T4, tag_value, B4>(b4) , | new internal::function_body_leaf<T4, tag_value, B4>(b4) , | |||
new internal::function_body_leaf<T5, tag_value, B5>(b5) , | new internal::function_body_leaf<T5, tag_value, B5>(b5) , | |||
skipping to change at line 1372 | skipping to change at line 1426 | |||
new internal::function_body_leaf<T7, tag_value, B7>(b7) | new internal::function_body_leaf<T7, tag_value, B7>(b7) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
#endif | #endif | |||
#if __TBB_VARIADIC_MAX >= 9 | #if __TBB_VARIADIC_MAX >= 9 | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<9,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<9,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<9,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<9,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
typedef typename std::tuple_element<2, OutputTuple>::type T2; | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |||
typedef typename std::tuple_element<3, OutputTuple>::type T3; | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |||
typedef typename std::tuple_element<4, OutputTuple>::type T4; | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |||
typedef typename std::tuple_element<5, OutputTuple>::type T5; | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |||
typedef typename std::tuple_element<6, OutputTuple>::type T6; | typedef typename tbb::flow::tuple_element<6, OutputTuple>::type T6; | |||
typedef typename std::tuple_element<7, OutputTuple>::type T7; | typedef typename tbb::flow::tuple_element<7, OutputTuple>::type T7; | |||
typedef typename std::tuple_element<8, OutputTuple>::type T8; | typedef typename tbb::flow::tuple_element<8, OutputTuple>::type T8; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<9, tag_matching_port, OutputTu ple>::type input_ports_type; | typedef typename wrap_tuple_elements<9, tag_matching_port, OutputTu ple>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename internal::function_body<T2, tag_value> *f2_p; | typedef typename internal::function_body<T2, tag_value> *f2_p; | |||
typedef typename internal::function_body<T3, tag_value> *f3_p; | typedef typename internal::function_body<T3, tag_value> *f3_p; | |||
typedef typename internal::function_body<T4, tag_value> *f4_p; | typedef typename internal::function_body<T4, tag_value> *f4_p; | |||
typedef typename internal::function_body<T5, tag_value> *f5_p; | typedef typename internal::function_body<T5, tag_value> *f5_p; | |||
typedef typename internal::function_body<T6, tag_value> *f6_p; | typedef typename internal::function_body<T6, tag_value> *f6_p; | |||
typedef typename internal::function_body<T7, tag_value> *f7_p; | typedef typename internal::function_body<T7, tag_value> *f7_p; | |||
typedef typename internal::function_body<T8, tag_value> *f8_p; | typedef typename internal::function_body<T8, tag_value> *f8_p; | |||
typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p, f6 _p, f7_p, f8_p > func_initializer_type; | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5 _p, f6_p, f7_p, f8_p > func_initializer_type; | |||
public: | public: | |||
template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5, typename B6, typename B7, typename B8> | template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5, typename B6, typename B7, typename B8> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7, B8 b8) : base_type(g, | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7, B8 b8) : base_type(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) , | new internal::function_body_leaf<T1, tag_value, B1>(b1) , | |||
new internal::function_body_leaf<T2, tag_value, B2>(b2) , | new internal::function_body_leaf<T2, tag_value, B2>(b2) , | |||
new internal::function_body_leaf<T3, tag_value, B3>(b3) , | new internal::function_body_leaf<T3, tag_value, B3>(b3) , | |||
new internal::function_body_leaf<T4, tag_value, B4>(b4) , | new internal::function_body_leaf<T4, tag_value, B4>(b4) , | |||
new internal::function_body_leaf<T5, tag_value, B5>(b5) , | new internal::function_body_leaf<T5, tag_value, B5>(b5) , | |||
skipping to change at line 1418 | skipping to change at line 1472 | |||
new internal::function_body_leaf<T8, tag_value, B8>(b8) | new internal::function_body_leaf<T8, tag_value, B8>(b8) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
#endif | #endif | |||
#if __TBB_VARIADIC_MAX >= 10 | #if __TBB_VARIADIC_MAX >= 10 | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class unfolded_join_node<10,tag_matching_port,OutputTuple,tag_matching> : public | class unfolded_join_node<10,tag_matching_port,OutputTuple,tag_matching> : public | |||
join_base<10,tag_matching_port,OutputTuple,tag_matching>::type { | join_base<10,tag_matching_port,OutputTuple,tag_matching>::type { | |||
typedef typename std::tuple_element<0, OutputTuple>::type T0; | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |||
typedef typename std::tuple_element<1, OutputTuple>::type T1; | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |||
typedef typename std::tuple_element<2, OutputTuple>::type T2; | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |||
typedef typename std::tuple_element<3, OutputTuple>::type T3; | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |||
typedef typename std::tuple_element<4, OutputTuple>::type T4; | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |||
typedef typename std::tuple_element<5, OutputTuple>::type T5; | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |||
typedef typename std::tuple_element<6, OutputTuple>::type T6; | typedef typename tbb::flow::tuple_element<6, OutputTuple>::type T6; | |||
typedef typename std::tuple_element<7, OutputTuple>::type T7; | typedef typename tbb::flow::tuple_element<7, OutputTuple>::type T7; | |||
typedef typename std::tuple_element<8, OutputTuple>::type T8; | typedef typename tbb::flow::tuple_element<8, OutputTuple>::type T8; | |||
typedef typename std::tuple_element<9, OutputTuple>::type T9; | typedef typename tbb::flow::tuple_element<9, OutputTuple>::type T9; | |||
public: | public: | |||
typedef typename wrap_tuple_elements<10, tag_matching_port, OutputT uple>::type input_ports_type; | typedef typename wrap_tuple_elements<10, tag_matching_port, OutputT uple>::type input_ports_type; | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
private: | private: | |||
typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | typedef join_node_base<tag_matching, input_ports_type, output_type > base_type; | |||
typedef typename internal::function_body<T0, tag_value> *f0_p; | typedef typename internal::function_body<T0, tag_value> *f0_p; | |||
typedef typename internal::function_body<T1, tag_value> *f1_p; | typedef typename internal::function_body<T1, tag_value> *f1_p; | |||
typedef typename internal::function_body<T2, tag_value> *f2_p; | typedef typename internal::function_body<T2, tag_value> *f2_p; | |||
typedef typename internal::function_body<T3, tag_value> *f3_p; | typedef typename internal::function_body<T3, tag_value> *f3_p; | |||
typedef typename internal::function_body<T4, tag_value> *f4_p; | typedef typename internal::function_body<T4, tag_value> *f4_p; | |||
typedef typename internal::function_body<T5, tag_value> *f5_p; | typedef typename internal::function_body<T5, tag_value> *f5_p; | |||
typedef typename internal::function_body<T6, tag_value> *f6_p; | typedef typename internal::function_body<T6, tag_value> *f6_p; | |||
typedef typename internal::function_body<T7, tag_value> *f7_p; | typedef typename internal::function_body<T7, tag_value> *f7_p; | |||
typedef typename internal::function_body<T8, tag_value> *f8_p; | typedef typename internal::function_body<T8, tag_value> *f8_p; | |||
typedef typename internal::function_body<T9, tag_value> *f9_p; | typedef typename internal::function_body<T9, tag_value> *f9_p; | |||
typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p, f6 _p, f7_p, f8_p, f9_p > func_initializer_type; | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5 _p, f6_p, f7_p, f8_p, f9_p > func_initializer_type; | |||
public: | public: | |||
template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5, typename B6, typename B7, typename B8, typename B9> | template<typename B0, typename B1, typename B2, typename B3, typena me B4, typename B5, typename B6, typename B7, typename B8, typename B9> | |||
unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7, B8 b8, B9 b9) : base_type(g, | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7, B8 b8, B9 b9) : base_type(g, | |||
func_initializer_type( | func_initializer_type( | |||
new internal::function_body_leaf<T0, tag_value, B0>(b0) , | new internal::function_body_leaf<T0, tag_value, B0>(b0) , | |||
new internal::function_body_leaf<T1, tag_value, B1>(b1) , | new internal::function_body_leaf<T1, tag_value, B1>(b1) , | |||
new internal::function_body_leaf<T2, tag_value, B2>(b2) , | new internal::function_body_leaf<T2, tag_value, B2>(b2) , | |||
new internal::function_body_leaf<T3, tag_value, B3>(b3) , | new internal::function_body_leaf<T3, tag_value, B3>(b3) , | |||
new internal::function_body_leaf<T4, tag_value, B4>(b4) , | new internal::function_body_leaf<T4, tag_value, B4>(b4) , | |||
new internal::function_body_leaf<T5, tag_value, B5>(b5) , | new internal::function_body_leaf<T5, tag_value, B5>(b5) , | |||
skipping to change at line 1465 | skipping to change at line 1519 | |||
new internal::function_body_leaf<T7, tag_value, B7>(b7) , | new internal::function_body_leaf<T7, tag_value, B7>(b7) , | |||
new internal::function_body_leaf<T8, tag_value, B8>(b8) , | new internal::function_body_leaf<T8, tag_value, B8>(b8) , | |||
new internal::function_body_leaf<T9, tag_value, B9>(b9) | new internal::function_body_leaf<T9, tag_value, B9>(b9) | |||
) ) {} | ) ) {} | |||
unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | unfolded_join_node(const unfolded_join_node &other) : base_type(oth er) {} | |||
}; | }; | |||
#endif | #endif | |||
//! templated function to refer to input ports of the join node | //! templated function to refer to input ports of the join node | |||
template<size_t N, typename JNT> | template<size_t N, typename JNT> | |||
typename std::tuple_element<N, typename JNT::input_ports_type>::type &i | typename tbb::flow::tuple_element<N, typename JNT::input_ports_type>::t | |||
nput_port(JNT &jn) { | ype &input_port(JNT &jn) { | |||
return std::get<N>(jn.input_ports()); | return tbb::flow::get<N>(jn.input_ports()); | |||
} | } | |||
} | } | |||
#endif // __TBB__flow_graph_join_impl_H | #endif // __TBB__flow_graph_join_impl_H | |||
End of changes. 92 change blocks. | ||||
199 lines changed or deleted | 270 lines changed or added | |||
_flow_graph_node_impl.h | _flow_graph_node_impl.h | |||
---|---|---|---|---|
skipping to change at line 64 | skipping to change at line 64 | |||
} | } | |||
}; | }; | |||
//! Input and scheduling for a function node that takes a type Input as input | //! Input and scheduling for a function node that takes a type Input as input | |||
// The only up-ref is apply_body_impl, which should implement the func tion | // The only up-ref is apply_body_impl, which should implement the func tion | |||
// call and any handling of the result. | // call and any handling of the result. | |||
template< typename Input, typename A, typename ImplType > | template< typename Input, typename A, typename ImplType > | |||
class function_input_base : public receiver<Input>, tbb::internal::no_a ssign { | class function_input_base : public receiver<Input>, tbb::internal::no_a ssign { | |||
typedef sender<Input> predecessor_type; | typedef sender<Input> predecessor_type; | |||
enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |||
enum op_type {reg_pred, rem_pred, app_body, tryput, try_fwd}; | enum op_type {reg_pred, rem_pred, app_body, try_fwd, tryput_bypass, app_body_bypass }; | |||
typedef function_input_base<Input, A, ImplType> my_class; | typedef function_input_base<Input, A, ImplType> my_class; | |||
public: | public: | |||
//! The input type of this receiver | //! The input type of this receiver | |||
typedef Input input_type; | typedef Input input_type; | |||
//! Constructor for function_input_base | //! Constructor for function_input_base | |||
function_input_base( graph &g, size_t max_concurrency, function_inp ut_queue<input_type,A> *q = NULL ) | function_input_base( graph &g, size_t max_concurrency, function_inp ut_queue<input_type,A> *q = NULL ) | |||
: my_root_task(g.root_task()), my_max_concurrency(max_concurren cy), my_concurrency(0), | : my_root_task(g.root_task()), my_max_concurrency(max_concurren cy), my_concurrency(0), | |||
skipping to change at line 95 | skipping to change at line 95 | |||
{ | { | |||
my_predecessors.set_owner(this); | my_predecessors.set_owner(this); | |||
my_aggregator.initialize_handler(my_handler(this)); | my_aggregator.initialize_handler(my_handler(this)); | |||
} | } | |||
//! Destructor | //! Destructor | |||
virtual ~function_input_base() { | virtual ~function_input_base() { | |||
if ( my_queue ) delete my_queue; | if ( my_queue ) delete my_queue; | |||
} | } | |||
//! Put to the node | //! Put to the node, returning a task if available | |||
virtual bool try_put( const input_type &t ) { | virtual task * try_put_task( const input_type &t ) { | |||
if ( my_max_concurrency == 0 ) { | if ( my_max_concurrency == 0 ) { | |||
spawn_body_task( t ); | return create_body_task( t ); | |||
return true; | ||||
} else { | } else { | |||
my_operation op_data(t, tryput); | my_operation op_data(t, tryput_bypass); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return op_data.status == SUCCEEDED; | if(op_data.status == SUCCEEDED ) { | |||
return op_data.bypass_t; | ||||
} | ||||
return NULL; | ||||
} | } | |||
} | } | |||
//! Adds src to the list of cached predecessors. | //! Adds src to the list of cached predecessors. | |||
/* override */ bool register_predecessor( predecessor_type &src ) { | /* override */ bool register_predecessor( predecessor_type &src ) { | |||
my_operation op_data(reg_pred); | my_operation op_data(reg_pred); | |||
op_data.r = &src; | op_data.r = &src; | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return true; | return true; | |||
} | } | |||
skipping to change at line 145 | skipping to change at line 147 | |||
size_t my_concurrency; | size_t my_concurrency; | |||
function_input_queue<input_type, A> *my_queue; | function_input_queue<input_type, A> *my_queue; | |||
predecessor_cache<input_type, null_mutex > my_predecessors; | predecessor_cache<input_type, null_mutex > my_predecessors; | |||
/*override*/void reset_receiver() { | /*override*/void reset_receiver() { | |||
my_predecessors.reset(); | my_predecessors.reset(); | |||
} | } | |||
private: | private: | |||
friend class apply_body_task< my_class, input_type >; | friend class apply_body_task_bypass< my_class, input_type >; | |||
friend class forward_task< my_class >; | friend class forward_task_bypass< my_class >; | |||
class my_operation : public aggregated_operation< my_operation > { | class my_operation : public aggregated_operation< my_operation > { | |||
public: | public: | |||
char type; | char type; | |||
union { | union { | |||
input_type *elem; | input_type *elem; | |||
predecessor_type *r; | predecessor_type *r; | |||
}; | }; | |||
tbb::task *bypass_t; | ||||
my_operation(const input_type& e, op_type t) : | my_operation(const input_type& e, op_type t) : | |||
type(char(t)), elem(const_cast<input_type*>(&e)) {} | type(char(t)), elem(const_cast<input_type*>(&e)) {} | |||
my_operation(op_type t) : type(char(t)), r(NULL) {} | my_operation(op_type t) : type(char(t)), r(NULL) {} | |||
}; | }; | |||
bool forwarder_busy; | bool forwarder_busy; | |||
typedef internal::aggregating_functor<my_class, my_operation> my_ha ndler; | typedef internal::aggregating_functor<my_class, my_operation> my_ha ndler; | |||
friend class internal::aggregating_functor<my_class, my_operation>; | friend class internal::aggregating_functor<my_class, my_operation>; | |||
aggregator< my_handler, my_operation > my_aggregator; | aggregator< my_handler, my_operation > my_aggregator; | |||
skipping to change at line 200 | skipping to change at line 203 | |||
if ( my_queue ) | if ( my_queue ) | |||
item_was_retrieved = my_queue->pop(i); | item_was_retrieved = my_queue->pop(i); | |||
else | else | |||
item_was_retrieved = my_predecessors.get_item(i ); | item_was_retrieved = my_predecessors.get_item(i ); | |||
if (item_was_retrieved) { | if (item_was_retrieved) { | |||
++my_concurrency; | ++my_concurrency; | |||
spawn_body_task(i); | spawn_body_task(i); | |||
} | } | |||
} | } | |||
break; | break; | |||
case tryput: internal_try_put(tmp); break; | case app_body_bypass: { | |||
task * new_task = NULL; | ||||
__TBB_ASSERT(my_max_concurrency != 0, NULL); | ||||
--my_concurrency; | ||||
if (my_concurrency<my_max_concurrency) { | ||||
input_type i; | ||||
bool item_was_retrieved = false; | ||||
if ( my_queue ) | ||||
item_was_retrieved = my_queue->pop(i); | ||||
else | ||||
item_was_retrieved = my_predecessors.get_it | ||||
em(i); | ||||
if (item_was_retrieved) { | ||||
++my_concurrency; | ||||
new_task = create_body_task(i); | ||||
} | ||||
} | ||||
tmp->bypass_t = new_task; | ||||
__TBB_store_with_release(tmp->status, SUCCEEDED); | ||||
} | ||||
break; | ||||
case tryput_bypass: internal_try_put_task(tmp); break; | ||||
case try_fwd: internal_forward(tmp); break; | case try_fwd: internal_forward(tmp); break; | |||
} | } | |||
} | } | |||
} | } | |||
//! Put to the node | //! Put to the node, but return the task instead of enqueueing it | |||
void internal_try_put(my_operation *op) { | void internal_try_put_task(my_operation *op) { | |||
__TBB_ASSERT(my_max_concurrency != 0, NULL); | __TBB_ASSERT(my_max_concurrency != 0, NULL); | |||
if (my_concurrency < my_max_concurrency) { | if (my_concurrency < my_max_concurrency) { | |||
++my_concurrency; | ++my_concurrency; | |||
spawn_body_task(*(op->elem)); | task * new_task = create_body_task(*(op->elem)); | |||
op->bypass_t = new_task; | ||||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
} else if ( my_queue && my_queue->push(*(op->elem)) ) { | } else if ( my_queue && my_queue->push(*(op->elem)) ) { | |||
op->bypass_t = SUCCESSFULLY_ENQUEUED; | ||||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
} else { | } else { | |||
op->bypass_t = NULL; | ||||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
} | } | |||
} | } | |||
//! Tries to spawn bodies if available and if concurrency allows | //! Tries to spawn bodies if available and if concurrency allows | |||
void internal_forward(my_operation *op) { | void internal_forward(my_operation *op) { | |||
op->bypass_t = NULL; | ||||
if (my_concurrency<my_max_concurrency || !my_max_concurrency) { | if (my_concurrency<my_max_concurrency || !my_max_concurrency) { | |||
input_type i; | input_type i; | |||
bool item_was_retrieved = false; | bool item_was_retrieved = false; | |||
if ( my_queue ) | if ( my_queue ) | |||
item_was_retrieved = my_queue->pop(i); | item_was_retrieved = my_queue->pop(i); | |||
else | else | |||
item_was_retrieved = my_predecessors.get_item(i); | item_was_retrieved = my_predecessors.get_item(i); | |||
if (item_was_retrieved) { | if (item_was_retrieved) { | |||
++my_concurrency; | ++my_concurrency; | |||
op->bypass_t = create_body_task(i); | ||||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
spawn_body_task(i); | ||||
return; | return; | |||
} | } | |||
} | } | |||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
forwarder_busy = false; | forwarder_busy = false; | |||
} | } | |||
//! Applies the body to the provided input | //! Applies the body to the provided input | |||
// then decides if more work is available | ||||
void apply_body( input_type &i ) { | void apply_body( input_type &i ) { | |||
static_cast<ImplType *>(this)->apply_body_impl(i); | task *new_task = apply_body_bypass(i); | |||
if(!new_task) return; | ||||
if(new_task == SUCCESSFULLY_ENQUEUED) return; | ||||
task::enqueue(*new_task); | ||||
return; | ||||
} | ||||
//! Applies the body to the provided input | ||||
// then decides if more work is available | ||||
// we should still be able to use app_body, because the task retur | ||||
ned should be the successor node | ||||
// and not us, so we are reducing my_concurrency. (might be a pro | ||||
blem if we are our own successor?) | ||||
task * apply_body_bypass( input_type &i ) { | ||||
task * new_task = static_cast<ImplType *>(this)->apply_body_imp | ||||
l_bypass(i); | ||||
if ( my_max_concurrency != 0 ) { | if ( my_max_concurrency != 0 ) { | |||
my_operation op_data(app_body); | my_operation op_data(app_body_bypass); // tries to pop an item or get_item, enqueues another apply_body | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
tbb::task *ttask = op_data.bypass_t; | ||||
new_task = combine_tasks(new_task, ttask); | ||||
} | } | |||
return new_task; | ||||
} | } | |||
//! allocates a task to call apply_body( input ) | ||||
inline task * create_body_task( const input_type &input ) { | ||||
return new(task::allocate_additional_child_of(*my_root_task)) | ||||
apply_body_task_bypass < my_class, input_type >(*this, input | ||||
); | ||||
} | ||||
//! Spawns a task that calls apply_body( input ) | //! Spawns a task that calls apply_body( input ) | |||
inline void spawn_body_task( const input_type &input ) { | inline void spawn_body_task( const input_type &input ) { | |||
task::enqueue(*new(task::allocate_additional_child_of(*my_root_t ask)) apply_body_task< my_class, input_type >(*this, input)); | task::enqueue(*create_body_task(input)); | |||
} | } | |||
//! This is executed by an enqueued task, the "forwarder" | //! This is executed by an enqueued task, the "forwarder" | |||
void forward() { | task *forward_task() { | |||
my_operation op_data(try_fwd); | my_operation op_data(try_fwd); | |||
task *rval = NULL; | ||||
do { | do { | |||
op_data.status = WAIT; | op_data.status = WAIT; | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
if(op_data.status == SUCCEEDED) { | ||||
tbb::task *ttask = op_data.bypass_t; | ||||
rval = combine_tasks(rval, ttask); | ||||
} | ||||
} while (op_data.status == SUCCEEDED); | } while (op_data.status == SUCCEEDED); | |||
return rval; | ||||
} | ||||
inline task *create_forward_task() { | ||||
task *rval = new(task::allocate_additional_child_of(*my_root_tas | ||||
k)) forward_task_bypass< my_class >(*this); | ||||
return rval; | ||||
} | } | |||
//! Spawns a task that calls forward() | //! Spawns a task that calls forward() | |||
inline void spawn_forward_task() { | inline void spawn_forward_task() { | |||
task::enqueue(*new(task::allocate_additional_child_of(*my_root_t ask)) forward_task< my_class >(*this)); | task::enqueue(*create_forward_task()); | |||
} | } | |||
}; // function_input_base | }; // function_input_base | |||
//! Implements methods for a function node that takes a type Input as i nput and sends | //! Implements methods for a function node that takes a type Input as i nput and sends | |||
// a type Output to its successors. | // a type Output to its successors. | |||
template< typename Input, typename Output, typename A> | template< typename Input, typename Output, typename A> | |||
class function_input : public function_input_base<Input, A, function_in put<Input,Output,A> > { | class function_input : public function_input_base<Input, A, function_in put<Input,Output,A> > { | |||
public: | public: | |||
typedef Input input_type; | typedef Input input_type; | |||
typedef Output output_type; | typedef Output output_type; | |||
skipping to change at line 303 | skipping to change at line 363 | |||
~function_input() { | ~function_input() { | |||
delete my_body; | delete my_body; | |||
} | } | |||
template< typename Body > | template< typename Body > | |||
Body copy_function_object() { | Body copy_function_object() { | |||
internal::function_body<input_type, output_type> &body_ref = *t his->my_body; | internal::function_body<input_type, output_type> &body_ref = *t his->my_body; | |||
return dynamic_cast< internal::function_body_leaf<input_type, o utput_type, Body> & >(body_ref).get_body(); | return dynamic_cast< internal::function_body_leaf<input_type, o utput_type, Body> & >(body_ref).get_body(); | |||
} | } | |||
void apply_body_impl( const input_type &i) { | task * apply_body_impl_bypass( const input_type &i) { | |||
successors().try_put( (*my_body)(i) ); | task * new_task = successors().try_put_task( (*my_body)(i) ); | |||
return new_task; | ||||
} | } | |||
protected: | protected: | |||
void reset_function_input() { | void reset_function_input() { | |||
base_type::reset_function_input_base(); | base_type::reset_function_input_base(); | |||
} | } | |||
function_body<input_type, output_type> *my_body; | function_body<input_type, output_type> *my_body; | |||
virtual broadcast_cache<output_type > &successors() = 0; | virtual broadcast_cache<output_type > &successors() = 0; | |||
skipping to change at line 356 | skipping to change at line 417 | |||
~multifunction_input() { | ~multifunction_input() { | |||
delete my_body; | delete my_body; | |||
} | } | |||
template< typename Body > | template< typename Body > | |||
Body copy_function_object() { | Body copy_function_object() { | |||
internal::multifunction_body<input_type, output_ports_type> &bo dy_ref = *this->my_body; | internal::multifunction_body<input_type, output_ports_type> &bo dy_ref = *this->my_body; | |||
return dynamic_cast< internal::multifunction_body_leaf<input_ty pe, output_ports_type, Body> & >(body_ref).get_body(); | return dynamic_cast< internal::multifunction_body_leaf<input_ty pe, output_ports_type, Body> & >(body_ref).get_body(); | |||
} | } | |||
void apply_body_impl( const input_type &i) { | // for multifunction nodes we do not have a single successor as suc | |||
h. So we just tell | ||||
// the task we were successful. | ||||
task * apply_body_impl_bypass( const input_type &i) { | ||||
(*my_body)(i, my_output_ports); | (*my_body)(i, my_output_ports); | |||
task * new_task = SUCCESSFULLY_ENQUEUED; | ||||
return new_task; | ||||
} | } | |||
output_ports_type &output_ports(){ return my_output_ports; } | output_ports_type &output_ports(){ return my_output_ports; } | |||
protected: | protected: | |||
void reset() { | void reset() { | |||
base_type::reset_function_input_base(); | base_type::reset_function_input_base(); | |||
} | } | |||
multifunction_body<input_type, output_ports_type> *my_body; | multifunction_body<input_type, output_ports_type> *my_body; | |||
output_ports_type my_output_ports; | output_ports_type my_output_ports; | |||
}; | }; | |||
// template to refer to an output port of a multifunction_node | // template to refer to an output port of a multifunction_node | |||
template<size_t N, typename MOP> | template<size_t N, typename MOP> | |||
typename std::tuple_element<N, typename MOP::output_ports_type>::type & | typename tbb::flow::tuple_element<N, typename MOP::output_ports_type>:: | |||
output_port(MOP &op) { | type &output_port(MOP &op) { | |||
return std::get<N>(op.output_ports()); | return tbb::flow::get<N>(op.output_ports()); | |||
} | } | |||
// helper structs for split_node | // helper structs for split_node | |||
template<int N> | template<int N> | |||
struct emit_element { | struct emit_element { | |||
template<typename T, typename P> | template<typename T, typename P> | |||
static void emit_this(const T &t, P &p) { | static void emit_this(const T &t, P &p) { | |||
(void)std::get<N-1>(p).try_put(std::get<N-1>(t)); | (void)tbb::flow::get<N-1>(p).try_put(tbb::flow::get<N-1>(t)); | |||
emit_element<N-1>::emit_this(t,p); | emit_element<N-1>::emit_this(t,p); | |||
} | } | |||
}; | }; | |||
template<> | template<> | |||
struct emit_element<1> { | struct emit_element<1> { | |||
template<typename T, typename P> | template<typename T, typename P> | |||
static void emit_this(const T &t, P &p) { | static void emit_this(const T &t, P &p) { | |||
(void)std::get<0>(p).try_put(std::get<0>(t)); | (void)tbb::flow::get<0>(p).try_put(tbb::flow::get<0>(t)); | |||
} | } | |||
}; | }; | |||
//! Implements methods for an executable node that takes continue_msg a s input | //! Implements methods for an executable node that takes continue_msg a s input | |||
template< typename Output > | template< typename Output > | |||
class continue_input : public continue_receiver { | class continue_input : public continue_receiver { | |||
public: | public: | |||
//! The input type of this receiver | //! The input type of this receiver | |||
typedef continue_msg input_type; | typedef continue_msg input_type; | |||
skipping to change at line 434 | skipping to change at line 499 | |||
return dynamic_cast< internal::function_body_leaf<input_type, o utput_type, Body> & >(body_ref).get_body(); | return dynamic_cast< internal::function_body_leaf<input_type, o utput_type, Body> & >(body_ref).get_body(); | |||
} | } | |||
protected: | protected: | |||
task *my_root_task; | task *my_root_task; | |||
function_body<input_type, output_type> *my_body; | function_body<input_type, output_type> *my_body; | |||
virtual broadcast_cache<output_type > &successors() = 0; | virtual broadcast_cache<output_type > &successors() = 0; | |||
friend class apply_body_task< continue_input< Output >, continue_ms g >; | friend class apply_body_task_bypass< continue_input< Output >, cont inue_msg >; | |||
//! Applies the body to the provided input | //! Applies the body to the provided input | |||
/* override */ void apply_body( input_type ) { | /* override */ task *apply_body_bypass( input_type ) { | |||
successors().try_put( (*my_body)( continue_msg() ) ); | return successors().try_put_task( (*my_body)( continue_msg() ) | |||
); | ||||
} | } | |||
//! Spawns a task that applies the body | //! Spawns a task that applies the body | |||
/* override */ void execute( ) { | /* override */ task *execute( ) { | |||
task::enqueue( * new ( task::allocate_additional_child_of( *my_ | task *res = new ( task::allocate_additional_child_of( *my_root_ | |||
root_task ) ) | task ) ) | |||
apply_body_task< continue_input< Output >, continue_msg >( * | apply_body_task_bypass< continue_input< Output >, continue_ | |||
this, continue_msg() ) ); | msg >( *this, continue_msg() ); | |||
return res; | ||||
} | } | |||
}; | }; | |||
//! Implements methods for both executable and function nodes that puts Output to its successors | //! Implements methods for both executable and function nodes that puts Output to its successors | |||
template< typename Output > | template< typename Output > | |||
class function_output : public sender<Output> { | class function_output : public sender<Output> { | |||
public: | public: | |||
typedef Output output_type; | typedef Output output_type; | |||
skipping to change at line 480 | skipping to change at line 546 | |||
return true; | return true; | |||
} | } | |||
// for multifunction_node. The function_body that implements | // for multifunction_node. The function_body that implements | |||
// the node will have an input and an output tuple of ports. To pu t | // the node will have an input and an output tuple of ports. To pu t | |||
// an item to a successor, the body should | // an item to a successor, the body should | |||
// | // | |||
// get<I>(output_ports).try_put(output_value); | // get<I>(output_ports).try_put(output_value); | |||
// | // | |||
// return value will be bool returned from successors.try_put. | // return value will be bool returned from successors.try_put. | |||
bool try_put(const output_type &i) { return my_successors.try_put(i ); } | task *try_put_task(const output_type &i) { return my_successors.try _put_task(i); } | |||
protected: | protected: | |||
broadcast_cache<output_type> my_successors; | broadcast_cache<output_type> my_successors; | |||
broadcast_cache<output_type > &successors() { return my_successors; } | broadcast_cache<output_type > &successors() { return my_successors; } | |||
}; | }; | |||
template< typename Output > | ||||
class multifunction_output : public function_output<Output> { | ||||
public: | ||||
typedef Output output_type; | ||||
typedef function_output<output_type> base_type; | ||||
using base_type::my_successors; | ||||
multifunction_output() : base_type() {my_successors.set_owner(this) | ||||
;} | ||||
multifunction_output( const multifunction_output &/*other*/) : base | ||||
_type() { my_successors.set_owner(this); } | ||||
bool try_put(const output_type &i) { | ||||
task *res = my_successors.try_put_task(i); | ||||
if(!res) return false; | ||||
if(res != SUCCESSFULLY_ENQUEUED) task::enqueue(*res); | ||||
return true; | ||||
} | ||||
}; | ||||
} // internal | } // internal | |||
#endif // __TBB__flow_graph_node_impl_H | #endif // __TBB__flow_graph_node_impl_H | |||
End of changes. 38 change blocks. | ||||
36 lines changed or deleted | 130 lines changed or added | |||
_flow_graph_or_impl.h | _flow_graph_or_impl.h | |||
---|---|---|---|---|
skipping to change at line 41 | skipping to change at line 41 | |||
#ifndef __TBB_flow_graph_H | #ifndef __TBB_flow_graph_H | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
#if TBB_PREVIEW_GRAPH_NODES | #if TBB_PREVIEW_GRAPH_NODES | |||
#include "tbb/internal/_flow_graph_types_impl.h" | #include "tbb/internal/_flow_graph_types_impl.h" | |||
namespace internal { | namespace internal { | |||
// Output of the or_node is a struct containing a std::tuple, and will be of | // Output of the or_node is a struct containing a tbb::flow::tuple, and will be of | |||
// the form | // the form | |||
// | // | |||
// struct { | // struct { | |||
// size_t indx; | // size_t indx; | |||
// tuple_types result; | // tuple_types result; | |||
// }; | // }; | |||
// | // | |||
// where the value of indx will indicate which result was put to the | // where the value of indx will indicate which result was put to the | |||
// successor. So if oval is the output to the successor, indx == 0 | // successor. So if oval is the output to the successor, indx == 0 | |||
// means std::get<0>(oval.result) is the output, and so on. | // means tbb::flow::get<0>(oval.result) is the output, and so on. | |||
// | // | |||
// tuple_types is the tuple that specified the possible outputs (and | // tuple_types is the tuple that specified the possible outputs (and | |||
// the corresponding inputs to the or_node.) | // the corresponding inputs to the or_node.) | |||
// | // | |||
// the types of each element are represented by tuple_types, a typedef | // the types of each element are represented by tuple_types, a typedef | |||
// in the or_node. So the 2nd type in the union that is the | // in the or_node. So the 2nd type in the union that is the | |||
// output type for an or_node OrType is | // output type for an or_node OrType is | |||
// | // | |||
// std::tuple_element<1,OrType::tuple_types>::type | // tbb::flow::tuple_element<1,OrType::tuple_types>::type | |||
// the struct has an OutputTuple default constructed, with element inde x assigned | // the struct has an OutputTuple default constructed, with element inde x assigned | |||
// the actual output value. | // the actual output value. | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
struct or_output_type { | struct or_output_type { | |||
typedef OutputTuple tuple_types; | typedef OutputTuple tuple_types; | |||
typedef struct { | typedef struct { | |||
size_t indx; | size_t indx; | |||
OutputTuple result; | OutputTuple result; | |||
} type; | } type; | |||
}; | }; | |||
template<typename TupleTypes,int N> | template<typename TupleTypes,int N> | |||
struct or_item_helper { | struct or_item_helper { | |||
template<typename OutputType> | template<typename OutputType> | |||
static inline void create_output_value(OutputType &o, void *v) { | static inline void create_output_value(OutputType &o, void *v) { | |||
o.indx = N; | o.indx = N; | |||
std::get<N>(o.result) = *(reinterpret_cast<typename std::tuple_ element<N, TupleTypes>::type *>(v)); | tbb::flow::get<N>(o.result) = *(reinterpret_cast<typename tbb:: flow::tuple_element<N, TupleTypes>::type *>(v)); | |||
} | } | |||
}; | }; | |||
template<typename TupleTypes,int N> | template<typename TupleTypes,int N> | |||
struct or_helper { | struct or_helper { | |||
template<typename OutputType> | template<typename OutputType> | |||
static inline void create_output(OutputType &o, size_t i, void* v) { | static inline void create_output(OutputType &o, size_t i, void* v) { | |||
if(i == N-1) { | if(i == N-1) { | |||
or_item_helper<TupleTypes,N-1>::create_output_value(o,v); | or_item_helper<TupleTypes,N-1>::create_output_value(o,v); | |||
} | } | |||
else | else | |||
or_helper<TupleTypes,N-1>::create_output(o,i,v); | or_helper<TupleTypes,N-1>::create_output(o,i,v); | |||
} | } | |||
template<typename PortTuple, typename PutBase> | template<typename PortTuple, typename PutBase> | |||
static inline void set_or_node_pointer(PortTuple &my_input, PutBase *p) { | static inline void set_or_node_pointer(PortTuple &my_input, PutBase *p) { | |||
std::get<N-1>(my_input).set_up(p, N-1); | tbb::flow::get<N-1>(my_input).set_up(p, N-1); | |||
or_helper<TupleTypes,N-1>::set_or_node_pointer(my_input, p); | or_helper<TupleTypes,N-1>::set_or_node_pointer(my_input, p); | |||
} | } | |||
}; | }; | |||
template<typename TupleTypes> | template<typename TupleTypes> | |||
struct or_helper<TupleTypes,1> { | struct or_helper<TupleTypes,1> { | |||
template<typename OutputType> | template<typename OutputType> | |||
static inline void create_output(OutputType &o, size_t i, void* v) { | static inline void create_output(OutputType &o, size_t i, void* v) { | |||
if(i == 0) { | if(i == 0) { | |||
or_item_helper<TupleTypes,0>::create_output_value(o,v); | or_item_helper<TupleTypes,0>::create_output_value(o,v); | |||
} | } | |||
} | } | |||
template<typename PortTuple, typename PutBase> | template<typename PortTuple, typename PutBase> | |||
static inline void set_or_node_pointer(PortTuple &my_input, PutBase *p) { | static inline void set_or_node_pointer(PortTuple &my_input, PutBase *p) { | |||
std::get<0>(my_input).set_up(p, 0); | tbb::flow::get<0>(my_input).set_up(p, 0); | |||
} | } | |||
}; | }; | |||
struct put_base { | struct put_base { | |||
virtual bool try_put_with_index(size_t index, void *v) = 0; | // virtual bool try_put_with_index(size_t index, void *v) = 0; | |||
virtual task * try_put_task_with_index(size_t index, void *v) = 0; | ||||
virtual ~put_base() { } | virtual ~put_base() { } | |||
}; | }; | |||
template<typename T> | template<typename T> | |||
class or_input_port : public receiver<T> { | class or_input_port : public receiver<T> { | |||
private: | private: | |||
size_t my_index; | size_t my_index; | |||
put_base *my_or_node; | put_base *my_or_node; | |||
public: | public: | |||
void set_up(put_base *p, size_t i) { my_index = i; my_or_node = p; } | void set_up(put_base *p, size_t i) { my_index = i; my_or_node = p; } | |||
bool try_put(const T &v) { | ||||
return my_or_node->try_put_with_index(my_index, reinterpret_cas | ||||
t<void *>(const_cast<T*>(&v))); | ||||
} | ||||
protected: | protected: | |||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_c | ||||
ache; | ||||
template<typename X, typename Y> friend class internal::round_robin | ||||
_cache; | ||||
task *try_put_task(const T &v) { | ||||
return my_or_node->try_put_task_with_index(my_index, reinterpre | ||||
t_cast<void *>(const_cast<T*>(&v))); | ||||
} | ||||
/*override*/void reset_receiver() {} | /*override*/void reset_receiver() {} | |||
}; | }; | |||
template<typename InputTuple, typename OutputType, typename StructTypes > | template<typename InputTuple, typename OutputType, typename StructTypes > | |||
class or_node_FE : public put_base { | class or_node_FE : public put_base { | |||
public: | public: | |||
static const int N = std::tuple_size<InputTuple>::value; | static const int N = tbb::flow::tuple_size<InputTuple>::value; | |||
typedef OutputType output_type; | typedef OutputType output_type; | |||
typedef InputTuple input_type; | typedef InputTuple input_type; | |||
or_node_FE( ) { | or_node_FE( ) { | |||
or_helper<StructTypes,N>::set_or_node_pointer(my_inputs, this); | or_helper<StructTypes,N>::set_or_node_pointer(my_inputs, this); | |||
} | } | |||
input_type &input_ports() { return my_inputs; } | input_type &input_ports() { return my_inputs; } | |||
protected: | protected: | |||
input_type my_inputs; | input_type my_inputs; | |||
}; | }; | |||
//! or_node_base | //! or_node_base | |||
template<typename InputTuple, typename OutputType, typename StructTypes > | template<typename InputTuple, typename OutputType, typename StructTypes > | |||
class or_node_base : public graph_node, public or_node_FE<InputTuple, O utputType,StructTypes>, | class or_node_base : public graph_node, public or_node_FE<InputTuple, O utputType,StructTypes>, | |||
public sender<OutputType> { | public sender<OutputType> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
static const size_t N = std::tuple_size<InputTuple>::value; | static const size_t N = tbb::flow::tuple_size<InputTuple>::value; | |||
typedef OutputType output_type; | typedef OutputType output_type; | |||
typedef StructTypes tuple_types; | typedef StructTypes tuple_types; | |||
typedef receiver<output_type> successor_type; | typedef receiver<output_type> successor_type; | |||
typedef or_node_FE<InputTuple, output_type,StructTypes> input_ports _type; | typedef or_node_FE<InputTuple, output_type,StructTypes> input_ports _type; | |||
private: | private: | |||
// ----------- Aggregator ------------ | // ----------- Aggregator ------------ | |||
enum op_type { reg_succ, rem_succ, try__put }; | enum op_type { reg_succ, rem_succ, try__put_task }; | |||
enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |||
typedef or_node_base<InputTuple,output_type,StructTypes> my_class; | typedef or_node_base<InputTuple,output_type,StructTypes> my_class; | |||
class or_node_base_operation : public aggregated_operation<or_node_ base_operation> { | class or_node_base_operation : public aggregated_operation<or_node_ base_operation> { | |||
public: | public: | |||
char type; | char type; | |||
size_t indx; | size_t indx; | |||
union { | union { | |||
void *my_arg; | void *my_arg; | |||
successor_type *my_succ; | successor_type *my_succ; | |||
task *bypass_t; | ||||
}; | }; | |||
or_node_base_operation(size_t i, const void* e, op_type t) : | or_node_base_operation(size_t i, const void* e, op_type t) : | |||
type(char(t)), indx(i), my_arg(const_cast<void *>(e)) {} | type(char(t)), indx(i), my_arg(const_cast<void *>(e)) {} | |||
or_node_base_operation(const successor_type &s, op_type t) : ty pe(char(t)), | or_node_base_operation(const successor_type &s, op_type t) : ty pe(char(t)), | |||
my_succ(const_cast<successor_type *>(&s)) {} | my_succ(const_cast<successor_type *>(&s)) {} | |||
or_node_base_operation(op_type t) : type(char(t)) {} | or_node_base_operation(op_type t) : type(char(t)) {} | |||
}; | }; | |||
typedef internal::aggregating_functor<my_class, or_node_base_operat ion> my_handler; | typedef internal::aggregating_functor<my_class, or_node_base_operat ion> my_handler; | |||
friend class internal::aggregating_functor<my_class, or_node_base_o peration>; | friend class internal::aggregating_functor<my_class, or_node_base_o peration>; | |||
skipping to change at line 201 | skipping to change at line 207 | |||
case reg_succ: | case reg_succ: | |||
my_successors.register_successor(*(current->my_succ)); | my_successors.register_successor(*(current->my_succ)); | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
case rem_succ: | case rem_succ: | |||
my_successors.remove_successor(*(current->my_succ)); | my_successors.remove_successor(*(current->my_succ)); | |||
__TBB_store_with_release(current->status, SUCCEEDED); | __TBB_store_with_release(current->status, SUCCEEDED); | |||
break; | break; | |||
case try__put_task: { | ||||
case try__put: | output_type oo; | |||
output_type oval; | or_helper<tuple_types,N>::create_output(oo, current | |||
or_helper<tuple_types,N>::create_output(oval,current->i | ->indx, current->my_arg); | |||
ndx,current->my_arg); | current->bypass_t = my_successors.try_put_task(oo); | |||
bool res = my_successors.try_put(oval); | __TBB_store_with_release(current->status, SUCCEEDED | |||
__TBB_store_with_release(current->status, res ? SUCCEED | ); // return of try_put_task actual return value | |||
ED : FAILED); | } | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
// ---------- end aggregator ----------- | // ---------- end aggregator ----------- | |||
public: | public: | |||
or_node_base(graph& g) : graph_node(g), input_ports_type() { | or_node_base(graph& g) : graph_node(g), input_ports_type() { | |||
my_successors.set_owner(this); | my_successors.set_owner(this); | |||
my_aggregator.initialize_handler(my_handler(this)); | my_aggregator.initialize_handler(my_handler(this)); | |||
} | } | |||
skipping to change at line 235 | skipping to change at line 241 | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return op_data.status == SUCCEEDED; | return op_data.status == SUCCEEDED; | |||
} | } | |||
bool remove_successor( successor_type &r) { | bool remove_successor( successor_type &r) { | |||
or_node_base_operation op_data(r, rem_succ); | or_node_base_operation op_data(r, rem_succ); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return op_data.status == SUCCEEDED; | return op_data.status == SUCCEEDED; | |||
} | } | |||
bool try_put_with_index(size_t indx, void *v) { | task * try_put_task_with_index(size_t indx, void *v) { | |||
or_node_base_operation op_data(indx, v, try__put); | or_node_base_operation op_data(indx, v, try__put_task); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return op_data.status == SUCCEEDED; | return op_data.bypass_t; | |||
} | } | |||
protected: | protected: | |||
/*override*/void reset() {} | /*override*/void reset() {} | |||
private: | private: | |||
broadcast_cache<output_type, null_rw_mutex> my_successors; | broadcast_cache<output_type, null_rw_mutex> my_successors; | |||
}; | }; | |||
// type generators | // type generators | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
struct or_types { | struct or_types { | |||
static const int N = std::tuple_size<OutputTuple>::value; | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |||
typedef typename wrap_tuple_elements<N,or_input_port,OutputTuple>:: type input_ports_type; | typedef typename wrap_tuple_elements<N,or_input_port,OutputTuple>:: type input_ports_type; | |||
typedef typename or_output_type<OutputTuple>::type output_type; | typedef typename or_output_type<OutputTuple>::type output_type; | |||
typedef internal::or_node_FE<input_ports_type,output_type,OutputTup le> or_FE_type; | typedef internal::or_node_FE<input_ports_type,output_type,OutputTup le> or_FE_type; | |||
typedef internal::or_node_base<input_ports_type, output_type, Outpu tTuple> or_base_type; | typedef internal::or_node_base<input_ports_type, output_type, Outpu tTuple> or_base_type; | |||
}; | }; | |||
template<class OutputTuple> | template<class OutputTuple> | |||
class unfolded_or_node : public or_types<OutputTuple>::or_base_type { | class unfolded_or_node : public or_types<OutputTuple>::or_base_type { | |||
public: | public: | |||
typedef typename or_types<OutputTuple>::input_ports_type input_port s_type; | typedef typename or_types<OutputTuple>::input_ports_type input_port s_type; | |||
End of changes. 18 change blocks. | ||||
26 lines changed or deleted | 34 lines changed or added | |||
_flow_graph_types_impl.h | _flow_graph_types_impl.h | |||
---|---|---|---|---|
skipping to change at line 44 | skipping to change at line 44 | |||
#endif | #endif | |||
namespace internal { | namespace internal { | |||
// wrap each element of a tuple in a template, and make a tuple of the resu lt. | // wrap each element of a tuple in a template, and make a tuple of the resu lt. | |||
template<int N, template<class> class PT, typename TypeTuple> | template<int N, template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements; | struct wrap_tuple_elements; | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<1, PT, TypeTuple> { | struct wrap_tuple_elements<1, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<2, PT, TypeTuple> { | struct wrap_tuple_elements<2, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<3, PT, TypeTuple> { | struct wrap_tuple_elements<3, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type>, | |||
PT<typename std::tuple_element<2,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<2,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<4, PT, TypeTuple> { | struct wrap_tuple_elements<4, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type>, | |||
PT<typename std::tuple_element<2,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<2,TypeTuple>::type>, | |||
PT<typename std::tuple_element<3,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<3,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<5, PT, TypeTuple> { | struct wrap_tuple_elements<5, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type>, | |||
PT<typename std::tuple_element<2,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<2,TypeTuple>::type>, | |||
PT<typename std::tuple_element<3,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<3,TypeTuple>::type>, | |||
PT<typename std::tuple_element<4,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<4,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
#if __TBB_VARIADIC_MAX >= 6 | #if __TBB_VARIADIC_MAX >= 6 | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<6, PT, TypeTuple> { | struct wrap_tuple_elements<6, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type>, | |||
PT<typename std::tuple_element<2,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<2,TypeTuple>::type>, | |||
PT<typename std::tuple_element<3,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<3,TypeTuple>::type>, | |||
PT<typename std::tuple_element<4,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<4,TypeTuple>::type>, | |||
PT<typename std::tuple_element<5,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<5,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
#endif | #endif | |||
#if __TBB_VARIADIC_MAX >= 7 | #if __TBB_VARIADIC_MAX >= 7 | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<7, PT, TypeTuple> { | struct wrap_tuple_elements<7, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type>, | |||
PT<typename std::tuple_element<2,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<2,TypeTuple>::type>, | |||
PT<typename std::tuple_element<3,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<3,TypeTuple>::type>, | |||
PT<typename std::tuple_element<4,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<4,TypeTuple>::type>, | |||
PT<typename std::tuple_element<5,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<5,TypeTuple>::type>, | |||
PT<typename std::tuple_element<6,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<6,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
#endif | #endif | |||
#if __TBB_VARIADIC_MAX >= 8 | #if __TBB_VARIADIC_MAX >= 8 | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<8, PT, TypeTuple> { | struct wrap_tuple_elements<8, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type>, | |||
PT<typename std::tuple_element<2,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<2,TypeTuple>::type>, | |||
PT<typename std::tuple_element<3,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<3,TypeTuple>::type>, | |||
PT<typename std::tuple_element<4,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<4,TypeTuple>::type>, | |||
PT<typename std::tuple_element<5,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<5,TypeTuple>::type>, | |||
PT<typename std::tuple_element<6,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<6,TypeTuple>::type>, | |||
PT<typename std::tuple_element<7,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<7,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
#endif | #endif | |||
#if __TBB_VARIADIC_MAX >= 9 | #if __TBB_VARIADIC_MAX >= 9 | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<9, PT, TypeTuple> { | struct wrap_tuple_elements<9, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type>, | |||
PT<typename std::tuple_element<2,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<2,TypeTuple>::type>, | |||
PT<typename std::tuple_element<3,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<3,TypeTuple>::type>, | |||
PT<typename std::tuple_element<4,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<4,TypeTuple>::type>, | |||
PT<typename std::tuple_element<5,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<5,TypeTuple>::type>, | |||
PT<typename std::tuple_element<6,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<6,TypeTuple>::type>, | |||
PT<typename std::tuple_element<7,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<7,TypeTuple>::type>, | |||
PT<typename std::tuple_element<8,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<8,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
#endif | #endif | |||
#if __TBB_VARIADIC_MAX >= 10 | #if __TBB_VARIADIC_MAX >= 10 | |||
template<template<class> class PT, typename TypeTuple> | template<template<class> class PT, typename TypeTuple> | |||
struct wrap_tuple_elements<10, PT, TypeTuple> { | struct wrap_tuple_elements<10, PT, TypeTuple> { | |||
typedef typename std::tuple< | typedef typename tbb::flow::tuple< | |||
PT<typename std::tuple_element<0,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<0,TypeTuple>::type>, | |||
PT<typename std::tuple_element<1,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<1,TypeTuple>::type>, | |||
PT<typename std::tuple_element<2,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<2,TypeTuple>::type>, | |||
PT<typename std::tuple_element<3,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<3,TypeTuple>::type>, | |||
PT<typename std::tuple_element<4,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<4,TypeTuple>::type>, | |||
PT<typename std::tuple_element<5,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<5,TypeTuple>::type>, | |||
PT<typename std::tuple_element<6,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<6,TypeTuple>::type>, | |||
PT<typename std::tuple_element<7,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<7,TypeTuple>::type>, | |||
PT<typename std::tuple_element<8,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<8,TypeTuple>::type>, | |||
PT<typename std::tuple_element<9,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<9,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
#endif | #endif | |||
} // namespace internal | } // namespace internal | |||
#endif /* __TBB__flow_graph_types_impl_H */ | #endif /* __TBB__flow_graph_types_impl_H */ | |||
End of changes. 10 change blocks. | ||||
65 lines changed or deleted | 65 lines changed or added | |||
_tbb_windef.h | _tbb_windef.h | |||
---|---|---|---|---|
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_tbb_windef_H | #ifndef __TBB_tbb_windef_H | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif /* __TBB_tbb_windef_H */ | #endif /* __TBB_tbb_windef_H */ | |||
// 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<0x0501 | |||
#error TBB is unable to run on old Windows versions; _WIN32_WINNT must be 0 | #error TBB is unable to run on old Windows versions; _WIN32_WINNT must be 0 | |||
x0400 or greater. | x0501 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. | |||
#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; | |||
End of changes. 1 change blocks. | ||||
3 lines changed or deleted | 3 lines changed or added | |||
concurrent_vector.h | concurrent_vector.h | |||
---|---|---|---|---|
skipping to change at line 65 | skipping to change at line 65 | |||
#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 | |||
#if __TBB_INITIALIZER_LISTS_PRESENT | ||||
#include <initializer_list> | ||||
#endif | ||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64) | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64) | |||
// 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; | |||
skipping to change at line 512 | skipping to change at line 516 | |||
// STL compatible constructors & destructors | // STL compatible constructors & destructors | |||
//--------------------------------------------------------------------- --- | //--------------------------------------------------------------------- --- | |||
//! Construct empty vector. | //! Construct empty vector. | |||
explicit concurrent_vector(const allocator_type &a = allocator_type()) | explicit concurrent_vector(const allocator_type &a = allocator_type()) | |||
: internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | : internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
} | } | |||
#if __TBB_INITIALIZER_LISTS_PRESENT | ||||
//! Constructor from initializer_list | ||||
concurrent_vector(std::initializer_list<T> init_list, const allocator_t | ||||
ype &a = allocator_type()) | ||||
: internal::allocator_base<T, A>(a), internal::concurrent_vector_ba | ||||
se() | ||||
{ | ||||
vector_allocator_ptr = &internal_allocator; | ||||
__TBB_TRY { | ||||
internal_assign_iterators(init_list.begin(), init_list.end()); | ||||
} __TBB_CATCH(...) { | ||||
segment_t *table = my_segment; | ||||
internal_free_segments( reinterpret_cast<void**>(table), intern | ||||
al_clear(&destroy_array), my_first_block ); | ||||
__TBB_RETHROW(); | ||||
} | ||||
} | ||||
#endif //# __TBB_INITIALIZER_LISTS_PRESENT | ||||
//! 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::concurrent_vector_ba se() | : internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
__TBB_TRY { | __TBB_TRY { | |||
internal_copy(vector, sizeof(T), ©_array); | internal_copy(vector, sizeof(T), ©_array); | |||
} __TBB_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 ); | |||
skipping to change at line 590 | skipping to change at line 611 | |||
} | } | |||
} | } | |||
//! 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, ©_array); | internal_assign(vector, sizeof(T), &destroy_array, &assign_arra y, ©_array); | |||
return *this; | return *this; | |||
} | } | |||
//TODO: add an template assignment operator? (i.e. with different eleme | ||||
nt type) | ||||
//! Assignment for vector with different allocator type | //! Assignment for vector with different allocator type | |||
template<class M> | template<class M> | |||
concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) { | concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) { | |||
if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) ) | if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) ) | |||
internal_assign(vector.internal_vector_base(), | internal_assign(vector.internal_vector_base(), | |||
sizeof(T), &destroy_array, &assign_array, ©_array); | sizeof(T), &destroy_array, &assign_array, ©_array); | |||
return *this; | return *this; | |||
} | } | |||
#if __TBB_INITIALIZER_LISTS_PRESENT | ||||
//! Assignment for initializer_list | ||||
concurrent_vector& operator=( const std::initializer_list<T> & init_lis | ||||
t) { | ||||
internal_clear(&destroy_array); | ||||
internal_assign_iterators(init_list.begin(), init_list.end()); | ||||
return *this; | ||||
} | ||||
#endif //#if __TBB_INITIALIZER_LISTS_PRESENT | ||||
//--------------------------------------------------------------------- --- | //--------------------------------------------------------------------- --- | |||
// Concurrent operations | // Concurrent operations | |||
//--------------------------------------------------------------------- --- | //--------------------------------------------------------------------- --- | |||
//TODO: consider adding overload of grow_by accepting range of iterator | ||||
s: grow_by(iterator,iterator) | ||||
//TODO: consider adding overload of grow_by accepting initializer_list: | ||||
grow_by(std::initializer_list<T>), as a analogy to std::vector::insert(in | ||||
itializer_list) | ||||
//! Grow by "delta" elements. | //! Grow by "delta" elements. | |||
#if TBB_DEPRECATED | #if TBB_DEPRECATED | |||
/** Returns old size. */ | /** Returns old size. */ | |||
size_type grow_by( size_type delta ) { | size_type grow_by( size_type delta ) { | |||
return delta ? internal_grow_by( delta, sizeof(T), &initialize_arra y, NULL ) : my_early_size; | return delta ? internal_grow_by( delta, sizeof(T), &initialize_arra y, NULL ) : my_early_size; | |||
} | } | |||
#else | #else | |||
/** Returns iterator pointing to the first new element. */ | /** Returns iterator pointing to the first new element. */ | |||
iterator grow_by( size_type delta ) { | iterator grow_by( size_type delta ) { | |||
return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size); | return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size); | |||
skipping to change at line 808 | skipping to change at line 842 | |||
clear(); | clear(); | |||
internal_resize( n, sizeof(T), max_size(), static_cast<const void*> (&t), &destroy_array, &initialize_array_by ); | internal_resize( n, sizeof(T), max_size(), static_cast<const void*> (&t), &destroy_array, &initialize_array_by ); | |||
} | } | |||
//! assign range [first, last) | //! assign range [first, last) | |||
template<class I> | template<class I> | |||
void assign(I first, I last) { | void assign(I first, I last) { | |||
clear(); internal_assign_range( first, last, static_cast<is_integer _tag<std::numeric_limits<I>::is_integer> *>(0) ); | clear(); internal_assign_range( first, last, static_cast<is_integer _tag<std::numeric_limits<I>::is_integer> *>(0) ); | |||
} | } | |||
#if __TBB_INITIALIZER_LISTS_PRESENT | ||||
//! assigns an initializer list | ||||
void assign(std::initializer_list<T> init_list) { | ||||
clear(); internal_assign_iterators( init_list.begin(), init_list.en | ||||
d()); | ||||
} | ||||
#endif //# __TBB_INITIALIZER_LISTS_PRESENT | ||||
//! swap two instances | //! swap two instances | |||
void swap(concurrent_vector &vector) { | void swap(concurrent_vector &vector) { | |||
if( this != &vector ) { | if( this != &vector ) { | |||
concurrent_vector_base_v3::internal_swap(static_cast<concurrent _vector_base_v3&>(vector)); | concurrent_vector_base_v3::internal_swap(static_cast<concurrent _vector_base_v3&>(vector)); | |||
std::swap(this->my_allocator, vector.my_allocator); | std::swap(this->my_allocator, vector.my_allocator); | |||
} | } | |||
} | } | |||
//! Clear container while keeping memory allocated. | //! Clear container while keeping memory allocated. | |||
/** To free up the memory, use in conjunction with method compact(). No t thread safe **/ | /** To free up the memory, use in conjunction with method compact(). No t thread safe **/ | |||
skipping to change at line 893 | skipping to change at line 934 | |||
public: | public: | |||
const pointer array; | const pointer array; | |||
const size_type n; | const size_type n; | |||
size_type i; | size_type i; | |||
internal_loop_guide(size_type ntrials, void *ptr) | internal_loop_guide(size_type ntrials, void *ptr) | |||
: array(static_cast<pointer>(ptr)), n(ntrials), i(0) {} | : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {} | |||
void init() { for(; i < n; ++i) new( &array[i] ) T(); } | void init() { for(; i < n; ++i) new( &array[i] ) T(); } | |||
void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(* static_cast<const T*>(src)); } | void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(* static_cast<const T*>(src)); } | |||
void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(s tatic_cast<const T*>(src)[i]); } | void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(s tatic_cast<const T*>(src)[i]); } | |||
void assign(const void *src) { for(; i < n; ++i) array[i] = static_ cast<const T*>(src)[i]; } | void assign(const void *src) { for(; i < n; ++i) array[i] = static_ cast<const T*>(src)[i]; } | |||
//TODO: rename to construct_range | ||||
template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) n ew( &array[i] ) T( *src ); } | template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) n ew( &array[i] ) T( *src ); } | |||
~internal_loop_guide() { | ~internal_loop_guide() { | |||
if(i < n) // if exception raised, do zeroing on the rest of ite ms | if(i < n) // if exception raised, do zeroing on the rest of ite ms | |||
std::memset(array+i, 0, (n-i)*sizeof(value_type)); | std::memset(array+i, 0, (n-i)*sizeof(value_type)); | |||
} | } | |||
}; | }; | |||
}; | }; | |||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |||
#pragma warning (push) | #pragma warning (push) | |||
End of changes. 7 change blocks. | ||||
0 lines changed or deleted | 51 lines changed or added | |||
critical_section.h | critical_section.h | |||
---|---|---|---|---|
skipping to change at line 61 | skipping to change at line 61 | |||
#else | #else | |||
pthread_mutex_t my_impl; | pthread_mutex_t my_impl; | |||
#endif | #endif | |||
tbb_thread::id my_tid; | tbb_thread::id my_tid; | |||
public: | public: | |||
void __TBB_EXPORTED_METHOD internal_construct(); | void __TBB_EXPORTED_METHOD internal_construct(); | |||
critical_section_v4() { | critical_section_v4() { | |||
#if _WIN32||_WIN64 | #if _WIN32||_WIN64 | |||
InitializeCriticalSection(&my_impl); | InitializeCriticalSectionEx( &my_impl, 4000, 0 ); | |||
#else | #else | |||
pthread_mutex_init(&my_impl, NULL); | pthread_mutex_init(&my_impl, NULL); | |||
#endif | #endif | |||
internal_construct(); | internal_construct(); | |||
} | } | |||
~critical_section_v4() { | ~critical_section_v4() { | |||
__TBB_ASSERT(my_tid == tbb_thread::id(), "Destroying a still-held c ritical section"); | __TBB_ASSERT(my_tid == tbb_thread::id(), "Destroying a still-held c ritical section"); | |||
#if _WIN32||_WIN64 | #if _WIN32||_WIN64 | |||
DeleteCriticalSection(&my_impl); | DeleteCriticalSection(&my_impl); | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
enumerable_thread_specific.h | enumerable_thread_specific.h | |||
---|---|---|---|---|
skipping to change at line 235 | skipping to change at line 235 | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
//! Specialization that exploits native TLS | //! Specialization that exploits native TLS | |||
template <> | template <> | |||
class ets_base<ets_key_per_instance>: protected ets_base<ets_no_key > { | class ets_base<ets_key_per_instance>: protected ets_base<ets_no_key > { | |||
typedef ets_base<ets_no_key> super; | typedef ets_base<ets_no_key> super; | |||
#if _WIN32||_WIN64 | #if _WIN32||_WIN64 | |||
#if __TBB_WIN8UI_SUPPORT | ||||
typedef DWORD tls_key_t; | ||||
void create_key() { my_key = FlsAlloc(NULL); } | ||||
void destroy_key() { FlsFree(my_key); } | ||||
void set_tls(void * value) { FlsSetValue(my_key, (LPVOID)value) | ||||
; } | ||||
void* get_tls() { return (void *)FlsGetValue(my_key); } | ||||
#else | ||||
typedef DWORD tls_key_t; | typedef DWORD tls_key_t; | |||
void create_key() { my_key = TlsAlloc(); } | void create_key() { my_key = TlsAlloc(); } | |||
void destroy_key() { TlsFree(my_key); } | void destroy_key() { TlsFree(my_key); } | |||
void set_tls(void * value) { TlsSetValue(my_key, (LPVOID)value) ; } | void set_tls(void * value) { TlsSetValue(my_key, (LPVOID)value) ; } | |||
void* get_tls() { return (void *)TlsGetValue(my_key); } | void* get_tls() { return (void *)TlsGetValue(my_key); } | |||
#endif | ||||
#else | #else | |||
typedef pthread_key_t tls_key_t; | typedef pthread_key_t tls_key_t; | |||
void create_key() { pthread_key_create(&my_key, NULL); } | void create_key() { pthread_key_create(&my_key, NULL); } | |||
void destroy_key() { pthread_key_delete(my_key); } | void destroy_key() { pthread_key_delete(my_key); } | |||
void set_tls( void * value ) const { pthread_setspecific(my_key , value); } | void set_tls( void * value ) const { pthread_setspecific(my_key , value); } | |||
void* get_tls() const { return pthread_getspecific(my_key); } | void* get_tls() const { return pthread_getspecific(my_key); } | |||
#endif | #endif | |||
tls_key_t my_key; | tls_key_t my_key; | |||
virtual void* create_local() = 0; | virtual void* create_local() = 0; | |||
virtual void* create_array(size_t _size) = 0; // _size in byte s | virtual void* create_array(size_t _size) = 0; // _size in byte s | |||
End of changes. 2 change blocks. | ||||
0 lines changed or deleted | 9 lines changed or added | |||
flow_graph.h | flow_graph.h | |||
---|---|---|---|---|
skipping to change at line 45 | skipping to change at line 45 | |||
#include "null_mutex.h" | #include "null_mutex.h" | |||
#include "spin_rw_mutex.h" | #include "spin_rw_mutex.h" | |||
#include "null_rw_mutex.h" | #include "null_rw_mutex.h" | |||
#include "task.h" | #include "task.h" | |||
#include "concurrent_vector.h" | #include "concurrent_vector.h" | |||
#include "internal/_aggregator_impl.h" | #include "internal/_aggregator_impl.h" | |||
// use the VC10 or gcc version of tuple if it is available. | // use the VC10 or gcc version of tuple if it is available. | |||
#if __TBB_CPP11_TUPLE_PRESENT | #if __TBB_CPP11_TUPLE_PRESENT | |||
#include <tuple> | #include <tuple> | |||
namespace tbb { | ||||
namespace flow { | ||||
using std::tuple; | ||||
using std::tuple_size; | ||||
using std::tuple_element; | ||||
using std::get; | ||||
} | ||||
} | ||||
#else | #else | |||
#include "compat/tuple" | #include "compat/tuple" | |||
#endif | #endif | |||
#include<list> | #include<list> | |||
#include<queue> | #include<queue> | |||
/** @file | /** @file | |||
\brief The graph related classes and functions | \brief The graph related classes and functions | |||
skipping to change at line 71 | skipping to change at line 79 | |||
namespace tbb { | namespace tbb { | |||
namespace flow { | namespace flow { | |||
//! An enumeration the provides the two most common concurrency levels: unl imited and serial | //! An enumeration the provides the two most common concurrency levels: unl imited and serial | |||
enum concurrency { unlimited = 0, serial = 1 }; | enum concurrency { unlimited = 0, serial = 1 }; | |||
namespace interface6 { | namespace interface6 { | |||
namespace internal { | namespace internal { | |||
template<typename T, typename M> | template<typename T, typename M> class successor_cache; | |||
class successor_cache; | template<typename T, typename M> class broadcast_cache; | |||
template<typename T, typename M> class round_robin_cache; | ||||
} | } | |||
//! An empty class used for messages that mean "I'm done" | //! An empty class used for messages that mean "I'm done" | |||
class continue_msg {}; | class continue_msg {}; | |||
template< typename T > class sender; | template< typename T > class sender; | |||
template< typename T > class receiver; | template< typename T > class receiver; | |||
class continue_receiver; | class continue_receiver; | |||
//! Pure virtual template class that defines a sender of messages of type T | //! Pure virtual template class that defines a sender of messages of type T | |||
skipping to change at line 114 | skipping to change at line 123 | |||
virtual bool try_reserve( T & ) { return false; } | virtual bool try_reserve( T & ) { return false; } | |||
//! Releases the reserved item | //! Releases the reserved item | |||
virtual bool try_release( ) { return false; } | virtual bool try_release( ) { return false; } | |||
//! Consumes the reserved item | //! Consumes the reserved item | |||
virtual bool try_consume( ) { return false; } | virtual bool try_consume( ) { return false; } | |||
}; | }; | |||
template< typename T > class limiter_node; // needed for resetting decreme nter | template< typename T > class limiter_node; // needed for resetting decreme nter | |||
template< typename R, typename B > class run_and_put_task; | ||||
static tbb::task * const SUCCESSFULLY_ENQUEUED = (task *)-1; | ||||
// enqueue left task if necessary. Returns the non-enqueued task if there | ||||
is one. | ||||
static inline tbb::task *combine_tasks( tbb::task * left, tbb::task * right | ||||
) { | ||||
// if no RHS task, don't change left. | ||||
if(right == NULL) return left; | ||||
// right != NULL | ||||
if(left == NULL) return right; | ||||
if(left == SUCCESSFULLY_ENQUEUED) return right; | ||||
// left contains a task | ||||
if(right != SUCCESSFULLY_ENQUEUED) { | ||||
// both are valid tasks | ||||
tbb::task::enqueue(*left); | ||||
return right; | ||||
} | ||||
return left; | ||||
} | ||||
//! Pure virtual template class that defines a receiver of messages of type T | //! Pure virtual template class that defines a receiver of messages of type T | |||
template< typename T > | template< typename T > | |||
class receiver { | class receiver { | |||
public: | public: | |||
//! The input type of this receiver | //! The input type of this receiver | |||
typedef T input_type; | typedef T input_type; | |||
//! The predecessor type for this node | //! The predecessor type for this node | |||
typedef sender<T> predecessor_type; | typedef sender<T> predecessor_type; | |||
//! Destructor | //! Destructor | |||
virtual ~receiver() {} | virtual ~receiver() {} | |||
//! Put an item to the receiver | //! Put an item to the receiver | |||
virtual bool try_put( const T& t ) = 0; | bool try_put( const T& t ) { | |||
task *res = try_put_task(t); | ||||
if(!res) return false; | ||||
if (res != SUCCESSFULLY_ENQUEUED) task::enqueue(*res); | ||||
return true; | ||||
} | ||||
//! put item to successor; return task to run the successor if possible | ||||
. | ||||
protected: | ||||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
virtual task *try_put_task(const T& t) = 0; | ||||
public: | ||||
//! Add a predecessor to the node | //! Add a predecessor to the node | |||
virtual bool register_predecessor( predecessor_type & ) { return false; } | virtual bool register_predecessor( predecessor_type & ) { return false; } | |||
//! Remove a predecessor from the node | //! Remove a predecessor from the node | |||
virtual bool remove_predecessor( predecessor_type & ) { return false; } | virtual bool remove_predecessor( predecessor_type & ) { return false; } | |||
protected: | protected: | |||
//! put receiver back in initial state | //! put receiver back in initial state | |||
template<typename U> friend class limiter_node; | template<typename U> friend class limiter_node; | |||
virtual void reset_receiver() = 0; | virtual void reset_receiver() = 0; | |||
template<typename TT, typename M> | template<typename TT, typename M> | |||
friend class internal::successor_cache; | friend class internal::successor_cache; | |||
virtual bool is_continue_receiver() { return false; } | virtual bool is_continue_receiver() { return false; } | |||
}; | }; | |||
//! Base class for receivers of completion messages | //! Base class for receivers of completion messages | |||
/** These receivers automatically reset, but cannot be explicitly waited on */ | /** These receivers automatically reset, but cannot be explicitly waited on */ | |||
class continue_receiver : public receiver< continue_msg > { | class continue_receiver : public receiver< continue_msg > { | |||
public: | public: | |||
//! The input type | //! The input type | |||
typedef continue_msg input_type; | typedef continue_msg input_type; | |||
skipping to change at line 189 | skipping to change at line 231 | |||
//! Decrements the trigger threshold | //! Decrements the trigger threshold | |||
/** Does not check to see if the removal of the predecessor now makes t he current count | /** Does not check to see if the removal of the predecessor now makes t he current count | |||
exceed the new threshold. So removing a predecessor while the grap h is active can cause | exceed the new threshold. So removing a predecessor while the grap h is active can cause | |||
unexpected results. */ | unexpected results. */ | |||
/* override */ bool remove_predecessor( predecessor_type & ) { | /* override */ bool remove_predecessor( predecessor_type & ) { | |||
spin_mutex::scoped_lock l(my_mutex); | spin_mutex::scoped_lock l(my_mutex); | |||
--my_predecessor_count; | --my_predecessor_count; | |||
return true; | return true; | |||
} | } | |||
//! Puts a continue_msg to the receiver | protected: | |||
/** If the message causes the message count to reach the predecessor co | template< typename R, typename B > friend class run_and_put_task; | |||
unt, execute() is called and | template<typename X, typename Y> friend class internal::broadcast_cache | |||
the message count is reset to 0. Otherwise the message count is in | ; | |||
cremented. */ | template<typename X, typename Y> friend class internal::round_robin_cac | |||
/* override */ bool try_put( const input_type & ) { | he; | |||
// execute body is supposed to be too small to create a task for. | ||||
/* override */ task *try_put_task( const input_type & ) { | ||||
{ | { | |||
spin_mutex::scoped_lock l(my_mutex); | spin_mutex::scoped_lock l(my_mutex); | |||
if ( ++my_current_count < my_predecessor_count ) | if ( ++my_current_count < my_predecessor_count ) | |||
return true; | return SUCCESSFULLY_ENQUEUED; | |||
else | else | |||
my_current_count = 0; | my_current_count = 0; | |||
} | } | |||
execute(); | task * res = execute(); | |||
return true; | return res; | |||
} | } | |||
protected: | ||||
spin_mutex my_mutex; | spin_mutex my_mutex; | |||
int my_predecessor_count; | int my_predecessor_count; | |||
int my_current_count; | int my_current_count; | |||
int my_initial_predecessor_count; | int my_initial_predecessor_count; | |||
// the friend declaration in the base class did not eliminate the "prot ected class" | // the friend declaration in the base class did not eliminate the "prot ected class" | |||
// error in gcc 4.1.2 | // error in gcc 4.1.2 | |||
template<typename U> friend class limiter_node; | template<typename U> friend class limiter_node; | |||
/*override*/void reset_receiver() { | /*override*/void reset_receiver() { | |||
my_current_count = 0; | my_current_count = 0; | |||
} | } | |||
//! Does whatever should happen when the threshold is reached | //! Does whatever should happen when the threshold is reached | |||
/** This should be very fast or else spawn a task. This is | /** This should be very fast or else spawn a task. This is | |||
called while the sender is blocked in the try_put(). */ | called while the sender is blocked in the try_put(). */ | |||
virtual void execute() = 0; | virtual task * execute() = 0; | |||
template<typename TT, typename M> | template<typename TT, typename M> | |||
friend class internal::successor_cache; | friend class internal::successor_cache; | |||
/*override*/ bool is_continue_receiver() { return true; } | /*override*/ bool is_continue_receiver() { return true; } | |||
}; | }; | |||
#include "internal/_flow_graph_impl.h" | #include "internal/_flow_graph_impl.h" | |||
using namespace internal::graph_policy_namespace; | using namespace internal::graph_policy_namespace; | |||
class graph; | class graph; | |||
class graph_node; | class graph_node; | |||
template <typename GraphContainerType, typename GraphNodeType> | template <typename GraphContainerType, typename GraphNodeType> | |||
skipping to change at line 320 | skipping to change at line 363 | |||
} | } | |||
private: | private: | |||
Body my_body; | Body my_body; | |||
}; | }; | |||
template< typename Receiver, typename Body > | template< typename Receiver, typename Body > | |||
class run_and_put_task : public task { | class run_and_put_task : public task { | |||
public: | public: | |||
run_and_put_task( Receiver &r, Body& body ) : my_receiver(r), my_bo dy(body) {} | run_and_put_task( Receiver &r, Body& body ) : my_receiver(r), my_bo dy(body) {} | |||
task *execute() { | task *execute() { | |||
my_receiver.try_put( my_body() ); | task *res = my_receiver.try_put_task( my_body() ); | |||
return NULL; | if(res == SUCCESSFULLY_ENQUEUED) res = NULL; | |||
return res; | ||||
} | } | |||
private: | private: | |||
Receiver &my_receiver; | Receiver &my_receiver; | |||
Body my_body; | Body my_body; | |||
}; | }; | |||
public: | public: | |||
//! Constructs a graph with isolated task_group_context | //! Constructs a graph with isolated task_group_context | |||
explicit graph() : my_nodes(NULL), my_nodes_last(NULL) | explicit graph() : my_nodes(NULL), my_nodes_last(NULL) | |||
{ | { | |||
skipping to change at line 550 | skipping to change at line 594 | |||
graph_node *my_p = &(*ii); | graph_node *my_p = &(*ii); | |||
my_p->reset(); | my_p->reset(); | |||
} | } | |||
} | } | |||
#include "internal/_flow_graph_node_impl.h" | #include "internal/_flow_graph_node_impl.h" | |||
//! An executable node that acts as a source, i.e. it has no predecessors | //! An executable node that acts as a source, i.e. it has no predecessors | |||
template < typename Output > | template < typename Output > | |||
class source_node : public graph_node, public sender< Output > { | class source_node : public graph_node, public sender< Output > { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
//! The type of the output message, which is complete | //! The type of the output message, which is complete | |||
typedef Output output_type; | typedef Output output_type; | |||
//! The type of successors of this node | //! The type of successors of this node | |||
typedef receiver< Output > successor_type; | typedef receiver< Output > successor_type; | |||
//! Constructor for a node with a successor | //! Constructor for a node with a successor | |||
template< typename Body > | template< typename Body > | |||
skipping to change at line 658 | skipping to change at line 703 | |||
} | } | |||
//! Activates a node that was created in the inactive state | //! Activates a node that was created in the inactive state | |||
void activate() { | void activate() { | |||
spin_mutex::scoped_lock lock(my_mutex); | spin_mutex::scoped_lock lock(my_mutex); | |||
my_active = true; | my_active = true; | |||
if ( !my_successors.empty() ) | if ( !my_successors.empty() ) | |||
spawn_put(); | spawn_put(); | |||
} | } | |||
template<class Body> | template<typename Body> | |||
Body copy_function_object() { | Body copy_function_object() { | |||
internal::source_body<output_type> &body_ref = *this->my_body; | internal::source_body<output_type> &body_ref = *this->my_body; | |||
return dynamic_cast< internal::source_body_leaf<output_type, Body> & >(body_ref).get_body(); | return dynamic_cast< internal::source_body_leaf<output_type, Body> & >(body_ref).get_body(); | |||
} | } | |||
protected: | protected: | |||
//! resets the node to its initial state | //! resets the node to its initial state | |||
void reset() { | void reset() { | |||
my_active = init_my_active; | my_active = init_my_active; | |||
skipping to change at line 686 | skipping to change at line 731 | |||
task *my_root_task; | task *my_root_task; | |||
spin_mutex my_mutex; | spin_mutex my_mutex; | |||
bool my_active; | bool my_active; | |||
bool init_my_active; | bool init_my_active; | |||
internal::source_body<output_type> *my_body; | internal::source_body<output_type> *my_body; | |||
internal::broadcast_cache< output_type > my_successors; | internal::broadcast_cache< output_type > my_successors; | |||
bool my_reserved; | bool my_reserved; | |||
bool my_has_cached_item; | bool my_has_cached_item; | |||
output_type my_cached_item; | output_type my_cached_item; | |||
friend class internal::source_task< source_node< output_type > >; | ||||
// used by apply_body, can invoke body of node. | // used by apply_body, can invoke body of node. | |||
bool try_reserve_apply_body(output_type &v) { | bool try_reserve_apply_body(output_type &v) { | |||
spin_mutex::scoped_lock lock(my_mutex); | spin_mutex::scoped_lock lock(my_mutex); | |||
if ( my_reserved ) { | if ( my_reserved ) { | |||
return false; | return false; | |||
} | } | |||
if ( !my_has_cached_item && (*my_body)(my_cached_item) ) | if ( !my_has_cached_item && (*my_body)(my_cached_item) ) | |||
my_has_cached_item = true; | my_has_cached_item = true; | |||
if ( my_has_cached_item ) { | if ( my_has_cached_item ) { | |||
v = my_cached_item; | v = my_cached_item; | |||
my_reserved = true; | my_reserved = true; | |||
return true; | return true; | |||
} else { | } else { | |||
return false; | return false; | |||
} | } | |||
} | } | |||
//! Applies the body | //! Spawns a task that applies the body | |||
/* override */ void apply_body( ) { | /* override */ void spawn_put( ) { | |||
task::enqueue( * new ( task::allocate_additional_child_of( *my_root | ||||
_task ) ) | ||||
internal:: source_task_bypass < source_node< output_type > >( *t | ||||
his ) ); | ||||
} | ||||
friend class internal::source_task_bypass< source_node< output_type > > | ||||
; | ||||
//! Applies the body. Returning SUCCESSFULLY_ENQUEUED okay; forward_ta | ||||
sk_bypass will handle it. | ||||
/* override */ task * apply_body_bypass( ) { | ||||
output_type v; | output_type v; | |||
if ( !try_reserve_apply_body(v) ) | if ( !try_reserve_apply_body(v) ) | |||
return; | return NULL; | |||
if ( my_successors.try_put( v ) ) | task *last_task = my_successors.try_put_task(v); | |||
if ( last_task ) | ||||
try_consume(); | try_consume(); | |||
else | else | |||
try_release(); | try_release(); | |||
} | return last_task; | |||
//! Spawns a task that applies the body | ||||
/* override */ void spawn_put( ) { | ||||
task::enqueue( * new ( task::allocate_additional_child_of( *my_root | ||||
_task ) ) | ||||
internal::source_task< source_node< output_type > >( *this ) ); | ||||
} | } | |||
}; // source_node | }; // source_node | |||
//! Implements a function node that supports Input -> Output | //! Implements a function node that supports Input -> Output | |||
template < typename Input, typename Output = continue_msg, graph_buffer_pol icy = queueing, typename Allocator=cache_aligned_allocator<Input> > | template < typename Input, typename Output = continue_msg, graph_buffer_pol icy = queueing, typename Allocator=cache_aligned_allocator<Input> > | |||
class function_node : public graph_node, public internal::function_input<In put,Output,Allocator>, public internal::function_output<Output> { | class function_node : public graph_node, public internal::function_input<In put,Output,Allocator>, public internal::function_output<Output> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
typedef Input input_type; | typedef Input input_type; | |||
typedef Output output_type; | typedef Output output_type; | |||
typedef sender< input_type > predecessor_type; | typedef sender< input_type > predecessor_type; | |||
typedef receiver< output_type > successor_type; | typedef receiver< output_type > successor_type; | |||
typedef internal::function_input<input_type,output_type,Allocator> fInp ut_type; | typedef internal::function_input<input_type,output_type,Allocator> fInp ut_type; | |||
typedef internal::function_output<output_type> fOutput_type; | typedef internal::function_output<output_type> fOutput_type; | |||
//! Constructor | //! Constructor | |||
skipping to change at line 751 | skipping to change at line 795 | |||
function_node( graph &g, size_t concurrency, Body body ) : | function_node( graph &g, size_t concurrency, Body body ) : | |||
graph_node(g), internal::function_input<input_type,output_type,Allo cator>(g, concurrency, body) | graph_node(g), internal::function_input<input_type,output_type,Allo cator>(g, concurrency, body) | |||
{} | {} | |||
//! Copy constructor | //! Copy constructor | |||
function_node( const function_node& src ) : | function_node( const function_node& src ) : | |||
graph_node(src.my_graph), internal::function_input<input_type,outpu t_type,Allocator>( src ), | graph_node(src.my_graph), internal::function_input<input_type,outpu t_type,Allocator>( src ), | |||
fOutput_type() | fOutput_type() | |||
{} | {} | |||
bool try_put(const input_type &i) { return fInput_type::try_put(i); } | ||||
protected: | protected: | |||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
using fInput_type::try_put_task; | ||||
// override of graph_node's reset. | // override of graph_node's reset. | |||
/*override*/void reset() {fInput_type::reset_function_input(); } | /*override*/void reset() {fInput_type::reset_function_input(); } | |||
/* override */ internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; } | /* override */ internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; } | |||
}; | }; | |||
//! Implements a function node that supports Input -> Output | //! Implements a function node that supports Input -> Output | |||
template < typename Input, typename Output, typename Allocator > | template < typename Input, typename Output, typename Allocator > | |||
class function_node<Input,Output,queueing,Allocator> : public graph_node, p ublic internal::function_input<Input,Output,Allocator>, public internal::fu nction_output<Output> { | class function_node<Input,Output,queueing,Allocator> : public graph_node, p ublic internal::function_input<Input,Output,Allocator>, public internal::fu nction_output<Output> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
typedef Input input_type; | typedef Input input_type; | |||
typedef Output output_type; | typedef Output output_type; | |||
typedef sender< input_type > predecessor_type; | typedef sender< input_type > predecessor_type; | |||
typedef receiver< output_type > successor_type; | typedef receiver< output_type > successor_type; | |||
typedef internal::function_input<input_type,output_type,Allocator> fInp ut_type; | typedef internal::function_input<input_type,output_type,Allocator> fInp ut_type; | |||
typedef internal::function_input_queue<input_type, Allocator> queue_typ e; | typedef internal::function_input_queue<input_type, Allocator> queue_typ e; | |||
typedef internal::function_output<output_type> fOutput_type; | typedef internal::function_output<output_type> fOutput_type; | |||
skipping to change at line 785 | skipping to change at line 832 | |||
template< typename Body > | template< typename Body > | |||
function_node( graph &g, size_t concurrency, Body body ) : | function_node( graph &g, size_t concurrency, Body body ) : | |||
graph_node(g), fInput_type( g, concurrency, body, new queue_type() ) | graph_node(g), fInput_type( g, concurrency, body, new queue_type() ) | |||
{} | {} | |||
//! Copy constructor | //! Copy constructor | |||
function_node( const function_node& src ) : | function_node( const function_node& src ) : | |||
graph_node(src.my_graph), fInput_type( src, new queue_type() ), fOu tput_type() | graph_node(src.my_graph), fInput_type( src, new queue_type() ), fOu tput_type() | |||
{} | {} | |||
bool try_put(const input_type &i) { return fInput_type::try_put(i); } | ||||
protected: | protected: | |||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
using fInput_type::try_put_task; | ||||
/*override*/void reset() { fInput_type::reset_function_input(); } | /*override*/void reset() { fInput_type::reset_function_input(); } | |||
/* override */ internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; } | /* override */ internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; } | |||
}; | }; | |||
#include "tbb/internal/_flow_graph_types_impl.h" | #include "tbb/internal/_flow_graph_types_impl.h" | |||
//! implements a function node that supports Input -> (set of outputs) | //! implements a function node that supports Input -> (set of outputs) | |||
// Output is a tuple of output types. | // Output is a tuple of output types. | |||
template < typename Input, typename Output, graph_buffer_policy = queueing, typename Allocator=cache_aligned_allocator<Input> > | template < typename Input, typename Output, graph_buffer_policy = queueing, typename Allocator=cache_aligned_allocator<Input> > | |||
class multifunction_node : | class multifunction_node : | |||
public graph_node, | public graph_node, | |||
public internal::multifunction_input | public internal::multifunction_input | |||
< | < | |||
Input, | Input, | |||
typename internal::wrap_tuple_elements< | typename internal::wrap_tuple_elements< | |||
std::tuple_size<Output>::value, // #elements in tuple | tbb::flow::tuple_size<Output>::value, // #elements in tuple | |||
internal::function_output, // wrap this around each element | internal::multifunction_output, // wrap this around each eleme | |||
nt | ||||
Output // the tuple providing the types | Output // the tuple providing the types | |||
>::type, | >::type, | |||
Allocator | Allocator | |||
> { | > { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
private: | private: | |||
static const int N = std::tuple_size<Output>::value; | static const int N = tbb::flow::tuple_size<Output>::value; | |||
public: | public: | |||
typedef Input input_type; | typedef Input input_type; | |||
typedef typename internal::wrap_tuple_elements<N,internal::function_out put, Output>::type output_ports_type; | typedef typename internal::wrap_tuple_elements<N,internal::multifunctio n_output, Output>::type output_ports_type; | |||
private: | private: | |||
typedef typename internal::multifunction_input<input_type, output_ports _type, Allocator> base_type; | typedef typename internal::multifunction_input<input_type, output_ports _type, Allocator> base_type; | |||
typedef typename internal::function_input_queue<input_type,Allocator> q ueue_type; | typedef typename internal::function_input_queue<input_type,Allocator> q ueue_type; | |||
public: | public: | |||
template<typename Body> | template<typename Body> | |||
multifunction_node( graph &g, size_t concurrency, Body body ) : | multifunction_node( graph &g, size_t concurrency, Body body ) : | |||
graph_node(g), base_type(g,concurrency, body) | graph_node(g), base_type(g,concurrency, body) | |||
{} | {} | |||
multifunction_node( const multifunction_node &other) : | multifunction_node( const multifunction_node &other) : | |||
graph_node(other.my_graph), base_type(other) | graph_node(other.my_graph), base_type(other) | |||
{} | {} | |||
// all the guts are in multifunction_input... | // all the guts are in multifunction_input... | |||
protected: | protected: | |||
/*override*/void reset() { base_type::reset(); } | /*override*/void reset() { base_type::reset(); } | |||
}; // multifunction_node | }; // multifunction_node | |||
template < typename Input, typename Output, typename Allocator > | template < typename Input, typename Output, typename Allocator > | |||
class multifunction_node<Input,Output,queueing,Allocator> : public graph_no de, public internal::multifunction_input<Input, | class multifunction_node<Input,Output,queueing,Allocator> : public graph_no de, public internal::multifunction_input<Input, | |||
typename internal::wrap_tuple_elements<std::tuple_size<Output>::value, | typename internal::wrap_tuple_elements<tbb::flow::tuple_size<Output>::v | |||
internal::function_output, Output>::type, Allocator> { | alue, internal::multifunction_output, Output>::type, Allocator> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
static const int N = std::tuple_size<Output>::value; | static const int N = tbb::flow::tuple_size<Output>::value; | |||
public: | public: | |||
typedef Input input_type; | typedef Input input_type; | |||
typedef typename internal::wrap_tuple_elements<N, internal::function_ou tput, Output>::type output_ports_type; | typedef typename internal::wrap_tuple_elements<N, internal::multifuncti on_output, Output>::type output_ports_type; | |||
private: | private: | |||
typedef typename internal::multifunction_input<input_type, output_ports _type, Allocator> base_type; | typedef typename internal::multifunction_input<input_type, output_ports _type, Allocator> base_type; | |||
typedef typename internal::function_input_queue<input_type,Allocator> q ueue_type; | typedef typename internal::function_input_queue<input_type,Allocator> q ueue_type; | |||
public: | public: | |||
template<typename Body> | template<typename Body> | |||
multifunction_node( graph &g, size_t concurrency, Body body) : | multifunction_node( graph &g, size_t concurrency, Body body) : | |||
graph_node(g), base_type(g,concurrency, body, new queue_type()) | graph_node(g), base_type(g,concurrency, body, new queue_type()) | |||
{} | {} | |||
multifunction_node( const multifunction_node &other) : | multifunction_node( const multifunction_node &other) : | |||
graph_node(other.my_graph), base_type(other, new queue_type()) | graph_node(other.my_graph), base_type(other, new queue_type()) | |||
skipping to change at line 862 | skipping to change at line 913 | |||
// all the guts are in multifunction_input... | // all the guts are in multifunction_input... | |||
protected: | protected: | |||
/*override*/void reset() { base_type::reset(); } | /*override*/void reset() { base_type::reset(); } | |||
}; // multifunction_node | }; // multifunction_node | |||
//! split_node: accepts a tuple as input, forwards each element of the tupl e to its | //! split_node: accepts a tuple as input, forwards each element of the tupl e to its | |||
// successors. The node has unlimited concurrency, so though it is marked as | // successors. The node has unlimited concurrency, so though it is marked as | |||
// "rejecting" it does not reject inputs. | // "rejecting" it does not reject inputs. | |||
template<typename TupleType, typename Allocator=cache_aligned_allocator<Tup leType> > | template<typename TupleType, typename Allocator=cache_aligned_allocator<Tup leType> > | |||
class split_node : public multifunction_node<TupleType, TupleType, rejectin g, Allocator> { | class split_node : public multifunction_node<TupleType, TupleType, rejectin g, Allocator> { | |||
static const int N = std::tuple_size<TupleType>::value; | static const int N = tbb::flow::tuple_size<TupleType>::value; | |||
typedef multifunction_node<TupleType,TupleType,rejecting,Allocator> bas e_type; | typedef multifunction_node<TupleType,TupleType,rejecting,Allocator> bas e_type; | |||
public: | public: | |||
typedef typename base_type::output_ports_type output_ports_type; | typedef typename base_type::output_ports_type output_ports_type; | |||
private: | private: | |||
struct splitting_body { | struct splitting_body { | |||
void operator()(const TupleType& t, output_ports_type &p) { | void operator()(const TupleType& t, output_ports_type &p) { | |||
internal::emit_element<N>::emit_this(t, p); | internal::emit_element<N>::emit_this(t, p); | |||
} | } | |||
}; | }; | |||
public: | public: | |||
typedef TupleType input_type; | typedef TupleType input_type; | |||
typedef Allocator allocator_type; | typedef Allocator allocator_type; | |||
split_node(graph &g) : base_type(g, unlimited, splitting_body()) {} | split_node(graph &g) : base_type(g, unlimited, splitting_body()) {} | |||
split_node( const split_node & other) : base_type(other) {} | split_node( const split_node & other) : base_type(other) {} | |||
}; | }; | |||
//! Implements an executable node that supports continue_msg -> Output | //! Implements an executable node that supports continue_msg -> Output | |||
template <typename Output> | template <typename Output> | |||
class continue_node : public graph_node, public internal::continue_input<Ou tput>, public internal::function_output<Output> { | class continue_node : public graph_node, public internal::continue_input<Ou tput>, public internal::function_output<Output> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
typedef continue_msg input_type; | typedef continue_msg input_type; | |||
typedef Output output_type; | typedef Output output_type; | |||
typedef sender< input_type > predecessor_type; | typedef sender< input_type > predecessor_type; | |||
typedef receiver< output_type > successor_type; | typedef receiver< output_type > successor_type; | |||
typedef internal::continue_input<Output> fInput_type; | ||||
typedef internal::function_output<output_type> fOutput_type; | typedef internal::function_output<output_type> fOutput_type; | |||
//! Constructor for executable node with continue_msg -> Output | //! Constructor for executable node with continue_msg -> Output | |||
template <typename Body > | template <typename Body > | |||
continue_node( graph &g, Body body ) : | continue_node( graph &g, Body body ) : | |||
graph_node(g), internal::continue_input<output_type>( g, body ) | graph_node(g), internal::continue_input<output_type>( g, body ) | |||
{} | {} | |||
//! Constructor for executable node with continue_msg -> Output | //! Constructor for executable node with continue_msg -> Output | |||
template <typename Body > | template <typename Body > | |||
continue_node( graph &g, int number_of_predecessors, Body body ) : | continue_node( graph &g, int number_of_predecessors, Body body ) : | |||
graph_node(g), internal::continue_input<output_type>( g, number_of_ predecessors, body ) | graph_node(g), internal::continue_input<output_type>( g, number_of_ predecessors, body ) | |||
{} | {} | |||
//! Copy constructor | //! Copy constructor | |||
continue_node( const continue_node& src ) : | continue_node( const continue_node& src ) : | |||
graph_node(src.my_graph), internal::continue_input<output_type>(src ), | graph_node(src.my_graph), internal::continue_input<output_type>(src ), | |||
internal::function_output<Output>() | internal::function_output<Output>() | |||
{} | {} | |||
bool try_put(const input_type &i) { return internal::continue_input<Out | ||||
put>::try_put(i); } | ||||
protected: | protected: | |||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
using fInput_type::try_put_task; | ||||
/*override*/void reset() { internal::continue_input<Output>::reset_rece iver(); } | /*override*/void reset() { internal::continue_input<Output>::reset_rece iver(); } | |||
/* override */ internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; } | /* override */ internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; } | |||
}; | }; | |||
template< typename T > | template< typename T > | |||
class overwrite_node : public graph_node, public receiver<T>, public sender <T> { | class overwrite_node : public graph_node, public receiver<T>, public sender <T> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
typedef T input_type; | typedef T input_type; | |||
typedef T output_type; | typedef T output_type; | |||
typedef sender< input_type > predecessor_type; | typedef sender< input_type > predecessor_type; | |||
typedef receiver< output_type > successor_type; | typedef receiver< output_type > successor_type; | |||
overwrite_node(graph &g) : graph_node(g), my_buffer_is_valid(false) { | overwrite_node(graph &g) : graph_node(g), my_buffer_is_valid(false) { | |||
my_successors.set_owner( this ); | my_successors.set_owner( this ); | |||
} | } | |||
skipping to change at line 943 | skipping to change at line 1000 | |||
my_successors.set_owner( this ); | my_successors.set_owner( this ); | |||
} | } | |||
~overwrite_node() {} | ~overwrite_node() {} | |||
/* override */ bool register_successor( successor_type &s ) { | /* override */ bool register_successor( successor_type &s ) { | |||
spin_mutex::scoped_lock l( my_mutex ); | spin_mutex::scoped_lock l( my_mutex ); | |||
if ( my_buffer_is_valid ) { | if ( my_buffer_is_valid ) { | |||
// We have a valid value that must be forwarded immediately. | // We have a valid value that must be forwarded immediately. | |||
if ( s.try_put( my_buffer ) || !s.register_predecessor( *this ) ) { | if ( s.try_put( my_buffer ) || !s.register_predecessor( *this ) ) { | |||
// We add the successor: it accepted our put or it rejected it but won't let use become a predecessor | // We add the successor: it accepted our put or it rejected it but won't let us become a predecessor | |||
my_successors.register_successor( s ); | my_successors.register_successor( s ); | |||
return true; | return true; | |||
} else { | } else { | |||
// We don't add the successor: it rejected our put and we b ecame its predecessor instead | // We don't add the successor: it rejected our put and we b ecame its predecessor instead | |||
return false; | return false; | |||
} | } | |||
} else { | } else { | |||
// No valid value yet, just add as successor | // No valid value yet, just add as successor | |||
my_successors.register_successor( s ); | my_successors.register_successor( s ); | |||
return true; | return true; | |||
} | } | |||
} | } | |||
/* override */ bool remove_successor( successor_type &s ) { | /* override */ bool remove_successor( successor_type &s ) { | |||
spin_mutex::scoped_lock l( my_mutex ); | spin_mutex::scoped_lock l( my_mutex ); | |||
my_successors.remove_successor(s); | my_successors.remove_successor(s); | |||
return true; | return true; | |||
} | } | |||
/* override */ bool try_put( const T &v ) { | ||||
spin_mutex::scoped_lock l( my_mutex ); | ||||
my_buffer = v; | ||||
my_buffer_is_valid = true; | ||||
my_successors.try_put(v); | ||||
return true; | ||||
} | ||||
/* override */ bool try_get( T &v ) { | /* override */ bool try_get( T &v ) { | |||
spin_mutex::scoped_lock l( my_mutex ); | spin_mutex::scoped_lock l( my_mutex ); | |||
if ( my_buffer_is_valid ) { | if ( my_buffer_is_valid ) { | |||
v = my_buffer; | v = my_buffer; | |||
return true; | return true; | |||
} else { | } else { | |||
return false; | return false; | |||
} | } | |||
} | } | |||
skipping to change at line 992 | skipping to change at line 1041 | |||
spin_mutex::scoped_lock l( my_mutex ); | spin_mutex::scoped_lock l( my_mutex ); | |||
return my_buffer_is_valid; | return my_buffer_is_valid; | |||
} | } | |||
void clear() { | void clear() { | |||
spin_mutex::scoped_lock l( my_mutex ); | spin_mutex::scoped_lock l( my_mutex ); | |||
my_buffer_is_valid = false; | my_buffer_is_valid = false; | |||
} | } | |||
protected: | protected: | |||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
/* override */ task * try_put_task( const T &v ) { | ||||
spin_mutex::scoped_lock l( my_mutex ); | ||||
my_buffer = v; | ||||
my_buffer_is_valid = true; | ||||
task * rtask = my_successors.try_put_task(v); | ||||
if(!rtask) rtask = SUCCESSFULLY_ENQUEUED; | ||||
return rtask; | ||||
} | ||||
/*override*/void reset() { my_buffer_is_valid = false; } | /*override*/void reset() { my_buffer_is_valid = false; } | |||
spin_mutex my_mutex; | spin_mutex my_mutex; | |||
internal::broadcast_cache< T, null_rw_mutex > my_successors; | internal::broadcast_cache< T, null_rw_mutex > my_successors; | |||
T my_buffer; | T my_buffer; | |||
bool my_buffer_is_valid; | bool my_buffer_is_valid; | |||
/*override*/void reset_receiver() {} | /*override*/void reset_receiver() {} | |||
}; | }; | |||
skipping to change at line 1016 | skipping to change at line 1076 | |||
typedef T output_type; | typedef T output_type; | |||
typedef sender< input_type > predecessor_type; | typedef sender< input_type > predecessor_type; | |||
typedef receiver< output_type > successor_type; | typedef receiver< output_type > successor_type; | |||
//! Constructor | //! Constructor | |||
write_once_node(graph& g) : overwrite_node<T>(g) {} | write_once_node(graph& g) : overwrite_node<T>(g) {} | |||
//! Copy constructor: call base class copy constructor | //! Copy constructor: call base class copy constructor | |||
write_once_node( const write_once_node& src ) : overwrite_node<T>(src) {} | write_once_node( const write_once_node& src ) : overwrite_node<T>(src) {} | |||
/* override */ bool try_put( const T &v ) { | protected: | |||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
/* override */ task *try_put_task( const T &v ) { | ||||
spin_mutex::scoped_lock l( this->my_mutex ); | spin_mutex::scoped_lock l( this->my_mutex ); | |||
if ( this->my_buffer_is_valid ) { | if ( this->my_buffer_is_valid ) { | |||
return false; | return NULL; | |||
} else { | } else { | |||
this->my_buffer = v; | this->my_buffer = v; | |||
this->my_buffer_is_valid = true; | this->my_buffer_is_valid = true; | |||
this->my_successors.try_put(v); | task *res = this->my_successors.try_put_task(v); | |||
return true; | if(!res) res = SUCCESSFULLY_ENQUEUED; | |||
return res; | ||||
} | } | |||
} | } | |||
}; | }; | |||
//! Forwards messages of type T to all successors | //! Forwards messages of type T to all successors | |||
template <typename T> | template <typename T> | |||
class broadcast_node : public graph_node, public receiver<T>, public sender <T> { | class broadcast_node : public graph_node, public receiver<T>, public sender <T> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
private: | ||||
internal::broadcast_cache<T> my_successors; | internal::broadcast_cache<T> my_successors; | |||
public: | public: | |||
typedef T input_type; | typedef T input_type; | |||
typedef T output_type; | typedef T output_type; | |||
typedef sender< input_type > predecessor_type; | typedef sender< input_type > predecessor_type; | |||
typedef receiver< output_type > successor_type; | typedef receiver< output_type > successor_type; | |||
broadcast_node(graph& g) : graph_node(g) { | broadcast_node(graph& g) : graph_node(g) { | |||
my_successors.set_owner( this ); | my_successors.set_owner( this ); | |||
} | } | |||
skipping to change at line 1063 | skipping to change at line 1130 | |||
my_successors.register_successor( r ); | my_successors.register_successor( r ); | |||
return true; | return true; | |||
} | } | |||
//! Removes s as a successor | //! Removes s as a successor | |||
virtual bool remove_successor( receiver<T> &r ) { | virtual bool remove_successor( receiver<T> &r ) { | |||
my_successors.remove_successor( r ); | my_successors.remove_successor( r ); | |||
return true; | return true; | |||
} | } | |||
/* override */ bool try_put( const T &t ) { | ||||
my_successors.try_put(t); | ||||
return true; | ||||
} | ||||
protected: | protected: | |||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
//! build a task to run the successor if possible. Default is old beha | ||||
vior. | ||||
/*override*/ task *try_put_task(const T& t) { | ||||
task *new_task = my_successors.try_put_task(t); | ||||
if(!new_task) new_task = SUCCESSFULLY_ENQUEUED; | ||||
return new_task; | ||||
} | ||||
/*override*/void reset() {} | /*override*/void reset() {} | |||
/*override*/void reset_receiver() {} | /*override*/void reset_receiver() {} | |||
}; | }; // broadcast_node | |||
#include "internal/_flow_graph_item_buffer_impl.h" | #include "internal/_flow_graph_item_buffer_impl.h" | |||
//! Forwards messages in arbitrary order | //! Forwards messages in arbitrary order | |||
template <typename T, typename A=cache_aligned_allocator<T> > | template <typename T, typename A=cache_aligned_allocator<T> > | |||
class buffer_node : public graph_node, public reservable_item_buffer<T, A>, public receiver<T>, public sender<T> { | class buffer_node : public graph_node, public reservable_item_buffer<T, A>, public receiver<T>, public sender<T> { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
typedef T input_type; | typedef T input_type; | |||
typedef T output_type; | typedef T output_type; | |||
typedef sender< input_type > predecessor_type; | typedef sender< input_type > predecessor_type; | |||
typedef receiver< output_type > successor_type; | typedef receiver< output_type > successor_type; | |||
typedef buffer_node<T, A> my_class; | typedef buffer_node<T, A> my_class; | |||
protected: | protected: | |||
typedef size_t size_type; | typedef size_t size_type; | |||
internal::round_robin_cache< T, null_rw_mutex > my_successors; | internal::round_robin_cache< T, null_rw_mutex > my_successors; | |||
task *my_parent; | task *my_parent; | |||
friend class internal::forward_task< buffer_node< T, A > >; | friend class internal::forward_task_bypass< buffer_node< T, A > >; | |||
enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res, put_item, try_fwd}; | enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res, put_item, try_fwd_task }; | |||
enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |||
// implements the aggregator_operation concept | // implements the aggregator_operation concept | |||
class buffer_operation : public internal::aggregated_operation< buffer_ operation > { | class buffer_operation : public internal::aggregated_operation< buffer_ operation > { | |||
public: | public: | |||
char type; | char type; | |||
T *elem; | T *elem; | |||
task * ltask; | ||||
successor_type *r; | successor_type *r; | |||
buffer_operation(const T& e, op_type t) : | buffer_operation(const T& e, op_type t) : type(char(t)), elem(const | |||
type(char(t)), elem(const_cast<T*>(&e)), r(NULL) {} | _cast<T*>(&e)) , ltask(NULL) , r(NULL) {} | |||
buffer_operation(op_type t) : type(char(t)), r(NULL) {} | buffer_operation(op_type t) : type(char(t)) , ltask(NULL) , r(NULL) | |||
{} | ||||
}; | }; | |||
bool forwarder_busy; | bool forwarder_busy; | |||
typedef internal::aggregating_functor<my_class, buffer_operation> my_ha ndler; | typedef internal::aggregating_functor<my_class, buffer_operation> my_ha ndler; | |||
friend class internal::aggregating_functor<my_class, buffer_operation>; | friend class internal::aggregating_functor<my_class, buffer_operation>; | |||
internal::aggregator< my_handler, buffer_operation> my_aggregator; | internal::aggregator< my_handler, buffer_operation> my_aggregator; | |||
virtual void handle_operations(buffer_operation *op_list) { | virtual void handle_operations(buffer_operation *op_list) { | |||
buffer_operation *tmp; | buffer_operation *tmp = NULL; | |||
bool try_forwarding=false; | bool try_forwarding=false; | |||
while (op_list) { | while (op_list) { | |||
tmp = op_list; | tmp = op_list; | |||
op_list = op_list->next; | op_list = op_list->next; | |||
switch (tmp->type) { | switch (tmp->type) { | |||
case reg_succ: internal_reg_succ(tmp); try_forwarding = true; break; | case reg_succ: internal_reg_succ(tmp); try_forwarding = true; break; | |||
case rem_succ: internal_rem_succ(tmp); break; | case rem_succ: internal_rem_succ(tmp); break; | |||
case req_item: internal_pop(tmp); break; | case req_item: internal_pop(tmp); break; | |||
case res_item: internal_reserve(tmp); break; | case res_item: internal_reserve(tmp); break; | |||
case rel_res: internal_release(tmp); try_forwarding = true; b reak; | case rel_res: internal_release(tmp); try_forwarding = true; b reak; | |||
case con_res: internal_consume(tmp); try_forwarding = true; b reak; | case con_res: internal_consume(tmp); try_forwarding = true; b reak; | |||
case put_item: internal_push(tmp); try_forwarding = true; brea k; | case put_item: internal_push(tmp); try_forwarding = true; brea k; | |||
case try_fwd: internal_forward(tmp); break; | case try_fwd_task: internal_forward_task(tmp); break; | |||
} | } | |||
} | } | |||
if (try_forwarding && !forwarder_busy) { | if (try_forwarding && !forwarder_busy) { | |||
forwarder_busy = true; | forwarder_busy = true; | |||
task::enqueue(*new(task::allocate_additional_child_of(*my_paren | task *new_task = new(task::allocate_additional_child_of(*my_par | |||
t)) internal::forward_task< buffer_node<input_type, A> >(*this)); | ent)) internal:: | |||
forward_task_bypass | ||||
< buffer_node<input_type, A> >(*this); | ||||
// tmp should point to the last item handled by the aggregator. | ||||
This is the operation | ||||
// the handling thread enqueued. So modifying that record will | ||||
be okay. | ||||
tbb::task *z = tmp->ltask; | ||||
tmp->ltask = combine_tasks(z, new_task); // in case the op gen | ||||
erated a task | ||||
} | } | |||
} | } | |||
inline task *grab_forwarding_task( buffer_operation &op_data) { | ||||
return op_data.ltask; | ||||
} | ||||
inline bool enqueue_forwarding_task(buffer_operation &op_data) { | ||||
task *ft = grab_forwarding_task(op_data); | ||||
if(ft) { | ||||
task::enqueue(*ft); | ||||
return true; | ||||
} | ||||
return false; | ||||
} | ||||
//! This is executed by an enqueued task, the "forwarder" | //! This is executed by an enqueued task, the "forwarder" | |||
virtual void forward() { | virtual task *forward_task() { | |||
buffer_operation op_data(try_fwd); | buffer_operation op_data(try_fwd_task); | |||
task *last_task = NULL; | ||||
do { | do { | |||
op_data.status = WAIT; | op_data.status = WAIT; | |||
op_data.ltask = NULL; | ||||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
tbb::task *xtask = op_data.ltask; | ||||
last_task = combine_tasks(last_task, xtask); | ||||
} while (op_data.status == SUCCEEDED); | } while (op_data.status == SUCCEEDED); | |||
return last_task; | ||||
} | } | |||
//! Register successor | //! Register successor | |||
virtual void internal_reg_succ(buffer_operation *op) { | virtual void internal_reg_succ(buffer_operation *op) { | |||
my_successors.register_successor(*(op->r)); | my_successors.register_successor(*(op->r)); | |||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
} | } | |||
//! Remove successor | //! Remove successor | |||
virtual void internal_rem_succ(buffer_operation *op) { | virtual void internal_rem_succ(buffer_operation *op) { | |||
my_successors.remove_successor(*(op->r)); | my_successors.remove_successor(*(op->r)); | |||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
} | } | |||
//! Tries to forward valid items to successors | //! Tries to forward valid items to successors | |||
virtual void internal_forward(buffer_operation *op) { | virtual void internal_forward_task(buffer_operation *op) { | |||
if (this->my_reserved || !this->item_valid(this->my_tail-1)) { | ||||
__TBB_store_with_release(op->status, FAILED); | ||||
this->forwarder_busy = false; | ||||
return; | ||||
} | ||||
T i_copy; | T i_copy; | |||
bool success = false; // flagged when a successor accepts | task * last_task = NULL; | |||
size_type counter = my_successors.size(); | size_type counter = my_successors.size(); | |||
// Try forwarding, giving each successor a chance | // Try forwarding, giving each successor a chance | |||
while (counter>0 && !this->buffer_empty() && this->item_valid(this- >my_tail-1)) { | while (counter>0 && !this->buffer_empty() && this->item_valid(this- >my_tail-1)) { | |||
this->fetch_back(i_copy); | this->fetch_back(i_copy); | |||
if( my_successors.try_put(i_copy) ) { | task *new_task = my_successors.try_put_task(i_copy); | |||
last_task = combine_tasks(last_task, new_task); | ||||
if(new_task) { | ||||
this->invalidate_back(); | this->invalidate_back(); | |||
--(this->my_tail); | --(this->my_tail); | |||
success = true; // found an accepting successor | ||||
} | } | |||
--counter; | --counter; | |||
} | } | |||
if (success && !counter) | op->ltask = last_task; // return task | |||
if (last_task && !counter) { | ||||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
} | ||||
else { | else { | |||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
forwarder_busy = false; | forwarder_busy = false; | |||
} | } | |||
} | } | |||
virtual void internal_push(buffer_operation *op) { | virtual void internal_push(buffer_operation *op) { | |||
this->push_back(*(op->elem)); | this->push_back(*(op->elem)); | |||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
} | } | |||
skipping to change at line 1240 | skipping to change at line 1346 | |||
// | // | |||
// message sender implementation | // message sender implementation | |||
// | // | |||
//! Adds a new successor. | //! Adds a new successor. | |||
/** Adds successor r to the list of successors; may forward tasks. */ | /** Adds successor r to the list of successors; may forward tasks. */ | |||
/* override */ bool register_successor( receiver<output_type> &r ) { | /* override */ bool register_successor( receiver<output_type> &r ) { | |||
buffer_operation op_data(reg_succ); | buffer_operation op_data(reg_succ); | |||
op_data.r = &r; | op_data.r = &r; | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
(void)enqueue_forwarding_task(op_data); | ||||
return true; | return true; | |||
} | } | |||
//! Removes a successor. | //! Removes a successor. | |||
/** Removes successor r from the list of successors. | /** Removes successor r from the list of successors. | |||
It also calls r.remove_predecessor(*this) to remove this node as a predecessor. */ | It also calls r.remove_predecessor(*this) to remove this node as a predecessor. */ | |||
/* override */ bool remove_successor( receiver<output_type> &r ) { | /* override */ bool remove_successor( receiver<output_type> &r ) { | |||
r.remove_predecessor(*this); | r.remove_predecessor(*this); | |||
buffer_operation op_data(rem_succ); | buffer_operation op_data(rem_succ); | |||
op_data.r = &r; | op_data.r = &r; | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
// even though this operation does not cause a forward, if we are t | ||||
he handler, and | ||||
// a forward is scheduled, we may be the first to reach this point | ||||
after the aggregator, | ||||
// and so should check for the task. | ||||
(void)enqueue_forwarding_task(op_data); | ||||
return true; | return true; | |||
} | } | |||
//! Request an item from the buffer_node | //! Request an item from the buffer_node | |||
/** true = v contains the returned item<BR> | /** true = v contains the returned item<BR> | |||
false = no item has been returned */ | false = no item has been returned */ | |||
/* override */ bool try_get( T &v ) { | /* override */ bool try_get( T &v ) { | |||
buffer_operation op_data(req_item); | buffer_operation op_data(req_item); | |||
op_data.elem = &v; | op_data.elem = &v; | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
(void)enqueue_forwarding_task(op_data); | ||||
return (op_data.status==SUCCEEDED); | return (op_data.status==SUCCEEDED); | |||
} | } | |||
//! Reserves an item. | //! Reserves an item. | |||
/** false = no item can be reserved<BR> | /** false = no item can be reserved<BR> | |||
true = an item is reserved */ | true = an item is reserved */ | |||
/* override */ bool try_reserve( T &v ) { | /* override */ bool try_reserve( T &v ) { | |||
buffer_operation op_data(res_item); | buffer_operation op_data(res_item); | |||
op_data.elem = &v; | op_data.elem = &v; | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
(void)enqueue_forwarding_task(op_data); | ||||
return (op_data.status==SUCCEEDED); | return (op_data.status==SUCCEEDED); | |||
} | } | |||
//! Release a reserved item. | //! Release a reserved item. | |||
/** true = item has been released and so remains in sender */ | /** true = item has been released and so remains in sender */ | |||
/* override */ bool try_release() { | /* override */ bool try_release() { | |||
buffer_operation op_data(rel_res); | buffer_operation op_data(rel_res); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
(void)enqueue_forwarding_task(op_data); | ||||
return true; | return true; | |||
} | } | |||
//! Consumes a reserved item. | //! Consumes a reserved item. | |||
/** true = item is removed from sender and reservation removed */ | /** true = item is removed from sender and reservation removed */ | |||
/* override */ bool try_consume() { | /* override */ bool try_consume() { | |||
buffer_operation op_data(con_res); | buffer_operation op_data(con_res); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
(void)enqueue_forwarding_task(op_data); | ||||
return true; | return true; | |||
} | } | |||
//! Receive an item | protected: | |||
/** true is always returned */ | ||||
/* override */ bool try_put(const T &t) { | template< typename R, typename B > friend class run_and_put_task; | |||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
//! receive an item, return a task *if possible | ||||
/* override */ task *try_put_task(const T &t) { | ||||
buffer_operation op_data(t, put_item); | buffer_operation op_data(t, put_item); | |||
my_aggregator.execute(&op_data); | my_aggregator.execute(&op_data); | |||
return true; | task *ft = grab_forwarding_task(op_data); | |||
if(!ft) { | ||||
ft = SUCCESSFULLY_ENQUEUED; | ||||
} | ||||
return ft; | ||||
} | } | |||
protected: | ||||
/*override*/void reset() { | /*override*/void reset() { | |||
reservable_item_buffer<T, A>::reset(); | reservable_item_buffer<T, A>::reset(); | |||
forwarder_busy = false; | forwarder_busy = false; | |||
} | } | |||
/*override*/void reset_receiver() { | /*override*/void reset_receiver() { | |||
// nothing to do; no predecesor_cache | // nothing to do; no predecesor_cache | |||
} | } | |||
}; | }; // buffer_node | |||
//! Forwards messages in FIFO order | //! Forwards messages in FIFO order | |||
template <typename T, typename A=cache_aligned_allocator<T> > | template <typename T, typename A=cache_aligned_allocator<T> > | |||
class queue_node : public buffer_node<T, A> { | class queue_node : public buffer_node<T, A> { | |||
protected: | protected: | |||
typedef typename buffer_node<T, A>::size_type size_type; | typedef typename buffer_node<T, A>::size_type size_type; | |||
typedef typename buffer_node<T, A>::buffer_operation queue_operation; | typedef typename buffer_node<T, A>::buffer_operation queue_operation; | |||
enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |||
//! Tries to forward valid items to successors | /* override */ void internal_forward_task(queue_operation *op) { | |||
/* override */ void internal_forward(queue_operation *op) { | ||||
T i_copy; | ||||
bool success = false; // flagged when a successor accepts | ||||
size_type counter = this->my_successors.size(); | ||||
if (this->my_reserved || !this->item_valid(this->my_head)) { | if (this->my_reserved || !this->item_valid(this->my_head)) { | |||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
this->forwarder_busy = false; | this->forwarder_busy = false; | |||
return; | return; | |||
} | } | |||
T i_copy; | ||||
task *last_task = NULL; | ||||
size_type counter = this->my_successors.size(); | ||||
// Keep trying to send items while there is at least one accepting successor | // Keep trying to send items while there is at least one accepting successor | |||
while (counter>0 && this->item_valid(this->my_head)) { | while (counter>0 && this->item_valid(this->my_head)) { | |||
this->fetch_front(i_copy); | this->fetch_front(i_copy); | |||
if(this->my_successors.try_put(i_copy)) { | task *new_task = this->my_successors.try_put_task(i_copy); | |||
this->invalidate_front(); | if(new_task) { | |||
++(this->my_head); | this->invalidate_front(); | |||
success = true; // found an accepting successor | ++(this->my_head); | |||
last_task = combine_tasks(last_task, new_task); | ||||
} | } | |||
--counter; | --counter; | |||
} | } | |||
if (success && !counter) | op->ltask = last_task; | |||
if (last_task && !counter) | ||||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
else { | else { | |||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
this->forwarder_busy = false; | this->forwarder_busy = false; | |||
} | } | |||
} | } | |||
/* override */ void internal_pop(queue_operation *op) { | /* override */ void internal_pop(queue_operation *op) { | |||
if ( this->my_reserved || !this->item_valid(this->my_head)){ | if ( this->my_reserved || !this->item_valid(this->my_head)){ | |||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
skipping to change at line 1456 | skipping to change at line 1578 | |||
base_type::reset(); | base_type::reset(); | |||
} | } | |||
typedef typename buffer_node<T, A>::size_type size_type; | typedef typename buffer_node<T, A>::size_type size_type; | |||
typedef typename buffer_node<T, A>::item_type item_type; | typedef typename buffer_node<T, A>::item_type item_type; | |||
typedef typename buffer_node<T, A>::buffer_operation prio_operation; | typedef typename buffer_node<T, A>::buffer_operation prio_operation; | |||
enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |||
/* override */ void handle_operations(prio_operation *op_list) { | /* override */ void handle_operations(prio_operation *op_list) { | |||
prio_operation *tmp /*, *pop_list*/ ; | prio_operation *tmp = op_list /*, *pop_list*/ ; | |||
bool try_forwarding=false; | bool try_forwarding=false; | |||
while (op_list) { | while (op_list) { | |||
tmp = op_list; | tmp = op_list; | |||
op_list = op_list->next; | op_list = op_list->next; | |||
switch (tmp->type) { | switch (tmp->type) { | |||
case buffer_node<T, A>::reg_succ: this->internal_reg_succ(tmp); try_forwarding = true; break; | case buffer_node<T, A>::reg_succ: this->internal_reg_succ(tmp); try_forwarding = true; break; | |||
case buffer_node<T, A>::rem_succ: this->internal_rem_succ(tmp); break; | case buffer_node<T, A>::rem_succ: this->internal_rem_succ(tmp); break; | |||
case buffer_node<T, A>::put_item: internal_push(tmp); try_forwa rding = true; break; | case buffer_node<T, A>::put_item: internal_push(tmp); try_forwa rding = true; break; | |||
case buffer_node<T, A>::try_fwd: internal_forward(tmp); break; | case buffer_node<T, A>::try_fwd_task: internal_forward_task(tmp ); break; | |||
case buffer_node<T, A>::rel_res: internal_release(tmp); try_for warding = true; break; | case buffer_node<T, A>::rel_res: internal_release(tmp); try_for warding = true; break; | |||
case buffer_node<T, A>::con_res: internal_consume(tmp); try_for warding = true; break; | case buffer_node<T, A>::con_res: internal_consume(tmp); try_for warding = true; break; | |||
case buffer_node<T, A>::req_item: internal_pop(tmp); break; | case buffer_node<T, A>::req_item: internal_pop(tmp); break; | |||
case buffer_node<T, A>::res_item: internal_reserve(tmp); break; | case buffer_node<T, A>::res_item: internal_reserve(tmp); break; | |||
} | } | |||
} | } | |||
// process pops! for now, no special pop processing | // process pops! for now, no special pop processing | |||
if (mark<this->my_tail) heapify(); | if (mark<this->my_tail) heapify(); | |||
if (try_forwarding && !this->forwarder_busy) { | if (try_forwarding && !this->forwarder_busy) { | |||
this->forwarder_busy = true; | this->forwarder_busy = true; | |||
task::enqueue(*new(task::allocate_additional_child_of(*(this->m | task *new_task = new(task::allocate_additional_child_of(*(this- | |||
y_parent))) internal::forward_task< buffer_node<input_type, A> >(*this)); | >my_parent))) internal:: | |||
forward_task_bypass | ||||
< buffer_node<input_type, A> >(*this); | ||||
// tmp should point to the last item handled by the aggregator. | ||||
This is the operation | ||||
// the handling thread enqueued. So modifying that record will | ||||
be okay. | ||||
tbb::task *tmp1 = tmp->ltask; | ||||
tmp->ltask = combine_tasks(tmp1, new_task); | ||||
} | } | |||
} | } | |||
//! Tries to forward valid items to successors | //! Tries to forward valid items to successors | |||
/* override */ void internal_forward(prio_operation *op) { | /* override */ void internal_forward_task(prio_operation *op) { | |||
T i_copy; | T i_copy; | |||
bool success = false; // flagged when a successor accepts | task * last_task = NULL; // flagged when a successor accepts | |||
size_type counter = this->my_successors.size(); | size_type counter = this->my_successors.size(); | |||
if (this->my_reserved || this->my_tail == 0) { | if (this->my_reserved || this->my_tail == 0) { | |||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
this->forwarder_busy = false; | this->forwarder_busy = false; | |||
return; | return; | |||
} | } | |||
// Keep trying to send while there exists an accepting successor | // Keep trying to send while there exists an accepting successor | |||
while (counter>0 && this->my_tail > 0) { | while (counter>0 && this->my_tail > 0) { | |||
i_copy = this->my_array[0].first; | i_copy = this->my_array[0].first; | |||
bool msg = this->my_successors.try_put(i_copy); | task * new_task = this->my_successors.try_put_task(i_copy); | |||
if ( msg == true ) { | last_task = combine_tasks(last_task, new_task); | |||
if ( new_task ) { | ||||
if (mark == this->my_tail) --mark; | if (mark == this->my_tail) --mark; | |||
--(this->my_tail); | --(this->my_tail); | |||
this->my_array[0].first=this->my_array[this->my_tail].first ; | this->my_array[0].first=this->my_array[this->my_tail].first ; | |||
if (this->my_tail > 1) // don't reheap for heap of size 1 | if (this->my_tail > 1) // don't reheap for heap of size 1 | |||
reheap(); | reheap(); | |||
success = true; // found an accepting successor | ||||
} | } | |||
--counter; | --counter; | |||
} | } | |||
if (success && !counter) | op->ltask = last_task; | |||
if (last_task && !counter) | ||||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
else { | else { | |||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
this->forwarder_busy = false; | this->forwarder_busy = false; | |||
} | } | |||
} | } | |||
/* override */ void internal_push(prio_operation *op) { | /* override */ void internal_push(prio_operation *op) { | |||
if ( this->my_tail >= this->my_array_size ) | if ( this->my_tail >= this->my_array_size ) | |||
this->grow_my_array( this->my_tail + 1 ); | this->grow_my_array( this->my_tail + 1 ); | |||
this->my_array[this->my_tail] = std::make_pair( *(op->elem), true ) ; | this->my_array[this->my_tail] = std::make_pair( *(op->elem), true ) ; | |||
++(this->my_tail); | ++(this->my_tail); | |||
__TBB_store_with_release(op->status, SUCCEEDED); | __TBB_store_with_release(op->status, SUCCEEDED); | |||
} | } | |||
/* override */ void internal_pop(prio_operation *op) { | /* override */ void internal_pop(prio_operation *op) { | |||
if ( this->my_reserved == true || this->my_tail == 0 ) { | if ( this->my_reserved == true || this->my_tail == 0 ) { | |||
__TBB_store_with_release(op->status, FAILED); | __TBB_store_with_release(op->status, FAILED); | |||
} | } | |||
else { | else { | |||
if (mark<this->my_tail && | if (mark<this->my_tail && | |||
compare(this->my_array[0].first, | compare(this->my_array[0].first, | |||
this->my_array[this->my_tail-1].first)) { | this->my_array[this->my_tail-1].first)) { | |||
// there are newly pushed elems; last one higher than top | // there are newly pushed elems; last one higher than top | |||
// copy the data | // copy the data | |||
skipping to change at line 1620 | skipping to change at line 1750 | |||
this->my_array[cur_pos].first = this->my_array[this->my_tail].first ; | this->my_array[cur_pos].first = this->my_array[this->my_tail].first ; | |||
} | } | |||
}; | }; | |||
//! Forwards messages only if the threshold has not been reached | //! Forwards messages only if the threshold has not been reached | |||
/** This node forwards items until its threshold is reached. | /** This node forwards items until its threshold is reached. | |||
It contains no buffering. If the downstream node rejects, the | It contains no buffering. If the downstream node rejects, the | |||
message is dropped. */ | message is dropped. */ | |||
template< typename T > | template< typename T > | |||
class limiter_node : public graph_node, public receiver< T >, public sender < T > { | class limiter_node : public graph_node, public receiver< T >, public sender < T > { | |||
protected: | ||||
using graph_node::my_graph; | using graph_node::my_graph; | |||
public: | public: | |||
typedef T input_type; | typedef T input_type; | |||
typedef T output_type; | typedef T output_type; | |||
typedef sender< input_type > predecessor_type; | typedef sender< input_type > predecessor_type; | |||
typedef receiver< output_type > successor_type; | typedef receiver< output_type > successor_type; | |||
private: | private: | |||
task *my_root_task; | task *my_root_task; | |||
size_t my_threshold; | size_t my_threshold; | |||
size_t my_count; | size_t my_count; | |||
internal::predecessor_cache< T > my_predecessors; | internal::predecessor_cache< T > my_predecessors; | |||
spin_mutex my_mutex; | spin_mutex my_mutex; | |||
internal::broadcast_cache< T > my_successors; | internal::broadcast_cache< T > my_successors; | |||
int init_decrement_predecessors; | int init_decrement_predecessors; | |||
friend class internal::forward_task< limiter_node<T> >; | friend class internal::forward_task_bypass< limiter_node<T> >; | |||
// Let decrementer call decrement_counter() | // Let decrementer call decrement_counter() | |||
friend class internal::decrementer< limiter_node<T> >; | friend class internal::decrementer< limiter_node<T> >; | |||
void decrement_counter() { | // only returns a valid task pointer or NULL, never SUCCESSFULLY_ENQUEU | |||
ED | ||||
task * decrement_counter() { | ||||
input_type v; | input_type v; | |||
task *rval = NULL; | ||||
// If we can't get / put an item immediately then drop the count | // If we can't get / put an item immediately then drop the count | |||
if ( my_predecessors.get_item( v ) == false | if ( my_predecessors.get_item( v ) == false | |||
|| my_successors.try_put(v) == false ) { | || (rval = my_successors.try_put_task(v)) == NULL ) { | |||
spin_mutex::scoped_lock lock(my_mutex); | spin_mutex::scoped_lock lock(my_mutex); | |||
--my_count; | --my_count; | |||
if ( !my_predecessors.empty() ) | if ( !my_predecessors.empty() ) { | |||
task::enqueue( * new ( task::allocate_additional_child_of( | task *rtask = new ( task::allocate_additional_child_of( *my | |||
*my_root_task ) ) | _root_task ) ) | |||
internal::forward_task< limiter_node<T> >( *thi | internal::forward_task_bypass< limiter_node<T> >( *this | |||
s ) ); | ); | |||
__TBB_ASSERT(!rval, "Have two tasks to handle"); | ||||
return rtask; | ||||
} | ||||
} | } | |||
return rval; | ||||
} | } | |||
void forward() { | void forward() { | |||
{ | { | |||
spin_mutex::scoped_lock lock(my_mutex); | spin_mutex::scoped_lock lock(my_mutex); | |||
if ( my_count < my_threshold ) | if ( my_count < my_threshold ) | |||
++my_count; | ++my_count; | |||
else | else | |||
return; | return; | |||
} | } | |||
decrement_counter(); | task * rtask = decrement_counter(); | |||
if(rtask) task::enqueue(*rtask); | ||||
} | ||||
task *forward_task() { | ||||
spin_mutex::scoped_lock lock(my_mutex); | ||||
if ( my_count >= my_threshold ) | ||||
return NULL; | ||||
++my_count; | ||||
task * rtask = decrement_counter(); | ||||
return rtask; | ||||
} | } | |||
public: | public: | |||
//! The internal receiver< continue_msg > that decrements the count | //! The internal receiver< continue_msg > that decrements the count | |||
internal::decrementer< limiter_node<T> > decrement; | internal::decrementer< limiter_node<T> > decrement; | |||
//! Constructor | //! Constructor | |||
limiter_node(graph &g, size_t threshold, int num_decrement_predecessors =0) : | limiter_node(graph &g, size_t threshold, int num_decrement_predecessors =0) : | |||
graph_node(g), my_root_task(g.root_task()), my_threshold(threshold) , my_count(0), | graph_node(g), my_root_task(g.root_task()), my_threshold(threshold) , my_count(0), | |||
init_decrement_predecessors(num_decrement_predecessors), | init_decrement_predecessors(num_decrement_predecessors), | |||
skipping to change at line 1707 | skipping to change at line 1854 | |||
} | } | |||
//! Removes a successor from this node | //! Removes a successor from this node | |||
/** r.remove_predecessor(*this) is also called. */ | /** r.remove_predecessor(*this) is also called. */ | |||
/* override */ bool remove_successor( receiver<output_type> &r ) { | /* override */ bool remove_successor( receiver<output_type> &r ) { | |||
r.remove_predecessor(*this); | r.remove_predecessor(*this); | |||
my_successors.remove_successor(r); | my_successors.remove_successor(r); | |||
return true; | return true; | |||
} | } | |||
//! Puts an item to this receiver | ||||
/* override */ bool try_put( const T &t ) { | ||||
{ | ||||
spin_mutex::scoped_lock lock(my_mutex); | ||||
if ( my_count >= my_threshold ) | ||||
return false; | ||||
else | ||||
++my_count; | ||||
} | ||||
bool msg = my_successors.try_put(t); | ||||
if ( msg != true ) { | ||||
spin_mutex::scoped_lock lock(my_mutex); | ||||
--my_count; | ||||
if ( !my_predecessors.empty() ) | ||||
task::enqueue( * new ( task::allocate_additional_child_of( | ||||
*my_root_task ) ) | ||||
internal::forward_task< limiter_node<T> >( *thi | ||||
s ) ); | ||||
} | ||||
return msg; | ||||
} | ||||
//! Removes src from the list of cached predecessors. | //! Removes src from the list of cached predecessors. | |||
/* override */ bool register_predecessor( predecessor_type &src ) { | /* override */ bool register_predecessor( predecessor_type &src ) { | |||
spin_mutex::scoped_lock lock(my_mutex); | spin_mutex::scoped_lock lock(my_mutex); | |||
my_predecessors.add( src ); | my_predecessors.add( src ); | |||
if ( my_count < my_threshold && !my_successors.empty() ) | if ( my_count < my_threshold && !my_successors.empty() ) { | |||
task::enqueue( * new ( task::allocate_additional_child_of( *my_ root_task ) ) | task::enqueue( * new ( task::allocate_additional_child_of( *my_ root_task ) ) | |||
internal::forward_task< limiter_node<T> >( *this | internal:: | |||
) ); | forward_task_bypass | |||
< limiter_node<T> >( *this ) ); | ||||
} | ||||
return true; | return true; | |||
} | } | |||
//! Removes src from the list of cached predecessors. | //! Removes src from the list of cached predecessors. | |||
/* override */ bool remove_predecessor( predecessor_type &src ) { | /* override */ bool remove_predecessor( predecessor_type &src ) { | |||
my_predecessors.remove( src ); | my_predecessors.remove( src ); | |||
return true; | return true; | |||
} | } | |||
protected: | protected: | |||
template< typename R, typename B > friend class run_and_put_task; | ||||
template<typename X, typename Y> friend class internal::broadcast_cache | ||||
; | ||||
template<typename X, typename Y> friend class internal::round_robin_cac | ||||
he; | ||||
//! Puts an item to this receiver | ||||
/* override */ task *try_put_task( const T &t ) { | ||||
{ | ||||
spin_mutex::scoped_lock lock(my_mutex); | ||||
if ( my_count >= my_threshold ) | ||||
return NULL; | ||||
else | ||||
++my_count; | ||||
} | ||||
task * rtask = my_successors.try_put_task(t); | ||||
if ( !rtask ) { // try_put_task failed. | ||||
spin_mutex::scoped_lock lock(my_mutex); | ||||
--my_count; | ||||
if ( !my_predecessors.empty() ) { | ||||
rtask = new ( task::allocate_additional_child_of( *my_root_ | ||||
task ) ) | ||||
internal::forward_task_bypass< limiter_node<T> >( *this | ||||
); | ||||
} | ||||
} | ||||
return rtask; | ||||
} | ||||
/*override*/void reset() { | /*override*/void reset() { | |||
my_count = 0; | my_count = 0; | |||
my_predecessors.reset(); | my_predecessors.reset(); | |||
decrement.reset_receiver(); | decrement.reset_receiver(); | |||
} | } | |||
/*override*/void reset_receiver() { my_predecessors.reset(); } | /*override*/void reset_receiver() { my_predecessors.reset(); } | |||
}; | }; // limiter_node | |||
#include "internal/_flow_graph_join_impl.h" | #include "internal/_flow_graph_join_impl.h" | |||
using internal::reserving_port; | using internal::reserving_port; | |||
using internal::queueing_port; | using internal::queueing_port; | |||
using internal::tag_matching_port; | using internal::tag_matching_port; | |||
using internal::input_port; | using internal::input_port; | |||
using internal::tag_value; | using internal::tag_value; | |||
using internal::NO_TAG; | using internal::NO_TAG; | |||
template<typename OutputTuple, graph_buffer_policy JP=queueing> class join_ node; | template<typename OutputTuple, graph_buffer_policy JP=queueing> class join_ node; | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class join_node<OutputTuple,reserving>: public internal::unfolded_join_node <std::tuple_size<OutputTuple>::value, reserving_port, OutputTuple, reservin g> { | class join_node<OutputTuple,reserving>: public internal::unfolded_join_node <tbb::flow::tuple_size<OutputTuple>::value, reserving_port, OutputTuple, re serving> { | |||
private: | private: | |||
static const int N = std::tuple_size<OutputTuple>::value; | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |||
typedef typename internal::unfolded_join_node<N, reserving_port, Output Tuple, reserving> unfolded_type; | typedef typename internal::unfolded_join_node<N, reserving_port, Output Tuple, reserving> unfolded_type; | |||
public: | public: | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
typedef typename unfolded_type::input_ports_type input_ports_type; | typedef typename unfolded_type::input_ports_type input_ports_type; | |||
join_node(graph &g) : unfolded_type(g) { } | join_node(graph &g) : unfolded_type(g) { } | |||
join_node(const join_node &other) : unfolded_type(other) {} | join_node(const join_node &other) : unfolded_type(other) {} | |||
}; | }; | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class join_node<OutputTuple,queueing>: public internal::unfolded_join_node< std::tuple_size<OutputTuple>::value, queueing_port, OutputTuple, queueing> { | class join_node<OutputTuple,queueing>: public internal::unfolded_join_node< tbb::flow::tuple_size<OutputTuple>::value, queueing_port, OutputTuple, queu eing> { | |||
private: | private: | |||
static const int N = std::tuple_size<OutputTuple>::value; | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |||
typedef typename internal::unfolded_join_node<N, queueing_port, OutputT uple, queueing> unfolded_type; | typedef typename internal::unfolded_join_node<N, queueing_port, OutputT uple, queueing> unfolded_type; | |||
public: | public: | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
typedef typename unfolded_type::input_ports_type input_ports_type; | typedef typename unfolded_type::input_ports_type input_ports_type; | |||
join_node(graph &g) : unfolded_type(g) { } | join_node(graph &g) : unfolded_type(g) { } | |||
join_node(const join_node &other) : unfolded_type(other) {} | join_node(const join_node &other) : unfolded_type(other) {} | |||
}; | }; | |||
// template for tag_matching join_node | // template for tag_matching join_node | |||
template<typename OutputTuple> | template<typename OutputTuple> | |||
class join_node<OutputTuple, tag_matching> : public internal::unfolded_join _node<std::tuple_size<OutputTuple>::value, | class join_node<OutputTuple, tag_matching> : public internal::unfolded_join _node<tbb::flow::tuple_size<OutputTuple>::value, | |||
tag_matching_port, OutputTuple, tag_matching> { | tag_matching_port, OutputTuple, tag_matching> { | |||
private: | private: | |||
static const int N = std::tuple_size<OutputTuple>::value; | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |||
typedef typename internal::unfolded_join_node<N, tag_matching_port, Out putTuple, tag_matching> unfolded_type; | typedef typename internal::unfolded_join_node<N, tag_matching_port, Out putTuple, tag_matching> unfolded_type; | |||
public: | public: | |||
typedef OutputTuple output_type; | typedef OutputTuple output_type; | |||
typedef typename unfolded_type::input_ports_type input_ports_type; | typedef typename unfolded_type::input_ports_type input_ports_type; | |||
template<typename B0, typename B1> | template<typename B0, typename B1> | |||
join_node(graph &g, B0 b0, B1 b1) : unfolded_type(g, b0, b1) { } | join_node(graph &g, B0 b0, B1 b1) : unfolded_type(g, b0, b1) { } | |||
template<typename B0, typename B1, typename B2> | template<typename B0, typename B1, typename B2> | |||
join_node(graph &g, B0 b0, B1 b1, B2 b2) : unfolded_type(g, b0, b1, b2) { } | join_node(graph &g, B0 b0, B1 b1, B2 b2) : unfolded_type(g, b0, b1, b2) { } | |||
template<typename B0, typename B1, typename B2, typename B3> | template<typename B0, typename B1, typename B2, typename B3> | |||
join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : unfolded_type(g, b0, b1, b2, b3) { } | join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : unfolded_type(g, b0, b1, b2, b3) { } | |||
skipping to change at line 1840 | skipping to change at line 1993 | |||
join_node(const join_node &other) : unfolded_type(other) {} | join_node(const join_node &other) : unfolded_type(other) {} | |||
}; | }; | |||
#if TBB_PREVIEW_GRAPH_NODES | #if TBB_PREVIEW_GRAPH_NODES | |||
// or node | // or node | |||
#include "internal/_flow_graph_or_impl.h" | #include "internal/_flow_graph_or_impl.h" | |||
template<typename InputTuple> | template<typename InputTuple> | |||
class or_node : public internal::unfolded_or_node<InputTuple> { | class or_node : public internal::unfolded_or_node<InputTuple> { | |||
private: | private: | |||
static const int N = std::tuple_size<InputTuple>::value; | static const int N = tbb::flow::tuple_size<InputTuple>::value; | |||
public: | public: | |||
typedef typename internal::or_output_type<InputTuple>::type output_type ; | typedef typename internal::or_output_type<InputTuple>::type output_type ; | |||
typedef typename internal::unfolded_or_node<InputTuple> unfolded_type; | typedef typename internal::unfolded_or_node<InputTuple> unfolded_type; | |||
or_node(graph& g) : unfolded_type(g) { } | or_node(graph& g) : unfolded_type(g) { } | |||
// Copy constructor | // Copy constructor | |||
or_node( const or_node& other ) : unfolded_type(other) { } | or_node( const or_node& other ) : unfolded_type(other) { } | |||
}; | }; | |||
#endif // TBB_PREVIEW_GRAPH_NODES | #endif // TBB_PREVIEW_GRAPH_NODES | |||
//! Makes an edge between a single predecessor and a single successor | //! Makes an edge between a single predecessor and a single successor | |||
End of changes. 115 change blocks. | ||||
157 lines changed or deleted | 344 lines changed or added | |||
gcc_generic.h | gcc_generic.h | |||
---|---|---|---|---|
skipping to change at line 40 | skipping to change at line 40 | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
#define __TBB_machine_gcc_generic_H | #define __TBB_machine_gcc_generic_H | |||
#include <stdint.h> | #include <stdint.h> | |||
#include <unistd.h> | #include <unistd.h> | |||
#define __TBB_WORDSIZE __SIZEOF_POINTER__ | #define __TBB_WORDSIZE __SIZEOF_POINTER__ | |||
#if __TBB_GCC_64BIT_ATOMIC_BUILTINS_BROKEN | ||||
#define __TBB_64BIT_ATOMICS 0 | ||||
#endif | ||||
/** FPU control setting not available for non-Intel architectures on Androi | ||||
d **/ | ||||
#if __ANDROID__ && __TBB_generic_arch | ||||
#define __TBB_CPU_CTL_ENV_PRESENT 0 | ||||
#endif | ||||
#ifdef __BYTE_ORDER__ | #ifdef __BYTE_ORDER__ | |||
#if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ | #if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ | |||
#define __TBB_BIG_ENDIAN 1 | #define __TBB_BIG_ENDIAN 1 | |||
#elif __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ | #elif __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ | |||
#define __TBB_BIG_ENDIAN 0 | #define __TBB_BIG_ENDIAN 0 | |||
#elif __BYTE_ORDER__==__ORDER_PDP_ENDIAN__ | #elif __BYTE_ORDER__==__ORDER_PDP_ENDIAN__ | |||
#define __TBB_BIG_ENDIAN -1 // not currently supported | #define __TBB_BIG_ENDIAN -1 // not currently supported | |||
#endif | #endif | |||
#endif | #endif | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 10 lines changed or added | |||
linux_common.h | linux_common.h | |||
---|---|---|---|---|
skipping to change at line 36 | skipping to change at line 36 | |||
the GNU General Public License. | the GNU General Public License. | |||
*/ | */ | |||
#ifndef __TBB_machine_H | #ifndef __TBB_machine_H | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
#include <sched.h> | #include <sched.h> | |||
#define __TBB_Yield() sched_yield() | #define __TBB_Yield() sched_yield() | |||
#include <unistd.h> | ||||
/* 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. | |||
skipping to change at line 67 | skipping to change at line 68 | |||
#ifndef __TBB_ASSERT | #ifndef __TBB_ASSERT | |||
#error machine specific headers must be included after tbb_stddef.h | #error machine specific headers must be included after tbb_stddef.h | |||
#endif | #endif | |||
namespace tbb { | namespace tbb { | |||
namespace internal { | namespace internal { | |||
inline int futex_wait( void *futex, int comparand ) { | inline int futex_wait( void *futex, int comparand ) { | |||
int r = ::syscall( SYS_futex,futex,__TBB_FUTEX_WAIT,comparand,NULL,NULL ,0 ); | int r = syscall( SYS_futex,futex,__TBB_FUTEX_WAIT,comparand,NULL,NULL,0 ); | |||
#if TBB_USE_ASSERT | #if TBB_USE_ASSERT | |||
int e = errno; | int e = errno; | |||
__TBB_ASSERT( r==0||r==EWOULDBLOCK||(r==-1&&(e==EAGAIN||e==EINTR)), "fu tex_wait failed." ); | __TBB_ASSERT( r==0||r==EWOULDBLOCK||(r==-1&&(e==EAGAIN||e==EINTR)), "fu tex_wait failed." ); | |||
#endif /* TBB_USE_ASSERT */ | #endif /* TBB_USE_ASSERT */ | |||
return r; | return r; | |||
} | } | |||
inline int futex_wakeup_one( void *futex ) { | inline int futex_wakeup_one( void *futex ) { | |||
int r = ::syscall( SYS_futex,futex,__TBB_FUTEX_WAKE,1,NULL,NULL,0 ); | int r = ::syscall( SYS_futex,futex,__TBB_FUTEX_WAKE,1,NULL,NULL,0 ); | |||
__TBB_ASSERT( r==0||r==1, "futex_wakeup_one: more than one thread woken up?" ); | __TBB_ASSERT( r==0||r==1, "futex_wakeup_one: more than one thread woken up?" ); | |||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 2 lines changed or added | |||
linux_ia32.h | linux_ia32.h | |||
---|---|---|---|---|
skipping to change at line 36 | skipping to change at line 36 | |||
the GNU General Public License. | the GNU General Public License. | |||
*/ | */ | |||
#if !defined(__TBB_machine_H) || defined(__TBB_machine_linux_ia32_H) | #if !defined(__TBB_machine_H) || defined(__TBB_machine_linux_ia32_H) | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
#define __TBB_machine_linux_ia32_H | #define __TBB_machine_linux_ia32_H | |||
#include <stdint.h> | #include <stdint.h> | |||
#include <unistd.h> | #include "gcc_ia32_common.h" | |||
#define __TBB_WORDSIZE 4 | #define __TBB_WORDSIZE 4 | |||
#define __TBB_BIG_ENDIAN 0 | #define __TBB_BIG_ENDIAN 0 | |||
#define __TBB_compiler_fence() __asm__ __volatile__("": : :"memory") | #define __TBB_compiler_fence() __asm__ __volatile__("": : :"memory") | |||
#define __TBB_control_consistency_helper() __TBB_compiler_fence() | #define __TBB_control_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_acquire_consistency_helper() __TBB_compiler_fence() | #define __TBB_acquire_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_release_consistency_helper() __TBB_compiler_fence() | #define __TBB_release_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_full_memory_fence() __asm__ __volatile__("mfence": : :"memory") | #define __TBB_full_memory_fence() __asm__ __volatile__("mfence": : :"memory") | |||
skipping to change at line 99 | skipping to change at line 99 | |||
#if __INTEL_COMPILER | #if __INTEL_COMPILER | |||
#pragma warning( push ) | #pragma warning( push ) | |||
// reference to EBX in a function requiring stack alignment | // reference to EBX in a function requiring stack alignment | |||
#pragma warning( disable: 998 ) | #pragma warning( disable: 998 ) | |||
#endif | #endif | |||
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 ) { | |||
#if __TBB_GCC_BUILTIN_ATOMICS_PRESENT | #if __TBB_GCC_BUILTIN_ATOMICS_PRESENT | |||
return __sync_val_compare_and_swap( reinterpret_cast<volatile int64_t*> (ptr), comparand, value ); | return __sync_val_compare_and_swap( reinterpret_cast<volatile int64_t*> (ptr), comparand, value ); | |||
#else /* !__TBB_GCC_BUILTIN_ATOMICS_PRESENT */ | #else /* !__TBB_GCC_BUILTIN_ATOMICS_PRESENT */ | |||
//TODO: look like ICC 13.0 has some issues with this code, investigate it more deeply | ||||
int64_t result; | int64_t result; | |||
union { | union { | |||
int64_t i64; | int64_t i64; | |||
int32_t i32[2]; | int32_t i32[2]; | |||
}; | }; | |||
i64 = value; | i64 = value; | |||
#if __PIC__ | #if __PIC__ | |||
/* compiling position-independent code */ | /* compiling position-independent code */ | |||
// EBX register preserved for compliance with position-independent code rules on IA32 | // EBX register preserved for compliance with position-independent code rules on IA32 | |||
int32_t tmp; | int32_t tmp; | |||
skipping to change at line 151 | skipping to change at line 152 | |||
); | ); | |||
#endif /* __PIC__ */ | #endif /* __PIC__ */ | |||
return result; | return result; | |||
#endif /* !__TBB_GCC_BUILTIN_ATOMICS_PRESENT */ | #endif /* !__TBB_GCC_BUILTIN_ATOMICS_PRESENT */ | |||
} | } | |||
#if __INTEL_COMPILER | #if __INTEL_COMPILER | |||
#pragma warning( pop ) | #pragma warning( pop ) | |||
#endif // warning 998 is back | #endif // warning 998 is back | |||
static inline int32_t __TBB_machine_lg( uint32_t x ) { | ||||
int32_t j; | ||||
__asm__ ("bsr %1,%0" : "=r"(j) : "r"(x)); | ||||
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"(*(__TBB_VOLATILE uint32_t *)ptr) : "r"(addend), "m"(*(__TBB_VOLATILE 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"(*(__TBB_VOLATILE uint32_ t *)ptr) : "r"(addend), "m"(*(__TBB_VOLATILE 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 ) { | ||||
for (int32_t i = 0; i < delay; i++) { | ||||
__asm__ __volatile__("pause;"); | ||||
} | ||||
return; | ||||
} | ||||
//TODO: Check if it possible and profitable for IA-32 on (Linux and Windows ) | //TODO: Check if it possible and profitable for IA-32 on (Linux and Windows ) | |||
//to use of 64-bit load/store via floating point registers together with fu ll fence | //to use of 64-bit load/store via floating point registers together with fu ll fence | |||
//for sequentially consistent load/store, instead of CAS. | //for sequentially consistent load/store, instead of CAS. | |||
#if __clang__ | #if __clang__ | |||
#define __TBB_fildq "fildll" | #define __TBB_fildq "fildll" | |||
#define __TBB_fistpq "fistpll" | #define __TBB_fistpq "fistpll" | |||
#else | #else | |||
#define __TBB_fildq "fildq" | #define __TBB_fildq "fildq" | |||
#define __TBB_fistpq "fistpq" | #define __TBB_fistpq "fistpq" | |||
skipping to change at line 220 | skipping to change at line 208 | |||
__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); | |||
} | } | |||
} | } | |||
// Machine specific atomic operations | // Machine specific atomic operations | |||
#define __TBB_AtomicOR(P,V) __TBB_machine_or(P,V) | #define __TBB_AtomicOR(P,V) __TBB_machine_or(P,V) | |||
#define __TBB_AtomicAND(P,V) __TBB_machine_and(P,V) | #define __TBB_AtomicAND(P,V) __TBB_machine_and(P,V) | |||
// Definition of other functions | ||||
#define __TBB_Pause(V) __TBB_machine_pause(V) | ||||
#define __TBB_Log2(V) __TBB_machine_lg(V) | ||||
#define __TBB_USE_GENERIC_DWORD_FETCH_ADD 1 | #define __TBB_USE_GENERIC_DWORD_FETCH_ADD 1 | |||
#define __TBB_USE_GENERIC_DWORD_FETCH_STORE 1 | #define __TBB_USE_GENERIC_DWORD_FETCH_STORE 1 | |||
#define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | #define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | |||
#define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1 | #define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1 | |||
// API to retrieve/update FPU control setting | ||||
#define __TBB_CPU_CTL_ENV_PRESENT 1 | ||||
struct __TBB_cpu_ctl_env_t { | ||||
int mxcsr; | ||||
short x87cw; | ||||
}; | ||||
inline void __TBB_get_cpu_ctl_env ( __TBB_cpu_ctl_env_t* ctl ) { | ||||
__asm__ __volatile__ ( | ||||
"stmxcsr %0\n\t" | ||||
"fstcw %1" | ||||
: "=m"(ctl->mxcsr), "=m"(ctl->x87cw) | ||||
); | ||||
} | ||||
inline void __TBB_set_cpu_ctl_env ( const __TBB_cpu_ctl_env_t* ctl ) { | ||||
__asm__ __volatile__ ( | ||||
"ldmxcsr %0\n\t" | ||||
"fldcw %1" | ||||
: : "m"(ctl->mxcsr), "m"(ctl->x87cw) | ||||
); | ||||
} | ||||
End of changes. 6 change blocks. | ||||
18 lines changed or deleted | 2 lines changed or added | |||
linux_ia64.h | linux_ia64.h | |||
---|---|---|---|---|
skipping to change at line 36 | skipping to change at line 36 | |||
the GNU General Public License. | the GNU General Public License. | |||
*/ | */ | |||
#if !defined(__TBB_machine_H) || defined(__TBB_machine_linux_ia64_H) | #if !defined(__TBB_machine_H) || defined(__TBB_machine_linux_ia64_H) | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
#define __TBB_machine_linux_ia64_H | #define __TBB_machine_linux_ia64_H | |||
#include <stdint.h> | #include <stdint.h> | |||
#include <unistd.h> | ||||
#include <ia64intrin.h> | #include <ia64intrin.h> | |||
#define __TBB_WORDSIZE 8 | #define __TBB_WORDSIZE 8 | |||
#define __TBB_BIG_ENDIAN 0 | #define __TBB_BIG_ENDIAN 0 | |||
#if __INTEL_COMPILER | #if __INTEL_COMPILER | |||
#define __TBB_compiler_fence() | #define __TBB_compiler_fence() | |||
#define __TBB_control_consistency_helper() __TBB_compiler_fence() | #define __TBB_control_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_acquire_consistency_helper() | #define __TBB_acquire_consistency_helper() | |||
#define __TBB_release_consistency_helper() | #define __TBB_release_consistency_helper() | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 0 lines changed or added | |||
linux_intel64.h | linux_intel64.h | |||
---|---|---|---|---|
skipping to change at line 36 | skipping to change at line 36 | |||
the GNU General Public License. | the GNU General Public License. | |||
*/ | */ | |||
#if !defined(__TBB_machine_H) || defined(__TBB_machine_linux_intel64_H) | #if !defined(__TBB_machine_H) || defined(__TBB_machine_linux_intel64_H) | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
#define __TBB_machine_linux_intel64_H | #define __TBB_machine_linux_intel64_H | |||
#include <stdint.h> | #include <stdint.h> | |||
#include <unistd.h> | #include "gcc_ia32_common.h" | |||
#define __TBB_WORDSIZE 8 | #define __TBB_WORDSIZE 8 | |||
#define __TBB_BIG_ENDIAN 0 | #define __TBB_BIG_ENDIAN 0 | |||
#define __TBB_compiler_fence() __asm__ __volatile__("": : :"memory") | #define __TBB_compiler_fence() __asm__ __volatile__("": : :"memory") | |||
#define __TBB_control_consistency_helper() __TBB_compiler_fence() | #define __TBB_control_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_acquire_consistency_helper() __TBB_compiler_fence() | #define __TBB_acquire_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_release_consistency_helper() __TBB_compiler_fence() | #define __TBB_release_consistency_helper() __TBB_compiler_fence() | |||
#ifndef __TBB_full_memory_fence | #ifndef __TBB_full_memory_fence | |||
skipping to change at line 89 | skipping to change at line 89 | |||
return result; \ | return result; \ | |||
} \ | } \ | |||
__TBB_MACHINE_DEFINE_ATOMICS(1,int8_t,"") | __TBB_MACHINE_DEFINE_ATOMICS(1,int8_t,"") | |||
__TBB_MACHINE_DEFINE_ATOMICS(2,int16_t,"") | __TBB_MACHINE_DEFINE_ATOMICS(2,int16_t,"") | |||
__TBB_MACHINE_DEFINE_ATOMICS(4,int32_t,"") | __TBB_MACHINE_DEFINE_ATOMICS(4,int32_t,"") | |||
__TBB_MACHINE_DEFINE_ATOMICS(8,int64_t,"q") | __TBB_MACHINE_DEFINE_ATOMICS(8,int64_t,"q") | |||
#undef __TBB_MACHINE_DEFINE_ATOMICS | #undef __TBB_MACHINE_DEFINE_ATOMICS | |||
static inline int64_t __TBB_machine_lg( uint64_t x ) { | ||||
__TBB_ASSERT(x, "__TBB_Log2(0) undefined"); | ||||
int64_t j; | ||||
__asm__ ("bsr %1,%0" : "=r"(j) : "r"(x)); | ||||
return j; | ||||
} | ||||
static inline void __TBB_machine_or( volatile void *ptr, uint64_t value ) { | static inline void __TBB_machine_or( volatile void *ptr, uint64_t value ) { | |||
__asm__ __volatile__("lock\norq %1,%0" : "=m"(*(volatile uint64_t*)ptr) : "r"(value), "m"(*(volatile uint64_t*)ptr) : "memory"); | __asm__ __volatile__("lock\norq %1,%0" : "=m"(*(volatile uint64_t*)ptr) : "r"(value), "m"(*(volatile uint64_t*)ptr) : "memory"); | |||
} | } | |||
static inline void __TBB_machine_and( volatile void *ptr, uint64_t value ) { | static inline void __TBB_machine_and( volatile void *ptr, uint64_t value ) { | |||
__asm__ __volatile__("lock\nandq %1,%0" : "=m"(*(volatile uint64_t*)ptr ) : "r"(value), "m"(*(volatile uint64_t*)ptr) : "memory"); | __asm__ __volatile__("lock\nandq %1,%0" : "=m"(*(volatile uint64_t*)ptr ) : "r"(value), "m"(*(volatile uint64_t*)ptr) : "memory"); | |||
} | } | |||
#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 | ||||
#ifndef __TBB_Pause | ||||
static inline void __TBB_machine_pause( int32_t delay ) { | ||||
for (int32_t i = 0; i < delay; i++) { | ||||
__asm__ __volatile__("pause;"); | ||||
} | ||||
return; | ||||
} | ||||
#define __TBB_Pause(V) __TBB_machine_pause(V) | ||||
#endif /* !__TBB_Pause */ | ||||
#define __TBB_Log2(V) __TBB_machine_lg(V) | ||||
#define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | #define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | |||
#define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1 | #define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1 | |||
// API to retrieve/update FPU control setting | ||||
#ifndef __TBB_CPU_CTL_ENV_PRESENT | ||||
#define __TBB_CPU_CTL_ENV_PRESENT 1 | ||||
struct __TBB_cpu_ctl_env_t { | ||||
int mxcsr; | ||||
short x87cw; | ||||
}; | ||||
inline void __TBB_get_cpu_ctl_env ( __TBB_cpu_ctl_env_t* ctl ) { | ||||
#if __TBB_ICC_12_0_INL_ASM_FSTCW_BROKEN | ||||
__TBB_cpu_ctl_env_t loc_ctl; | ||||
__asm__ __volatile__ ( | ||||
"stmxcsr %0\n\t" | ||||
"fstcw %1" | ||||
: "=m"(loc_ctl.mxcsr), "=m"(loc_ctl.x87cw) | ||||
); | ||||
*ctl = loc_ctl; | ||||
#else | ||||
__asm__ __volatile__ ( | ||||
"stmxcsr %0\n\t" | ||||
"fstcw %1" | ||||
: "=m"(ctl->mxcsr), "=m"(ctl->x87cw) | ||||
); | ||||
#endif | ||||
} | ||||
inline void __TBB_set_cpu_ctl_env ( const __TBB_cpu_ctl_env_t* ctl ) { | ||||
__asm__ __volatile__ ( | ||||
"ldmxcsr %0\n\t" | ||||
"fldcw %1" | ||||
: : "m"(ctl->mxcsr), "m"(ctl->x87cw) | ||||
); | ||||
} | ||||
#endif /* !__TBB_CPU_CTL_ENV_PRESENT */ | ||||
End of changes. 4 change blocks. | ||||
21 lines changed or deleted | 1 lines changed or added | |||
macos_common.h | macos_common.h | |||
---|---|---|---|---|
skipping to change at line 59 | skipping to change at line 59 | |||
} | } | |||
#define __TBB_HardwareConcurrency() __TBB_macos_available_cpu() | #define __TBB_HardwareConcurrency() __TBB_macos_available_cpu() | |||
#ifndef __TBB_full_memory_fence | #ifndef __TBB_full_memory_fence | |||
// TBB has not recognized the architecture (none of the architecture ab straction | // TBB has not recognized the architecture (none of the architecture ab straction | |||
// headers was included). | // headers was included). | |||
#define __TBB_UnknownArchitecture 1 | #define __TBB_UnknownArchitecture 1 | |||
#endif | #endif | |||
#if __TBB_UnknownArchitecture || __TBB_WORDSIZE==4 | #if __TBB_UnknownArchitecture || (__TBB_WORDSIZE==4 && !TBB_USE_ICC_BUILTIN S) | |||
// In case of IA32 this is a workaround for compiler bugs triggered by inli ne | // In case of IA32 this is a workaround for compiler bugs triggered by inli ne | |||
// assembly implementation of __TBB_machine_cmpswp8 in linux_ia32.h, which may | // assembly implementation of __TBB_machine_cmpswp8 in linux_ia32.h, which may | |||
// lead to incorrect codegen (gcc) or compilation failures (any icc includi ng 12.0.4). | // lead to incorrect codegen (gcc) or compilation failures (any icc includi ng 12.0.4). | |||
// Implementation of atomic operations based on OS provided primitives | // Implementation of atomic operations based on OS provided primitives | |||
#include <libkern/OSAtomic.h> | #include <libkern/OSAtomic.h> | |||
static inline int64_t __TBB_machine_cmpswp8_OsX(volatile void *ptr, int64_t value, int64_t comparand) | static inline int64_t __TBB_machine_cmpswp8_OsX(volatile void *ptr, int64_t value, int64_t comparand) | |||
{ | { | |||
__TBB_ASSERT( !((uintptr_t)ptr&0x7), "address not properly aligned for Mac OS atomics"); | __TBB_ASSERT( !((uintptr_t)ptr&0x7), "address not properly aligned for Mac OS atomics"); | |||
skipping to change at line 84 | skipping to change at line 84 | |||
#else | #else | |||
int64_t snapshot = OSAtomicAdd64( 0, address ); | int64_t snapshot = OSAtomicAdd64( 0, address ); | |||
#endif | #endif | |||
if( snapshot!=comparand ) return snapshot; | if( snapshot!=comparand ) return snapshot; | |||
} | } | |||
return comparand; | return comparand; | |||
} | } | |||
#define __TBB_machine_cmpswp8 __TBB_machine_cmpswp8_OsX | #define __TBB_machine_cmpswp8 __TBB_machine_cmpswp8_OsX | |||
#endif /* __TBB_UnknownArchitecture || __TBB_WORDSIZE==4 */ | #endif /* __TBB_UnknownArchitecture || (__TBB_WORDSIZE==4 && !TBB_USE_ICC_B UILTINS) */ | |||
#if __TBB_UnknownArchitecture | #if __TBB_UnknownArchitecture | |||
#ifndef __TBB_WORDSIZE | #ifndef __TBB_WORDSIZE | |||
#define __TBB_WORDSIZE 4 | #define __TBB_WORDSIZE 4 | |||
#endif | #endif | |||
#ifdef __TBB_BIG_ENDIAN | #ifdef __TBB_BIG_ENDIAN | |||
// Already determined based on hardware architecture. | // Already determined based on hardware architecture. | |||
#elif __BIG_ENDIAN__ | #elif __BIG_ENDIAN__ | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 2 lines changed or added | |||
mutex.h | mutex.h | |||
---|---|---|---|---|
skipping to change at line 56 | skipping to change at line 56 | |||
/** For testing purposes only. | /** For testing purposes only. | |||
@ingroup synchronization */ | @ingroup synchronization */ | |||
class mutex { | class mutex { | |||
public: | public: | |||
//! Construct unacquired mutex. | //! Construct unacquired mutex. | |||
mutex() { | mutex() { | |||
#if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS | #if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS | |||
internal_construct(); | internal_construct(); | |||
#else | #else | |||
#if _WIN32||_WIN64 | #if _WIN32||_WIN64 | |||
InitializeCriticalSection(&impl); | InitializeCriticalSectionEx(&impl, 4000, 0); | |||
#else | #else | |||
int error_code = pthread_mutex_init(&impl,NULL); | int error_code = pthread_mutex_init(&impl,NULL); | |||
if( error_code ) | if( error_code ) | |||
tbb::internal::handle_perror(error_code,"mutex: pthread_mutex_i nit failed"); | tbb::internal::handle_perror(error_code,"mutex: pthread_mutex_i nit failed"); | |||
#endif /* _WIN32||_WIN64*/ | #endif /* _WIN32||_WIN64*/ | |||
#endif /* TBB_USE_ASSERT */ | #endif /* TBB_USE_ASSERT */ | |||
}; | }; | |||
~mutex() { | ~mutex() { | |||
#if TBB_USE_ASSERT | #if TBB_USE_ASSERT | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
parallel_for.h | parallel_for.h | |||
---|---|---|---|---|
skipping to change at line 84 | skipping to change at line 84 | |||
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); | |||
my_partition.align_depth( d ); | my_partition.align_depth( d ); | |||
} | } | |||
//! 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 ); | |||
} | } | |||
static void run( const Range& range, const Body& body, const Parti tioner& partitioner ) { | static void run( const Range& range, const Body& body, Partitioner & partitioner ) { | |||
if( !range.empty() ) { | if( !range.empty() ) { | |||
#if !__TBB_TASK_GROUP_CONTEXT || 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,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,partitioner); | |||
#endif /* __TBB_TASK_GROUP_CONTEXT && !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_TASK_GROUP_CONTEXT | #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, Partitioner & 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,partitioner); | |||
task::spawn_root_and_wait(a); | task::spawn_root_and_wait(a); | |||
} | } | |||
} | } | |||
#endif /* __TBB_TASK_GROUP_CONTEXT */ | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |||
//! create a continuation task, serve as callback for partitioner | //! create a continuation task, serve as callback for partitioner | |||
flag_task *create_continuation() { | flag_task *create_continuation() { | |||
return new( allocate_continuation() ) flag_task(); | return new( allocate_continuation() ) flag_task(); | |||
} | } | |||
//! Run body for range | //! Run body for range | |||
void run_body( Range &r ) { my_body( r ); } | void run_body( Range &r ) { my_body( r ); } | |||
skipping to change at line 138 | skipping to change at line 138 | |||
template<typename Function, typename Index> | template<typename Function, typename Index> | |||
class parallel_for_body : internal::no_assign { | class parallel_for_body : internal::no_assign { | |||
const 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( const Function& _func, Index& _begin, Index& _st ep) | parallel_for_body( const Function& _func, Index& _begin, Index& _st ep) | |||
: 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 { | |||
#if __INTEL_COMPILER | ||||
#pragma ivdep | ||||
#endif | ||||
for( Index i = r.begin(), k = my_begin + i * my_step; i < r.en d(); i++, k = k + my_step) | for( Index i = r.begin(), k = my_begin + i * my_step; i < r.en d(); i++, k = k + my_step) | |||
my_func( k ); | my_func( k ); | |||
} | } | |||
}; | }; | |||
} // 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 | |||
skipping to change at line 162 | skipping to change at line 165 | |||
**/ | **/ | |||
/** \name parallel_for | /** \name parallel_for | |||
See also requirements on \ref range_req "Range" and \ref parallel_for_b ody_req "parallel_for Body". **/ | See also requirements on \ref range_req "Range" and \ref parallel_for_b ody_req "parallel_for Body". **/ | |||
//@{ | //@{ | |||
//! Parallel iteration over range with default partitioner. | //! Parallel iteration over range with default partitioner. | |||
/** @ingroup algorithms **/ | /** @ingroup algorithms **/ | |||
template<typename Range, typename Body> | template<typename Range, typename Body> | |||
void parallel_for( const Range& range, const Body& body ) { | void parallel_for( const Range& range, const Body& body ) { | |||
internal::start_for<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,bo dy,__TBB_DEFAULT_PARTITIONER()); | internal::start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(ra nge,body,__TBB_DEFAULT_PARTITIONER()); | |||
} | } | |||
//! Parallel iteration over range with simple partitioner. | //! Parallel iteration over range with simple partitioner. | |||
/** @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 ) { | void parallel_for( const Range& range, const Body& body, const simple_parti tioner& partitioner ) { | |||
internal::start_for<Range,Body,simple_partitioner>::run(range,body,part itioner); | internal::start_for<Range,Body,const simple_partitioner>::run(range,bod y,partitioner); | |||
} | } | |||
//! Parallel iteration over range with auto_partitioner. | //! Parallel iteration over range with auto_partitioner. | |||
/** @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 ) { | void parallel_for( const Range& range, const Body& body, const auto_partiti oner& partitioner ) { | |||
internal::start_for<Range,Body,auto_partitioner>::run(range,body,partit ioner); | internal::start_for<Range,Body,const auto_partitioner>::run(range,body, partitioner); | |||
} | } | |||
//! 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_TASK_GROUP_CONTEXT | #if __TBB_TASK_GROUP_CONTEXT | |||
//! Parallel iteration over range with default partitioner and user-supplie | ||||
d context. | ||||
/** @ingroup algorithms **/ | ||||
template<typename Range, typename Body> | ||||
void parallel_for( const Range& range, const Body& body, task_group_context | ||||
& context ) { | ||||
internal::start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(ra | ||||
nge, body, __TBB_DEFAULT_PARTITIONER(), 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,const simple_partitioner>::run(range, bo dy, partitioner, 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,const auto_partitioner>::run(range, body , partitioner, 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_TASK_GROUP_CONTEXT */ | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |||
//@} | //@} | |||
namespace strict_ppl { | namespace strict_ppl { | |||
//@{ | //@{ | |||
//! Parallel iteration over a range of integers with a step provided | //! Implementation of parallel iteration over stepped range of integers wit | |||
template <typename Index, typename Function> | h explicit step and partitioner | |||
void parallel_for(Index first, Index last, Index step, const Function& f) { | template <typename Index, typename Function, typename Partitioner> | |||
void parallel_for_impl(Index first, Index last, Index step, const Function& | ||||
f, Partitioner& partitioner) { | ||||
if (step <= 0 ) | if (step <= 0 ) | |||
internal::throw_exception(internal::eid_nonpositive_step); // throw s std::invalid_argument | internal::throw_exception(internal::eid_nonpositive_step); // throw s std::invalid_argument | |||
else if (last > first) { | else if (last > first) { | |||
// Above "else" avoids "potential divide by zero" warning on some p latforms | // Above "else" avoids "potential divide by zero" warning on some p latforms | |||
Index end = (last - first - Index(1)) / step + Index(1); | Index end = (last - first - Index(1)) / step + Index(1); | |||
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()); | tbb::parallel_for(range, body, partitioner); | |||
} | } | |||
} | } | |||
//! Parallel iteration over a range of integers with a default step value | ||||
//! Parallel iteration over a range of integers with a step provided and de | ||||
fault partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, Index step, const Function& f) { | ||||
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | ||||
tep, f, auto_partitioner()); | ||||
} | ||||
//! Parallel iteration over a range of integers with a step provided and si | ||||
mple partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, Index step, const Function& f, c | ||||
onst simple_partitioner& partitioner) { | ||||
parallel_for_impl<Index,Function,const simple_partitioner>(first, last, | ||||
step, f, partitioner); | ||||
} | ||||
//! Parallel iteration over a range of integers with a step provided and au | ||||
to partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, Index step, const Function& f, c | ||||
onst auto_partitioner& partitioner) { | ||||
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | ||||
tep, f, partitioner); | ||||
} | ||||
//! Parallel iteration over a range of integers with a step provided and af | ||||
finity partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, Index step, const Function& f, a | ||||
ffinity_partitioner& partitioner) { | ||||
parallel_for_impl(first, last, step, f, partitioner); | ||||
} | ||||
//! Parallel iteration over a range of integers with a default step value a | ||||
nd default partitioner | ||||
template <typename Index, typename Function> | template <typename Index, typename Function> | |||
void parallel_for(Index first, Index last, const Function& f) { | void parallel_for(Index first, Index last, const Function& f) { | |||
parallel_for(first, last, static_cast<Index>(1), f); | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | |||
tatic_cast<Index>(1), f, auto_partitioner()); | ||||
} | ||||
//! Parallel iteration over a range of integers with a default step value a | ||||
nd simple partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, const Function& f, const simple_ | ||||
partitioner& partitioner) { | ||||
parallel_for_impl<Index,Function,const simple_partitioner>(first, last, | ||||
static_cast<Index>(1), f, partitioner); | ||||
} | ||||
//! Parallel iteration over a range of integers with a default step value a | ||||
nd auto partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, const Function& f, const auto_pa | ||||
rtitioner& partitioner) { | ||||
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | ||||
tatic_cast<Index>(1), f, partitioner); | ||||
} | ||||
//! Parallel iteration over a range of integers with a default step value a | ||||
nd affinity partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, const Function& f, affinity_part | ||||
itioner& partitioner) { | ||||
parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner); | ||||
} | } | |||
#if __TBB_TASK_GROUP_CONTEXT | #if __TBB_TASK_GROUP_CONTEXT | |||
//! Parallel iteration over a range of integers with explicit step and task | //! Implementation of parallel iteration over stepped range of integers wit | |||
group context | h explicit step, task group context, and partitioner | |||
template <typename Index, typename Function> | template <typename Index, typename Function, typename Partitioner> | |||
void parallel_for(Index first, Index last, Index step, const Function& f, t | void parallel_for_impl(Index first, Index last, Index step, const Function& | |||
bb::task_group_context &context) { | f, Partitioner& partitioner, tbb::task_group_context &context) { | |||
if (step <= 0 ) | if (step <= 0 ) | |||
internal::throw_exception(internal::eid_nonpositive_step); // throw s std::invalid_argument | internal::throw_exception(internal::eid_nonpositive_step); // throw s std::invalid_argument | |||
else if (last > first) { | else if (last > first) { | |||
// Above "else" avoids "potential divide by zero" warning on some p latforms | // Above "else" avoids "potential divide by zero" warning on some p latforms | |||
Index end = (last - first - Index(1)) / step + Index(1); | Index end = (last - first - Index(1)) / step + Index(1); | |||
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, partitioner, context); | |||
} | } | |||
} | } | |||
//! Parallel iteration over a range of integers with a default step value a | ||||
nd explicit task group context | //! Parallel iteration over a range of integers with explicit step, task gr | |||
oup context, and default partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, Index step, const Function& f, t | ||||
bb::task_group_context &context) { | ||||
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | ||||
tep, f, auto_partitioner(), context); | ||||
} | ||||
//! Parallel iteration over a range of integers with explicit step, task gr | ||||
oup context, and simple partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, Index step, const Function& f, c | ||||
onst simple_partitioner& partitioner, tbb::task_group_context &context) { | ||||
parallel_for_impl<Index,Function,const simple_partitioner>(first, last, | ||||
step, f, partitioner, context); | ||||
} | ||||
//! Parallel iteration over a range of integers with explicit step, task gr | ||||
oup context, and auto partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, Index step, const Function& f, c | ||||
onst auto_partitioner& partitioner, tbb::task_group_context &context) { | ||||
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | ||||
tep, f, partitioner, context); | ||||
} | ||||
//! Parallel iteration over a range of integers with explicit step, task gr | ||||
oup context, and affinity partitioner | ||||
template <typename Index, typename Function> | ||||
void parallel_for(Index first, Index last, Index step, const Function& f, a | ||||
ffinity_partitioner& partitioner, tbb::task_group_context &context) { | ||||
parallel_for_impl(first, last, step, f, partitioner, context); | ||||
} | ||||
//! Parallel iteration over a range of integers with a default step value, | ||||
explicit task group context, and default partitioner | ||||
template <typename Index, typename Function> | template <typename Index, typename Function> | |||
void parallel_for(Index first, Index last, const Function& f, tbb::task_gro up_context &context) { | 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); | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s tatic_cast<Index>(1), f, auto_partitioner(), context); | |||
} | } | |||
//! Parallel iteration over a range of integers with a default step value, | ||||
explicit task group context, and simple partitioner | ||||
template <typename Index, typename Function, typename Partitioner> | ||||
void parallel_for(Index first, Index last, const Function& f, const simple_ | ||||
partitioner& partitioner, tbb::task_group_context &context) { | ||||
parallel_for_impl<Index,Function,const simple_partitioner>(first, last, | ||||
static_cast<Index>(1), f, partitioner, context); | ||||
} | ||||
//! Parallel iteration over a range of integers with a default step value, | ||||
explicit task group context, and auto partitioner | ||||
template <typename Index, typename Function, typename Partitioner> | ||||
void parallel_for(Index first, Index last, const Function& f, const auto_pa | ||||
rtitioner& partitioner, tbb::task_group_context &context) { | ||||
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | ||||
tatic_cast<Index>(1), f, partitioner, context); | ||||
} | ||||
//! Parallel iteration over a range of integers with a default step value, | ||||
explicit task group context, and affinity_partitioner | ||||
template <typename Index, typename Function, typename Partitioner> | ||||
void parallel_for(Index first, Index last, const Function& f, affinity_part | ||||
itioner& partitioner, tbb::task_group_context &context) { | ||||
parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner, c | ||||
ontext); | ||||
} | ||||
#endif /* __TBB_TASK_GROUP_CONTEXT */ | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |||
//@} | //@} | |||
} // namespace strict_ppl | } // namespace strict_ppl | |||
using strict_ppl::parallel_for; | using strict_ppl::parallel_for; | |||
} // namespace tbb | } // namespace tbb | |||
#if TBB_PREVIEW_SERIAL_SUBSET | #if TBB_PREVIEW_SERIAL_SUBSET | |||
End of changes. 21 change blocks. | ||||
25 lines changed or deleted | 155 lines changed or added | |||
partitioner.h | partitioner.h | |||
---|---|---|---|---|
skipping to change at line 117 | skipping to change at line 117 | |||
namespace interface6 { | namespace interface6 { | |||
//! @cond INTERNAL | //! @cond INTERNAL | |||
namespace internal { | namespace internal { | |||
using namespace tbb::internal; | using namespace tbb::internal; | |||
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; | |||
//! Join task node that contains shared flag for stealing feedback | //! Join task node that contains shared flag for stealing feedback | |||
class flag_task: public task { | class flag_task: public task { | |||
public: | public: | |||
tbb::atomic<bool> child_stolen; | tbb::atomic<bool> my_child_stolen; | |||
flag_task() { child_stolen = false; } | flag_task() { my_child_stolen = false; } | |||
task* execute() { return NULL; } | task* execute() { return NULL; } | |||
static void mark_task_stolen(task &t) { | ||||
tbb::atomic<bool> &flag = static_cast<flag_task*>(t.parent())->my_c | ||||
hild_stolen; | ||||
#if TBB_USE_THREADING_TOOLS | ||||
// Threading tools respect lock prefix but report false-positive da | ||||
ta-race via plain store | ||||
flag.fetch_and_store<release>(true); | ||||
#else | ||||
flag = true; | ||||
#endif //TBB_USE_THREADING_TOOLS | ||||
} | ||||
static bool is_peer_stolen(task &t) { | ||||
return static_cast<flag_task*>(t.parent())->my_child_stolen; | ||||
} | ||||
}; | }; | |||
//! Task to signal the demand without carrying the work | //! Task to signal the demand without carrying the work | |||
class signal_task: public task { | class signal_task: public task { | |||
public: | public: | |||
task* execute() { | task* execute() { | |||
if( is_stolen_task() ) { | if( is_stolen_task() ) { | |||
static_cast<flag_task*>(parent())->child_stolen = true; | flag_task::mark_task_stolen(*this); | |||
} | } | |||
return NULL; | return NULL; | |||
} | } | |||
}; | }; | |||
//! Depth is a relative depth of recursive division inside a range pool. Re lative depth allows | //! Depth is a relative depth of recursive division inside a range pool. Re lative depth allows | |||
//! infinite absolute depth of the recursion for heavily imbalanced workloa ds with range represented | //! infinite absolute depth of the recursion for heavily imbalanced workloa ds with range represented | |||
//! by a number that cannot fit into machine word. | //! by a number that cannot fit into machine word. | |||
typedef unsigned char depth_t; | typedef unsigned char depth_t; | |||
skipping to change at line 293 | skipping to change at line 305 | |||
#if __TBB_INITIAL_TASK_IMBALANCE | #if __TBB_INITIAL_TASK_IMBALANCE | |||
if( src.my_divisor <= 1 ) my_divisor = 0; | if( src.my_divisor <= 1 ) my_divisor = 0; | |||
else my_divisor = src.my_divisor = (src.my_divisor+1u) / 2u; | else my_divisor = src.my_divisor = (src.my_divisor+1u) / 2u; | |||
#else | #else | |||
my_divisor = src.my_divisor / 2u; | my_divisor = src.my_divisor / 2u; | |||
src.my_divisor = src.my_divisor - my_divisor; // TODO: check the ef fect separately | src.my_divisor = src.my_divisor - my_divisor; // TODO: check the ef fect separately | |||
if(my_divisor) src.my_max_depth += static_cast<depth_t>(__TBB_Log2( src.my_divisor/my_divisor)); | if(my_divisor) src.my_max_depth += static_cast<depth_t>(__TBB_Log2( src.my_divisor/my_divisor)); | |||
#endif | #endif | |||
} | } | |||
bool check_being_stolen( task &t) { // part of old should_execute_range () | bool check_being_stolen( task &t) { // part of old should_execute_range () | |||
if( !my_divisor ) { | if( !my_divisor ) { // if not from the top P tasks of binary tree | |||
my_divisor = 1; // todo: replace by on-stack flag (partition_st | my_divisor = 1; // TODO: replace by on-stack flag (partition_st | |||
ate's member)? | ate's member)? | |||
if( t.is_stolen_task() ) { | if( t.is_stolen_task() ) { | |||
#if TBB_USE_EXCEPTIONS | #if TBB_USE_EXCEPTIONS | |||
// RTTI is available, check whether the cast is valid | // RTTI is available, check whether the cast is valid | |||
__TBB_ASSERT(dynamic_cast<flag_task*>(t.parent()), 0); | __TBB_ASSERT(dynamic_cast<flag_task*>(t.parent()), 0); | |||
// correctness of the cast relies on avoiding the root task for which: | // correctness of the cast relies on avoiding the root task for which: | |||
// - initial value of my_divisor != 0 (protected by separat e assertion) | // - initial value of my_divisor != 0 (protected by separat e assertion) | |||
// - is_stolen_task() always return false for the root task . | // - is_stolen_task() always returns false for the root tas k. | |||
#endif | #endif | |||
static_cast<flag_task*>(t.parent())->child_stolen = true; | flag_task::mark_task_stolen(t); | |||
my_max_depth++; | my_max_depth++; | |||
return true; | return true; | |||
} | } | |||
} | } | |||
return false; | return false; | |||
} | } | |||
bool divisions_left() { // part of old should_execute_range() | bool divisions_left() { // part of old should_execute_range() | |||
if( my_divisor > 1 ) return true; | if( my_divisor > 1 ) return true; | |||
if( my_divisor && my_max_depth > 1 ) { // can split the task and on ce more internally. TODO: on-stack flag instead | if( my_divisor && my_max_depth > 1 ) { // can split the task and on ce more internally. TODO: on-stack flag instead | |||
// keep same fragmentation while splitting for the local task p ool | // keep same fragmentation while splitting for the local task p ool | |||
my_max_depth--; | my_max_depth--; | |||
my_divisor = 0; | my_divisor = 0; // decrease max_depth once per task | |||
return true; | return true; | |||
} else return false; | } else return false; | |||
} | } | |||
bool should_create_trap() { | bool should_create_trap() { | |||
return my_divisor > 0; | return my_divisor > 0; | |||
} | } | |||
bool check_for_demand(task &t) { | bool check_for_demand(task &t) { | |||
if( static_cast<flag_task*>(t.parent())->child_stolen ) { | if( flag_task::is_peer_stolen(t) ) { | |||
my_max_depth++; | my_max_depth++; | |||
return true; | return true; | |||
} else return false; | } else return false; | |||
} | } | |||
void align_depth(depth_t base) { | void align_depth(depth_t base) { | |||
__TBB_ASSERT(base <= my_max_depth, 0); | __TBB_ASSERT(base <= my_max_depth, 0); | |||
my_max_depth -= base; | my_max_depth -= base; | |||
} | } | |||
depth_t max_depth() { return my_max_depth; } | depth_t max_depth() { return my_max_depth; } | |||
}; | }; | |||
skipping to change at line 383 | skipping to change at line 395 | |||
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; | |||
} | } | |||
bool check_for_demand( task &t ) { | bool check_for_demand( task &t ) { | |||
if( !my_delay ) { | if( !my_delay ) { | |||
if( map_mid<map_end ) { | if( map_mid<map_end ) { | |||
__TBB_ASSERT(my_max_depth>__TBB_Log2(map_end-map_mid), 0); | __TBB_ASSERT(my_max_depth>__TBB_Log2(map_end-map_mid), 0); | |||
return true;// do not do my_max_depth++ here, but be sure m y_max_depth is big enough | return true;// do not do my_max_depth++ here, but be sure m y_max_depth is big enough | |||
} | } | |||
if( static_cast<flag_task*>(t.parent())->child_stolen ) { | if( flag_task::is_peer_stolen(t) ) { | |||
my_max_depth++; | my_max_depth++; | |||
return true; | return true; | |||
} | } | |||
} else my_delay = false; | } else my_delay = false; | |||
return false; | return false; | |||
} | } | |||
bool divisions_left() { // part of old should_execute_range() | bool divisions_left() { // part of old should_execute_range() | |||
return my_divisor > 1; | return my_divisor > 1; | |||
} | } | |||
bool should_create_trap() { | bool should_create_trap() { | |||
End of changes. 9 change blocks. | ||||
11 lines changed or deleted | 25 lines changed or added | |||
recursive_mutex.h | recursive_mutex.h | |||
---|---|---|---|---|
skipping to change at line 55 | skipping to change at line 55 | |||
/** Mutex that allows recursive mutex acquisition. | /** Mutex that allows recursive mutex acquisition. | |||
@ingroup synchronization */ | @ingroup synchronization */ | |||
class recursive_mutex { | class recursive_mutex { | |||
public: | public: | |||
//! Construct unacquired recursive_mutex. | //! Construct unacquired recursive_mutex. | |||
recursive_mutex() { | recursive_mutex() { | |||
#if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS | #if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS | |||
internal_construct(); | internal_construct(); | |||
#else | #else | |||
#if _WIN32||_WIN64 | #if _WIN32||_WIN64 | |||
InitializeCriticalSection(&impl); | InitializeCriticalSectionEx(&impl, 4000, 0); | |||
#else | #else | |||
pthread_mutexattr_t mtx_attr; | pthread_mutexattr_t mtx_attr; | |||
int error_code = pthread_mutexattr_init( &mtx_attr ); | int error_code = pthread_mutexattr_init( &mtx_attr ); | |||
if( error_code ) | if( error_code ) | |||
tbb::internal::handle_perror(error_code,"recursive_mutex: pthre ad_mutexattr_init failed"); | tbb::internal::handle_perror(error_code,"recursive_mutex: pthre ad_mutexattr_init failed"); | |||
pthread_mutexattr_settype( &mtx_attr, PTHREAD_MUTEX_RECURSIVE ); | pthread_mutexattr_settype( &mtx_attr, PTHREAD_MUTEX_RECURSIVE ); | |||
error_code = pthread_mutex_init( &impl, &mtx_attr ); | error_code = pthread_mutex_init( &impl, &mtx_attr ); | |||
if( error_code ) | if( error_code ) | |||
tbb::internal::handle_perror(error_code,"recursive_mutex: pthre ad_mutex_init failed"); | tbb::internal::handle_perror(error_code,"recursive_mutex: pthre ad_mutex_init failed"); | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
tbb_config.h | tbb_config.h | |||
---|---|---|---|---|
skipping to change at line 41 | skipping to change at line 41 | |||
/** This header is supposed to contain macro definitions and C style commen ts only. | /** This header is supposed to contain macro definitions and C style commen ts only. | |||
The macros defined here are intended to control such aspects of TBB bui ld as | The macros defined here are intended to control such aspects of TBB bui ld as | |||
- presence of compiler features | - presence of compiler features | |||
- compilation modes | - compilation modes | |||
- feature sets | - feature sets | |||
- known compiler/platform issues | - known compiler/platform issues | |||
**/ | **/ | |||
#define __TBB_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC _PATCHLEVEL__) | #define __TBB_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC _PATCHLEVEL__) | |||
#if __clang__ | #if __clang__ | |||
#define __TBB_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) | #define __TBB_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) | |||
#endif | #endif | |||
/** Presence of compiler features **/ | /** Presence of compiler features **/ | |||
#if __INTEL_COMPILER == 9999 && __INTEL_COMPILER_BUILD_DATE == 20110811 | #if __INTEL_COMPILER == 9999 && __INTEL_COMPILER_BUILD_DATE == 20110811 | |||
/* Intel Composer XE 2011 Update 6 incorrectly sets __INTEL_COMPILER. Fix i t. */ | /* Intel Composer XE 2011 Update 6 incorrectly sets __INTEL_COMPILER. Fix i t. */ | |||
#undef __INTEL_COMPILER | #undef __INTEL_COMPILER | |||
#define __INTEL_COMPILER 1210 | #define __INTEL_COMPILER 1210 | |||
skipping to change at line 87 | skipping to change at line 88 | |||
/*ICC 12.1 Upd 10 and 13 beta Upd 2 fixed exception_ptr linking issue*/ \ | /*ICC 12.1 Upd 10 and 13 beta Upd 2 fixed exception_ptr linking issue*/ \ | |||
|| (__INTEL_COMPILER == 1300 && __INTEL_COMPILER_BUILD_DATE >= 20120530) \ | || (__INTEL_COMPILER == 1300 && __INTEL_COMPILER_BUILD_DATE >= 20120530) \ | |||
|| (__INTEL_COMPILER == 1210 && __INTEL_COMPILER_BUILD_DATE >= 20120410) | || (__INTEL_COMPILER == 1210 && __INTEL_COMPILER_BUILD_DATE >= 20120410) | |||
/** libstc++ that comes with GCC 4.6 use C++ features not yet supported by current ICC (12.1)**/ | /** libstc++ that comes with GCC 4.6 use C++ features not yet supported by current ICC (12.1)**/ | |||
#elif (__TBB_GCC_VERSION >= 40404) && (__TBB_GCC_VERSION < 40600) | #elif (__TBB_GCC_VERSION >= 40404) && (__TBB_GCC_VERSION < 40600) | |||
#define __TBB_EXCEPTION_PTR_PRESENT __GXX_EXPERIMENTAL_CXX0X __ && __INTEL_COMPILER >= 1200 | #define __TBB_EXCEPTION_PTR_PRESENT __GXX_EXPERIMENTAL_CXX0X __ && __INTEL_COMPILER >= 1200 | |||
#else | #else | |||
#define __TBB_EXCEPTION_PTR_PRESENT 0 | #define __TBB_EXCEPTION_PTR_PRESENT 0 | |||
#endif | #endif | |||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700 || (__ GXX_EXPERIMENTAL_CXX0X__ && __TBB_GCC_VERSION >= 40600)) | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700 || (__ GXX_EXPERIMENTAL_CXX0X__ && __TBB_GCC_VERSION >= 40600)) | |||
#define __TBB_STATIC_ASSERT_PRESENT __GXX_EXPERIMENTAL_CXX0X __ || (_MSC_VER >= 1600) | ||||
#define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) || (( __GXX_EXPERIMENTAL_CXX0X__) && (__TBB_GCC_VERSION >= 40300)) | #define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) || (( __GXX_EXPERIMENTAL_CXX0X__) && (__TBB_GCC_VERSION >= 40300)) | |||
/** TODO: re-check for compiler version greater than 12.1 if it support | ||||
s initializer lists**/ | ||||
#define __TBB_INITIALIZER_LISTS_PRESENT 0 | ||||
#elif __clang__ | #elif __clang__ | |||
//TODO: these options need to be rechecked | //TODO: these options need to be rechecked | |||
#define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_CLANG_VERSION >= 20900) | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_CLANG_VERSION >= 20900) | |||
#define __TBB_CPP11_RVALUE_REF_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_CLANG_VERSION >= 20900) | #define __TBB_CPP11_RVALUE_REF_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_CLANG_VERSION >= 20900) | |||
#define __TBB_EXCEPTION_PTR_PRESENT __GXX_EXPERIMENTAL_CXX0X __ | #define __TBB_EXCEPTION_PTR_PRESENT __GXX_EXPERIMENTAL_CXX0X __ | |||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_CLANG_VERSION > 30100)// TODO: check version | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_CLANG_VERSION > 30100)// TODO: check version | |||
#define __TBB_STATIC_ASSERT_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_CLANG_VERSION >= 20900) | ||||
#define __TBB_CPP11_TUPLE_PRESENT ((__GXX_EXPERIMENTAL_CXX 0X__) && (__TBB_GCC_VERSION >= 40300)) | #define __TBB_CPP11_TUPLE_PRESENT ((__GXX_EXPERIMENTAL_CXX 0X__) && (__TBB_GCC_VERSION >= 40300)) | |||
#define __TBB_INITIALIZER_LISTS_PRESENT 0 | ||||
#elif __GNUC__ | #elif __GNUC__ | |||
#define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __GXX_EXPERIMENTAL_CXX0X __ | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __GXX_EXPERIMENTAL_CXX0X __ | |||
#define __TBB_CPP11_RVALUE_REF_PRESENT __GXX_EXPERIMENTAL_CXX0X __ | #define __TBB_CPP11_RVALUE_REF_PRESENT __GXX_EXPERIMENTAL_CXX0X __ | |||
/** __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 here is a substitution for _GLIB CXX_ATOMIC_BUILTINS_4, which is a prerequisite | /** __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 here is a substitution for _GLIB CXX_ATOMIC_BUILTINS_4, which is a prerequisite | |||
for exception_ptr but cannot be used in this file because it is def ined in a header, not by the compiler. | for exception_ptr but cannot be used in this file because it is def ined in a header, not by the compiler. | |||
If the compiler has no atomic intrinsics, the C++ library should no t expect those as well. **/ | If the compiler has no atomic intrinsics, the C++ library should no t expect those as well. **/ | |||
#define __TBB_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && (__TBB_GCC_VERSION >= 40404) && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | #define __TBB_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && (__TBB_GCC_VERSION >= 40404) && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | |||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_GCC_VERSION >= 40600) | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_CXX0 X__ && __TBB_GCC_VERSION >= 40600) | |||
#define __TBB_STATIC_ASSERT_PRESENT ((__TBB_GCC_VERSION >= 4 0300) && (__GXX_EXPERIMENTAL_CXX0X__)) | ||||
#define __TBB_CPP11_TUPLE_PRESENT ((__GXX_EXPERIMENTAL_CXX 0X__) && (__TBB_GCC_VERSION >= 40300)) | #define __TBB_CPP11_TUPLE_PRESENT ((__GXX_EXPERIMENTAL_CXX 0X__) && (__TBB_GCC_VERSION >= 40300)) | |||
#define __TBB_INITIALIZER_LISTS_PRESENT ((__GXX_EXPERIMENTAL_CXX 0X__) && (__TBB_GCC_VERSION >= 40400)) | ||||
#elif _MSC_VER | #elif _MSC_VER | |||
#define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | |||
#define __TBB_CPP11_RVALUE_REF_PRESENT 0 | #define __TBB_CPP11_RVALUE_REF_PRESENT 0 | |||
#define __TBB_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1600) | #define __TBB_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1600) | |||
#define __TBB_STATIC_ASSERT_PRESENT (_MSC_VER >= 1600) | ||||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700) | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700) | |||
#define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) | #define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) | |||
#define __TBB_INITIALIZER_LISTS_PRESENT 0 | ||||
#else | #else | |||
#define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | |||
#define __TBB_CPP11_RVALUE_REF_PRESENT 0 | #define __TBB_CPP11_RVALUE_REF_PRESENT 0 | |||
#define __TBB_EXCEPTION_PTR_PRESENT 0 | #define __TBB_EXCEPTION_PTR_PRESENT 0 | |||
#define __TBB_STATIC_ASSERT_PRESENT 0 | ||||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT 0 | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT 0 | |||
#define __TBB_CPP11_TUPLE_PRESENT 0 | #define __TBB_CPP11_TUPLE_PRESENT 0 | |||
#define __TBB_INITIALIZER_LISTS_PRESENT 0 | ||||
#endif | #endif | |||
//TODO: not clear how exactly this macro affects exception_ptr - investigat e | //TODO: not clear how exactly this macro affects exception_ptr - investigat e | |||
// On linux ICC fails to find existing std::exception_ptr in libstdc++ with out this define | // On linux ICC fails to find existing std::exception_ptr in libstdc++ with out this define | |||
#if __INTEL_COMPILER && __GNUC__ && __TBB_EXCEPTION_PTR_PRESENT && !defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | #if __INTEL_COMPILER && __GNUC__ && __TBB_EXCEPTION_PTR_PRESENT && !defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | |||
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 | #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 | |||
#endif | #endif | |||
// Work around a bug in MinGW32 | // Work around a bug in MinGW32 | |||
#if __MINGW32__ && __TBB_EXCEPTION_PTR_PRESENT && !defined(_GLIBCXX_ATOMIC_ BUILTINS_4) | #if __MINGW32__ && __TBB_EXCEPTION_PTR_PRESENT && !defined(_GLIBCXX_ATOMIC_ BUILTINS_4) | |||
#define _GLIBCXX_ATOMIC_BUILTINS_4 | #define _GLIBCXX_ATOMIC_BUILTINS_4 | |||
#endif | #endif | |||
#if __GNUC__ || __SUNPRO_CC || __IBMCPP__ | #if __GNUC__ || __SUNPRO_CC || __IBMCPP__ | |||
/* ICC defines __GNUC__ and so is covered */ | /* ICC defines __GNUC__ and so is covered */ | |||
#define __TBB_ATTRIBUTE_ALIGNED_PRESENT 1 | #define __TBB_ATTRIBUTE_ALIGNED_PRESENT 1 | |||
#elif _MSC_VER && (_MSC_VER >= 1300 || __INTEL_COMPILER) | #elif _MSC_VER && (_MSC_VER >= 1300 || __INTEL_COMPILER) | |||
#define __TBB_DECLSPEC_ALIGN_PRESENT 1 | #define __TBB_DECLSPEC_ALIGN_PRESENT 1 | |||
#endif | #endif | |||
/* Actually ICC supports gcc __sync_* intrinsics starting 11.1, | ||||
* but 64 bit support for 32 bit target comes in later ones*/ | ||||
/* TODO: change the version back to 4.1.2 once macro __TBB_WORD_SIZE become optional */ | /* TODO: change the version back to 4.1.2 once macro __TBB_WORD_SIZE become optional */ | |||
#if (__TBB_GCC_VERSION >= 40306) && !defined(__INTEL_COMPILER) | #if (__TBB_GCC_VERSION >= 40306) || (__INTEL_COMPILER >= 1200) | |||
/** built-in atomics available in GCC since 4.1.2 **/ | /** built-in atomics available in GCC since 4.1.2 **/ | |||
#define __TBB_GCC_BUILTIN_ATOMICS_PRESENT 1 | #define __TBB_GCC_BUILTIN_ATOMICS_PRESENT 1 | |||
#endif | #endif | |||
#if (__INTEL_COMPILER >= 1210) | ||||
/** built-in C++11 style atomics available in compiler since 12.1 **/ | ||||
#define __TBB_ICC_BUILTIN_ATOMICS_PRESENT 1 | ||||
#endif | ||||
/** User controlled TBB features & modes **/ | /** User controlled TBB features & modes **/ | |||
#ifndef TBB_USE_DEBUG | #ifndef TBB_USE_DEBUG | |||
#ifdef TBB_DO_ASSERT | #ifdef TBB_DO_ASSERT | |||
#define TBB_USE_DEBUG TBB_DO_ASSERT | #define TBB_USE_DEBUG TBB_DO_ASSERT | |||
#else | #else | |||
#ifdef _DEBUG | #ifdef _DEBUG | |||
#define TBB_USE_DEBUG _DEBUG | #define TBB_USE_DEBUG _DEBUG | |||
#else | #else | |||
#define TBB_USE_DEBUG 0 | #define TBB_USE_DEBUG 0 | |||
skipping to change at line 230 | skipping to change at line 249 | |||
#endif | #endif | |||
#endif /* defined TBB_USE_CAPTURED_EXCEPTION */ | #endif /* defined TBB_USE_CAPTURED_EXCEPTION */ | |||
/** Check whether the request to use GCC atomics can be satisfied **/ | /** Check whether the request to use GCC atomics can be satisfied **/ | |||
#if (TBB_USE_GCC_BUILTINS && !__TBB_GCC_BUILTIN_ATOMICS_PRESENT) | #if (TBB_USE_GCC_BUILTINS && !__TBB_GCC_BUILTIN_ATOMICS_PRESENT) | |||
#error "GCC atomic built-ins are not supported." | #error "GCC atomic built-ins are not supported." | |||
#endif | #endif | |||
/** Internal TBB features & modes **/ | /** Internal TBB features & modes **/ | |||
/** __TBB_DYNAMIC_LOAD_ENABLED describes the system possibility to dynamic | /** __TBB_WEAK_SYMBOLS_PRESENT denotes that the system supports the weak sy | |||
load libraries | mbol mechanism **/ | |||
__TBB_SOURCE_DIRECTLY_INCLUDED is a mode used in whitebox testing when | #define __TBB_WEAK_SYMBOLS_PRESENT !_WIN32 && !__APPLE__ && !__sun && ((__T | |||
it's necessary to test internal functions not exported from TBB DLLs | BB_GCC_VERSION >= 40000) || defined(__INTEL_COMPILER)) | |||
**/ | ||||
/** __TBB_DYNAMIC_LOAD_ENABLED describes the system possibility to load sha red libraries at run time **/ | ||||
#ifndef __TBB_DYNAMIC_LOAD_ENABLED | #ifndef __TBB_DYNAMIC_LOAD_ENABLED | |||
#define __TBB_DYNAMIC_LOAD_ENABLED 1 | #define __TBB_DYNAMIC_LOAD_ENABLED 1 | |||
#elif !(_WIN32||_WIN64) && !__TBB_DYNAMIC_LOAD_ENABLED | ||||
#define __TBB_WEAK_SYMBOLS 1 | ||||
#endif | #endif | |||
/** __TBB_SOURCE_DIRECTLY_INCLUDED is a mode used in whitebox testing when | ||||
it's necessary to test internal functions not exported from TBB DLLs | ||||
**/ | ||||
#if (_WIN32||_WIN64) && __TBB_SOURCE_DIRECTLY_INCLUDED | #if (_WIN32||_WIN64) && __TBB_SOURCE_DIRECTLY_INCLUDED | |||
#define __TBB_NO_IMPLICIT_LINKAGE 1 | #define __TBB_NO_IMPLICIT_LINKAGE 1 | |||
#define __TBBMALLOC_NO_IMPLICIT_LINKAGE 1 | #define __TBBMALLOC_NO_IMPLICIT_LINKAGE 1 | |||
#endif | #endif | |||
#ifndef __TBB_COUNT_TASK_NODES | #ifndef __TBB_COUNT_TASK_NODES | |||
#define __TBB_COUNT_TASK_NODES TBB_USE_ASSERT | #define __TBB_COUNT_TASK_NODES TBB_USE_ASSERT | |||
#endif | #endif | |||
#ifndef __TBB_TASK_GROUP_CONTEXT | #ifndef __TBB_TASK_GROUP_CONTEXT | |||
skipping to change at line 288 | skipping to change at line 307 | |||
#ifndef __TBB_TASK_PRIORITY | #ifndef __TBB_TASK_PRIORITY | |||
#define __TBB_TASK_PRIORITY __TBB_TASK_GROUP_CONTEXT | #define __TBB_TASK_PRIORITY __TBB_TASK_GROUP_CONTEXT | |||
#endif /* __TBB_TASK_PRIORITY */ | #endif /* __TBB_TASK_PRIORITY */ | |||
#if __TBB_TASK_PRIORITY && !__TBB_TASK_GROUP_CONTEXT | #if __TBB_TASK_PRIORITY && !__TBB_TASK_GROUP_CONTEXT | |||
#error __TBB_TASK_PRIORITY requires __TBB_TASK_GROUP_CONTEXT to be enab led | #error __TBB_TASK_PRIORITY requires __TBB_TASK_GROUP_CONTEXT to be enab led | |||
#endif | #endif | |||
#if !defined(__TBB_SURVIVE_THREAD_SWITCH) && \ | #if !defined(__TBB_SURVIVE_THREAD_SWITCH) && \ | |||
(_WIN32 || _WIN64 || __APPLE__ || __linux__) | (_WIN32 || _WIN64 || __APPLE__ || (__linux__ && !__ANDROID__)) | |||
#define __TBB_SURVIVE_THREAD_SWITCH 1 | #define __TBB_SURVIVE_THREAD_SWITCH 1 | |||
#endif /* __TBB_SURVIVE_THREAD_SWITCH */ | #endif /* __TBB_SURVIVE_THREAD_SWITCH */ | |||
#ifndef __TBB_DEFAULT_PARTITIONER | #ifndef __TBB_DEFAULT_PARTITIONER | |||
#if TBB_DEPRECATED | #if TBB_DEPRECATED | |||
/** Default partitioner for parallel loop templates in TBB 1.0-2.1 */ | /** Default partitioner for parallel loop templates in TBB 1.0-2.1 */ | |||
#define __TBB_DEFAULT_PARTITIONER tbb::simple_partitioner | #define __TBB_DEFAULT_PARTITIONER tbb::simple_partitioner | |||
#else | #else | |||
/** Default partitioner for parallel loop templates since TBB 2.2 */ | /** Default partitioner for parallel loop templates since TBB 2.2 */ | |||
#define __TBB_DEFAULT_PARTITIONER tbb::auto_partitioner | #define __TBB_DEFAULT_PARTITIONER tbb::auto_partitioner | |||
skipping to change at line 318 | skipping to change at line 337 | |||
#define __TBB_VARIADIC_MAX 10 | #define __TBB_VARIADIC_MAX 10 | |||
#endif | #endif | |||
#endif | #endif | |||
/** Macros of the form __TBB_XXX_BROKEN denote known issues that are caused by | /** Macros of the form __TBB_XXX_BROKEN denote known issues that are caused by | |||
the bugs in compilers, standard or OS specific libraries. They should b e | the bugs in compilers, standard or OS specific libraries. They should b e | |||
removed as soon as the corresponding bugs are fixed or the buggy OS/com piler | removed as soon as the corresponding bugs are fixed or the buggy OS/com piler | |||
versions go out of the support list. | versions go out of the support list. | |||
**/ | **/ | |||
#if __ANDROID__ && __TBB_GCC_VERSION <= 40403 && !__GCC_HAVE_SYNC_COMPARE_A | ||||
ND_SWAP_8 | ||||
/** Necessary because on Android 8-byte CAS and F&A are not available f | ||||
or some processor architectures, | ||||
but no mandatory warning message appears from GCC 4.4.3. Instead, o | ||||
nly a linkage error occurs when | ||||
these atomic operations are used (such as in unit test test_atomic. | ||||
exe). **/ | ||||
#define __TBB_GCC_64BIT_ATOMIC_BUILTINS_BROKEN 1 | ||||
#endif | ||||
#if __GNUC__ && __TBB_x86_64 && __INTEL_COMPILER == 1200 | #if __GNUC__ && __TBB_x86_64 && __INTEL_COMPILER == 1200 | |||
#define __TBB_ICC_12_0_INL_ASM_FSTCW_BROKEN 1 | #define __TBB_ICC_12_0_INL_ASM_FSTCW_BROKEN 1 | |||
#endif | #endif | |||
#if _MSC_VER && __INTEL_COMPILER && (__INTEL_COMPILER<1110 || __INTEL_COMPI LER==1110 && __INTEL_COMPILER_BUILD_DATE < 20091012) | #if _MSC_VER && __INTEL_COMPILER && (__INTEL_COMPILER<1110 || __INTEL_COMPI LER==1110 && __INTEL_COMPILER_BUILD_DATE < 20091012) | |||
/** Necessary to avoid ICL error (or warning in non-strict mode): | /** Necessary to avoid ICL error (or warning in non-strict mode): | |||
"exception specification for implicitly declared virtual destructor is | "exception specification for implicitly declared virtual destructor is | |||
incompatible with that of overridden one". **/ | incompatible with that of overridden one". **/ | |||
#define __TBB_DEFAULT_DTOR_THROW_SPEC_BROKEN 1 | #define __TBB_DEFAULT_DTOR_THROW_SPEC_BROKEN 1 | |||
#endif | #endif | |||
skipping to change at line 399 | skipping to change at line 425 | |||
#define __TBB_CPP11_STD_FORWARD_BROKEN 1 | #define __TBB_CPP11_STD_FORWARD_BROKEN 1 | |||
#else | #else | |||
#define __TBB_CPP11_STD_FORWARD_BROKEN 0 | #define __TBB_CPP11_STD_FORWARD_BROKEN 0 | |||
#endif | #endif | |||
#if __TBB_DEFINE_MIC | #if __TBB_DEFINE_MIC | |||
/** Main thread and user's thread have different default thread affinit y masks. **/ | /** Main thread and user's thread have different default thread affinit y masks. **/ | |||
#define __TBB_MAIN_THREAD_AFFINITY_BROKEN 1 | #define __TBB_MAIN_THREAD_AFFINITY_BROKEN 1 | |||
#endif | #endif | |||
#if !defined(__EXCEPTIONS) && __GNUC__==4 && (__GNUC_MINOR__==4 ||__GNUC_MI | #if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP | |||
NOR__==5) && defined(__GXX_EXPERIMENTAL_CXX0X__) | #define __TBB_WIN8UI_SUPPORT 1 | |||
#else | ||||
#define __TBB_WIN8UI_SUPPORT 0 | ||||
#endif | ||||
#if !defined(__EXCEPTIONS) && __GNUC__==4 && (__GNUC_MINOR__==4 ||__GNUC_MI | ||||
NOR__==5 || (__INTEL_COMPILER==1300 && __TBB_GCC_VERSION>=40600 && __TBB_GC | ||||
C_VERSION<=40700)) && defined(__GXX_EXPERIMENTAL_CXX0X__) | ||||
/* There is an issue for specific GCC toolchain when C++11 is enabled | /* There is an issue for specific GCC toolchain when C++11 is enabled | |||
and exceptions are disabled: | and exceptions are disabled: | |||
exceprion_ptr.h/nested_exception.h are using throw unconditionally. | exceprion_ptr.h/nested_exception.h are using throw unconditionally. | |||
*/ | */ | |||
#define __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 1 | #define __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 1 | |||
#else | #else | |||
#define __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 0 | #define __TBB_LIBSTDCPP_EXCEPTION_HEADERS_BROKEN 0 | |||
#endif | #endif | |||
#endif /* __TBB_tbb_config_H */ | #endif /* __TBB_tbb_config_H */ | |||
End of changes. 21 change blocks. | ||||
11 lines changed or deleted | 50 lines changed or added | |||
tbb_machine.h | tbb_machine.h | |||
---|---|---|---|---|
skipping to change at line 192 | skipping to change at line 192 | |||
#if __MINGW64__ || __MINGW32__ | #if __MINGW64__ || __MINGW32__ | |||
extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); | extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); | |||
#define __TBB_Yield() SwitchToThread() | #define __TBB_Yield() SwitchToThread() | |||
#if (TBB_USE_GCC_BUILTINS && __TBB_GCC_BUILTIN_ATOMICS_PRESENT) | #if (TBB_USE_GCC_BUILTINS && __TBB_GCC_BUILTIN_ATOMICS_PRESENT) | |||
#include "machine/gcc_generic.h" | #include "machine/gcc_generic.h" | |||
#elif __MINGW64__ | #elif __MINGW64__ | |||
#include "machine/linux_intel64.h" | #include "machine/linux_intel64.h" | |||
#elif __MINGW32__ | #elif __MINGW32__ | |||
#include "machine/linux_ia32.h" | #include "machine/linux_ia32.h" | |||
#endif | #endif | |||
#elif (TBB_USE_ICC_BUILTINS && __TBB_ICC_BUILTIN_ATOMICS_PRESENT) | ||||
#include "machine/icc_generic.h" | ||||
#elif defined(_M_IX86) | #elif defined(_M_IX86) | |||
#include "machine/windows_ia32.h" | #include "machine/windows_ia32.h" | |||
#elif defined(_M_X64) | #elif defined(_M_X64) | |||
#include "machine/windows_intel64.h" | #include "machine/windows_intel64.h" | |||
#elif _XBOX | #elif _XBOX | |||
#include "machine/xbox360_ppc.h" | #include "machine/xbox360_ppc.h" | |||
#endif | #endif | |||
#ifdef _MANAGED | #ifdef _MANAGED | |||
#pragma managed(pop) | #pragma managed(pop) | |||
#endif | #endif | |||
#elif __TBB_DEFINE_MIC | #elif __TBB_DEFINE_MIC | |||
#include "machine/mic_common.h" | #include "machine/mic_common.h" | |||
//TODO: check if ICC atomic intrinsics are available for MIC | ||||
#include "machine/linux_intel64.h" | #include "machine/linux_intel64.h" | |||
#elif __linux__ || __FreeBSD__ || __NetBSD__ | #elif __linux__ || __FreeBSD__ || __NetBSD__ | |||
#if (TBB_USE_GCC_BUILTINS && __TBB_GCC_BUILTIN_ATOMICS_PRESENT) | #if (TBB_USE_GCC_BUILTINS && __TBB_GCC_BUILTIN_ATOMICS_PRESENT) | |||
#include "machine/gcc_generic.h" | #include "machine/gcc_generic.h" | |||
#elif (TBB_USE_ICC_BUILTINS && __TBB_ICC_BUILTIN_ATOMICS_PRESENT) | ||||
#include "machine/icc_generic.h" | ||||
#elif __i386__ | #elif __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 __ia64__ | #elif __ia64__ | |||
#include "machine/linux_ia64.h" | #include "machine/linux_ia64.h" | |||
#elif __powerpc__ | #elif __powerpc__ | |||
#include "machine/mac_ppc.h" | #include "machine/mac_ppc.h" | |||
#elif __TBB_GCC_BUILTIN_ATOMICS_PRESENT | #elif __TBB_GCC_BUILTIN_ATOMICS_PRESENT | |||
#include "machine/gcc_generic.h" | #include "machine/gcc_generic.h" | |||
#endif | #endif | |||
#include "machine/linux_common.h" | #include "machine/linux_common.h" | |||
#elif __APPLE__ | #elif __APPLE__ | |||
//TODO: TBB_USE_GCC_BUILTINS is not used for Mac, Sun, Aix | ||||
#if __i386__ | #if (TBB_USE_ICC_BUILTINS && __TBB_ICC_BUILTIN_ATOMICS_PRESENT) | |||
#include "machine/icc_generic.h" | ||||
#elif __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 __POWERPC__ | #elif __POWERPC__ | |||
#include "machine/mac_ppc.h" | #include "machine/mac_ppc.h" | |||
#endif | #endif | |||
#include "machine/macos_common.h" | #include "machine/macos_common.h" | |||
#elif _AIX | #elif _AIX | |||
skipping to change at line 263 | skipping to change at line 270 | |||
#include <sched.h> | #include <sched.h> | |||
#define __TBB_Yield() sched_yield() | #define __TBB_Yield() sched_yield() | |||
#endif /* OS selection */ | #endif /* OS selection */ | |||
#ifndef __TBB_64BIT_ATOMICS | #ifndef __TBB_64BIT_ATOMICS | |||
#define __TBB_64BIT_ATOMICS 1 | #define __TBB_64BIT_ATOMICS 1 | |||
#endif | #endif | |||
//TODO: replace usage of these functions with usage of tbb::atomic, and the | ||||
n remove them | ||||
//TODO: map functions with W suffix to use cast to tbb::atomic and accordin | ||||
g op, i.e. as_atomic().op() | ||||
// Special atomic functions | // Special atomic functions | |||
#if __TBB_USE_FENCED_ATOMICS | #if __TBB_USE_FENCED_ATOMICS | |||
#define __TBB_machine_cmpswp1 __TBB_machine_cmpswp1full_fence | #define __TBB_machine_cmpswp1 __TBB_machine_cmpswp1full_fence | |||
#define __TBB_machine_cmpswp2 __TBB_machine_cmpswp2full_fence | #define __TBB_machine_cmpswp2 __TBB_machine_cmpswp2full_fence | |||
#define __TBB_machine_cmpswp4 __TBB_machine_cmpswp4full_fence | #define __TBB_machine_cmpswp4 __TBB_machine_cmpswp4full_fence | |||
#define __TBB_machine_cmpswp8 __TBB_machine_cmpswp8full_fence | #define __TBB_machine_cmpswp8 __TBB_machine_cmpswp8full_fence | |||
#if __TBB_WORDSIZE==8 | #if __TBB_WORDSIZE==8 | |||
#define __TBB_machine_fetchadd8 __TBB_machine_fetchadd8 full_fence | #define __TBB_machine_fetchadd8 __TBB_machine_fetchadd8 full_fence | |||
#define __TBB_machine_fetchstore8 __TBB_machine_fetchstor e8full_fence | #define __TBB_machine_fetchstore8 __TBB_machine_fetchstor e8full_fence | |||
#define __TBB_FetchAndAddWrelease(P,V) __TBB_machine_fetchadd8 release(P,V) | #define __TBB_FetchAndAddWrelease(P,V) __TBB_machine_fetchadd8 release(P,V) | |||
#define __TBB_FetchAndIncrementWacquire(P) __TBB_machine_fetchadd8 acquire(P,1) | #define __TBB_FetchAndIncrementWacquire(P) __TBB_machine_fetchadd8 acquire(P,1) | |||
#define __TBB_FetchAndDecrementWrelease(P) __TBB_machine_fetchadd8 release(P,(-1)) | #define __TBB_FetchAndDecrementWrelease(P) __TBB_machine_fetchadd8 release(P,(-1)) | |||
#else | #else | |||
#error Define macros for 4-byte word, similarly to the above __TBB_ | #define __TBB_machine_fetchadd4 __TBB_machine_fetchadd4 | |||
WORDSIZE==8 branch. | full_fence | |||
#define __TBB_machine_fetchstore4 __TBB_machine_fetchstor | ||||
e4full_fence | ||||
#define __TBB_FetchAndAddWrelease(P,V) __TBB_machine_fetchadd4 | ||||
release(P,V) | ||||
#define __TBB_FetchAndIncrementWacquire(P) __TBB_machine_fetchadd4 | ||||
acquire(P,1) | ||||
#define __TBB_FetchAndDecrementWrelease(P) __TBB_machine_fetchadd4 | ||||
release(P,(-1)) | ||||
#endif /* __TBB_WORDSIZE==4 */ | #endif /* __TBB_WORDSIZE==4 */ | |||
#else /* !__TBB_USE_FENCED_ATOMICS */ | #else /* !__TBB_USE_FENCED_ATOMICS */ | |||
#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)) | |||
#endif /* !__TBB_USE_FENCED_ATOMICS */ | #endif /* !__TBB_USE_FENCED_ATOMICS */ | |||
#if __TBB_WORDSIZE==4 | #if __TBB_WORDSIZE==4 | |||
#define __TBB_CompareAndSwapW(P,V,C) __TBB_machine_cmpswp4(P,V,C) | #define __TBB_CompareAndSwapW(P,V,C) __TBB_machine_cmpswp4(P,V,C) | |||
#define __TBB_FetchAndAddW(P,V) __TBB_machine_fetchadd4(P,V) | #define __TBB_FetchAndAddW(P,V) __TBB_machine_fetchadd4(P,V) | |||
End of changes. 6 change blocks. | ||||
4 lines changed or deleted | 23 lines changed or added | |||
tbb_stddef.h | tbb_stddef.h | |||
---|---|---|---|---|
skipping to change at line 37 | skipping to change at line 37 | |||
*/ | */ | |||
#ifndef __TBB_tbb_stddef_H | #ifndef __TBB_tbb_stddef_H | |||
#define __TBB_tbb_stddef_H | #define __TBB_tbb_stddef_H | |||
// Marketing-driven product version | // Marketing-driven product version | |||
#define TBB_VERSION_MAJOR 4 | #define TBB_VERSION_MAJOR 4 | |||
#define TBB_VERSION_MINOR 1 | #define TBB_VERSION_MINOR 1 | |||
// Engineering-focused interface version | // Engineering-focused interface version | |||
#define TBB_INTERFACE_VERSION 6100 | #define TBB_INTERFACE_VERSION 6101 | |||
#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 | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
tuple | tuple | |||
---|---|---|---|---|
skipping to change at line 40 | skipping to change at line 40 | |||
#define __TBB_tuple_H | #define __TBB_tuple_H | |||
#include <utility> | #include <utility> | |||
#include "../tbb_stddef.h" | #include "../tbb_stddef.h" | |||
// build preprocessor variables for varying number of arguments | // build preprocessor variables for varying number of arguments | |||
// Need the leading comma so the empty __TBB_T_PACK will not cause a syntax error. | // Need the leading comma so the empty __TBB_T_PACK will not cause a syntax error. | |||
#if __TBB_VARIADIC_MAX <= 5 | #if __TBB_VARIADIC_MAX <= 5 | |||
#define __TBB_T_PACK | #define __TBB_T_PACK | |||
#define __TBB_U_PACK | #define __TBB_U_PACK | |||
#define __TBB_CLASS_T_PACK | #define __TBB_TYPENAME_T_PACK | |||
#define __TBB_CLASS_U_PACK | #define __TBB_TYPENAME_U_PACK | |||
#define __TBB_NULL_TYPE_PACK | #define __TBB_NULL_TYPE_PACK | |||
#define __TBB_REF_T_PARAM_PACK | #define __TBB_REF_T_PARAM_PACK | |||
#define __TBB_CONST_REF_T_PARAM_PACK | #define __TBB_CONST_REF_T_PARAM_PACK | |||
#define __TBB_T_PARAM_LIST_PACK | #define __TBB_T_PARAM_LIST_PACK | |||
#define __TBB_CONST_NULL_REF_PACK | #define __TBB_CONST_NULL_REF_PACK | |||
// | // | |||
#elif __TBB_VARIADIC_MAX == 6 | #elif __TBB_VARIADIC_MAX == 6 | |||
#define __TBB_T_PACK ,T5 | #define __TBB_T_PACK ,T5 | |||
#define __TBB_U_PACK ,U5 | #define __TBB_U_PACK ,U5 | |||
#define __TBB_CLASS_T_PACK , class T5 | #define __TBB_TYPENAME_T_PACK , typename T5 | |||
#define __TBB_CLASS_U_PACK , class U5 | #define __TBB_TYPENAME_U_PACK , typename U5 | |||
#define __TBB_NULL_TYPE_PACK , null_type | #define __TBB_NULL_TYPE_PACK , null_type | |||
#define __TBB_REF_T_PARAM_PACK ,T5& t5 | #define __TBB_REF_T_PARAM_PACK ,T5& t5 | |||
#define __TBB_CONST_REF_T_PARAM_PACK ,const T5& t5 | #define __TBB_CONST_REF_T_PARAM_PACK ,const T5& t5 | |||
#define __TBB_T_PARAM_LIST_PACK ,t5 | #define __TBB_T_PARAM_LIST_PACK ,t5 | |||
#define __TBB_CONST_NULL_REF_PACK , const null_type& | #define __TBB_CONST_NULL_REF_PACK , const null_type& | |||
// | // | |||
#elif __TBB_VARIADIC_MAX == 7 | #elif __TBB_VARIADIC_MAX == 7 | |||
#define __TBB_T_PACK ,T5, T6 | #define __TBB_T_PACK ,T5, T6 | |||
#define __TBB_U_PACK ,U5, U6 | #define __TBB_U_PACK ,U5, U6 | |||
#define __TBB_CLASS_T_PACK , class T5 , class T6 | #define __TBB_TYPENAME_T_PACK , typename T5 , typename T6 | |||
#define __TBB_CLASS_U_PACK , class U5 , class U6 | #define __TBB_TYPENAME_U_PACK , typename U5 , typename U6 | |||
#define __TBB_NULL_TYPE_PACK , null_type, null_type | #define __TBB_NULL_TYPE_PACK , null_type, null_type | |||
#define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6 | #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6 | |||
#define __TBB_CONST_REF_T_PARAM_PACK ,const T5& t5, const T6& t6 | #define __TBB_CONST_REF_T_PARAM_PACK ,const T5& t5, const T6& t6 | |||
#define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 | #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 | |||
#define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type& | #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type& | |||
// | // | |||
#elif __TBB_VARIADIC_MAX == 8 | #elif __TBB_VARIADIC_MAX == 8 | |||
#define __TBB_T_PACK ,T5, T6, T7 | #define __TBB_T_PACK ,T5, T6, T7 | |||
#define __TBB_U_PACK ,U5, U6, U7 | #define __TBB_U_PACK ,U5, U6, U7 | |||
#define __TBB_CLASS_T_PACK , class T5 , class T6, class T7 | #define __TBB_TYPENAME_T_PACK , typename T5 , typename T6, typename T7 | |||
#define __TBB_CLASS_U_PACK , class U5 , class U6, class U7 | #define __TBB_TYPENAME_U_PACK , typename U5 , typename U6, typename U7 | |||
#define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type | #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type | |||
#define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7 | #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7 | |||
#define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7 & t7 | #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7 & t7 | |||
#define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 | #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 | |||
#define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con st null_type& | #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con st null_type& | |||
// | // | |||
#elif __TBB_VARIADIC_MAX == 9 | #elif __TBB_VARIADIC_MAX == 9 | |||
#define __TBB_T_PACK ,T5, T6, T7, T8 | #define __TBB_T_PACK ,T5, T6, T7, T8 | |||
#define __TBB_U_PACK ,U5, U6, U7, U8 | #define __TBB_U_PACK ,U5, U6, U7, U8 | |||
#define __TBB_CLASS_T_PACK , class T5, class T6, class T7, class T8 | #define __TBB_TYPENAME_T_PACK , typename T5, typename T6, typename T7, type | |||
#define __TBB_CLASS_U_PACK , class U5, class U6, class U7, class U8 | name T8 | |||
#define __TBB_TYPENAME_U_PACK , typename U5, typename U6, typename U7, type | ||||
name U8 | ||||
#define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type, null_type | #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type, null_type | |||
#define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7, T8& t8 | #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7, T8& t8 | |||
#define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7 & t7, const T8& t8 | #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7 & t7, const T8& t8 | |||
#define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 ,t8 | #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 ,t8 | |||
#define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con st null_type&, const null_type& | #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con st null_type&, const null_type& | |||
// | // | |||
#elif __TBB_VARIADIC_MAX >= 10 | #elif __TBB_VARIADIC_MAX >= 10 | |||
#define __TBB_T_PACK ,T5, T6, T7, T8, T9 | #define __TBB_T_PACK ,T5, T6, T7, T8, T9 | |||
#define __TBB_U_PACK ,U5, U6, U7, U8, U9 | #define __TBB_U_PACK ,U5, U6, U7, U8, U9 | |||
#define __TBB_CLASS_T_PACK , class T5, class T6, class T7, class T8, class | #define __TBB_TYPENAME_T_PACK , typename T5, typename T6, typename T7, type | |||
T9 | name T8, typename T9 | |||
#define __TBB_CLASS_U_PACK , class U5, class U6, class U7, class U8, class | #define __TBB_TYPENAME_U_PACK , typename U5, typename U6, typename U7, type | |||
U9 | name U8, typename U9 | |||
#define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type, null_type, null_type | #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type, null_type, null_type | |||
#define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7, T8& t8, T9& t9 | #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7, T8& t8, T9& t9 | |||
#define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7 & t7, const T8& t8, const T9& t9 | #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7 & t7, const T8& t8, const T9& t9 | |||
#define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 ,t8 ,t9 | #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 ,t8 ,t9 | |||
#define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con st null_type&, const null_type&, const null_type& | #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con st null_type&, const null_type&, const null_type& | |||
#endif | #endif | |||
namespace tbb { | namespace tbb { | |||
namespace interface5 { | namespace interface5 { | |||
namespace internal { | namespace internal { | |||
struct null_type { }; | struct null_type { }; | |||
} | } | |||
using internal::null_type; | using internal::null_type; | |||
// tuple forward declaration | // tuple forward declaration | |||
template <class T0=null_type, class T1=null_type, class T2=null_type, class | template <typename T0=null_type, typename T1=null_type, typename T2=null_ty | |||
T3=null_type, class T4=null_type | pe, | |||
typename T3=null_type, typename T4=null_type | ||||
#if __TBB_VARIADIC_MAX >= 6 | #if __TBB_VARIADIC_MAX >= 6 | |||
, class T5=null_type | , typename T5=null_type | |||
#if __TBB_VARIADIC_MAX >= 7 | #if __TBB_VARIADIC_MAX >= 7 | |||
, class T6=null_type | , typename T6=null_type | |||
#if __TBB_VARIADIC_MAX >= 8 | #if __TBB_VARIADIC_MAX >= 8 | |||
, class T7=null_type | , typename T7=null_type | |||
#if __TBB_VARIADIC_MAX >= 9 | #if __TBB_VARIADIC_MAX >= 9 | |||
, class T8=null_type | , typename T8=null_type | |||
#if __TBB_VARIADIC_MAX >= 10 | #if __TBB_VARIADIC_MAX >= 10 | |||
, class T9=null_type | , typename T9=null_type | |||
#endif | #endif | |||
#endif | #endif | |||
#endif | #endif | |||
#endif | #endif | |||
#endif | #endif | |||
> | > | |||
class tuple; | class tuple; | |||
namespace internal { | namespace internal { | |||
// const null_type temp | // const null_type temp | |||
inline const null_type cnull() { return null_type(); } | inline const null_type cnull() { return null_type(); } | |||
// cons forward declaration | // cons forward declaration | |||
template <class HT, class TT> struct cons; | template <typename HT, typename TT> struct cons; | |||
// type of a component of the cons | // type of a component of the cons | |||
template<int N, class T> | template<int N, typename T> | |||
struct component { | struct component { | |||
typedef typename T::tail_type next; | typedef typename T::tail_type next; | |||
typedef typename component<N-1,next>::type type; | typedef typename component<N-1,next>::type type; | |||
}; | }; | |||
template<class T> | template<typename T> | |||
struct component<0,T> { | struct component<0,T> { | |||
typedef typename T::head_type type; | typedef typename T::head_type type; | |||
}; | }; | |||
template<> | template<> | |||
struct component<0,null_type> { | struct component<0,null_type> { | |||
typedef null_type type; | typedef null_type type; | |||
}; | }; | |||
// const version of component | // const version of component | |||
template<int N, class T> | template<int N, typename T> | |||
struct component<N, const T> | struct component<N, const T> | |||
{ | { | |||
typedef typename T::tail_type next; | typedef typename T::tail_type next; | |||
typedef const typename component<N-1,next>::type type; | typedef const typename component<N-1,next>::type type; | |||
}; | }; | |||
template<class T> | template<typename T> | |||
struct component<0, const T> | struct component<0, const T> | |||
{ | { | |||
typedef const typename T::head_type type; | typedef const typename T::head_type type; | |||
}; | }; | |||
// helper class for getting components of cons | // helper class for getting components of cons | |||
template< int N> | template< int N> | |||
struct get_helper { | struct get_helper { | |||
template<class HT, class TT> | template<typename HT, typename TT> | |||
inline static typename component<N, cons<HT,TT> >::type& get(cons<HT,TT>& t i) { | inline static typename component<N, cons<HT,TT> >::type& get(cons<HT,TT>& t i) { | |||
return get_helper<N-1>::get(ti.tail); | return get_helper<N-1>::get(ti.tail); | |||
} | } | |||
template<class HT, class TT> | template<typename HT, typename TT> | |||
inline static typename component<N, cons<HT,TT> >::type const& get(const co ns<HT,TT>& ti) { | inline static typename component<N, cons<HT,TT> >::type const& get(const co ns<HT,TT>& ti) { | |||
return get_helper<N-1>::get(ti.tail); | return get_helper<N-1>::get(ti.tail); | |||
} | } | |||
}; | }; | |||
template<> | template<> | |||
struct get_helper<0> { | struct get_helper<0> { | |||
template<class HT, class TT> | template<typename HT, typename TT> | |||
inline static typename component<0, cons<HT,TT> >::type& get(cons<HT,TT>& t i) { | inline static typename component<0, cons<HT,TT> >::type& get(cons<HT,TT>& t i) { | |||
return ti.head; | return ti.head; | |||
} | } | |||
template<class HT, class TT> | template<typename HT, typename TT> | |||
inline static typename component<0, cons<HT,TT> >::type const& get(const co ns<HT,TT>& ti) { | inline static typename component<0, cons<HT,TT> >::type const& get(const co ns<HT,TT>& ti) { | |||
return ti.head; | return ti.head; | |||
} | } | |||
}; | }; | |||
// traits adaptor | // traits adaptor | |||
template <class T0, class T1, class T2, class T3, class T4 __TBB_CLASS_T_PA CK> | template <typename T0, typename T1, typename T2, typename T3, typename T4 _ _TBB_TYPENAME_T_PACK> | |||
struct tuple_traits { | struct tuple_traits { | |||
typedef cons <T0, typename tuple_traits<T1, T2, T3, T4 __TBB_T_PACK , n ull_type>::U > U; | typedef cons <T0, typename tuple_traits<T1, T2, T3, T4 __TBB_T_PACK , n ull_type>::U > U; | |||
}; | }; | |||
template <> | template <typename T0> | |||
struct tuple_traits<class T0, null_type, null_type, null_type, null_type __ | struct tuple_traits<T0, null_type, null_type, null_type, null_type __TBB_NU | |||
TBB_NULL_TYPE_PACK > { | LL_TYPE_PACK > { | |||
typedef cons<T0, null_type> U; | typedef cons<T0, null_type> U; | |||
}; | }; | |||
template<> | template<> | |||
struct tuple_traits<null_type, null_type, null_type, null_type, null_type _ _TBB_NULL_TYPE_PACK > { | struct tuple_traits<null_type, null_type, null_type, null_type, null_type _ _TBB_NULL_TYPE_PACK > { | |||
typedef null_type U; | typedef null_type U; | |||
}; | }; | |||
// core cons defs | // core cons defs | |||
template <class HT, class TT> | template <typename HT, typename TT> | |||
struct cons{ | struct cons{ | |||
typedef HT head_type; | typedef HT head_type; | |||
typedef TT tail_type; | typedef TT tail_type; | |||
HT head; | head_type head; | |||
TT tail; | tail_type tail; | |||
static const int length = 1 + tail_type::length; | static const int length = 1 + tail_type::length; | |||
// default constructors | // default constructors | |||
explicit cons() : head(), tail() { } | explicit cons() : head(), tail() { } | |||
// non-default constructors | // non-default constructors | |||
cons(head_type& h, const tail_type& t) : head(h), tail(t) { } | cons(head_type& h, const tail_type& t) : head(h), tail(t) { } | |||
template <class T0, class T1, class T2, class T3, class T4 __TBB_CLASS_ T_PACK > | template <typename T0, typename T1, typename T2, typename T3, typename T4 __TBB_TYPENAME_T_PACK > | |||
cons(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4 __TBB_CONST_REF_T_PARAM_PACK) : | cons(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4 __TBB_CONST_REF_T_PARAM_PACK) : | |||
head(t0), tail(t1, t2, t3, t4 __TBB_T_PARAM_LIST_PACK, cnull()) { } | head(t0), tail(t1, t2, t3, t4 __TBB_T_PARAM_LIST_PACK, cnull()) { } | |||
template <class T0, class T1, class T2, class T3, class T4 __TBB_CLASS_ T_PACK > | template <typename T0, typename T1, typename T2, typename T3, typename T4 __TBB_TYPENAME_T_PACK > | |||
cons(T0& t0, T1& t1, T2& t2, T3& t3, T4& t4 __TBB_REF_T_PARAM_PACK) : | cons(T0& t0, T1& t1, T2& t2, T3& t3, T4& t4 __TBB_REF_T_PARAM_PACK) : | |||
head(t0), tail(t1, t2, t3, t4 __TBB_T_PARAM_LIST_PACK , cnull()) { } | head(t0), tail(t1, t2, t3, t4 __TBB_T_PARAM_LIST_PACK , cnull()) { } | |||
template <class HT1, class TT1> | template <typename HT1, typename TT1> | |||
cons(const cons<HT1,TT1>& other) : head(other.head), tail(other.tail) { } | cons(const cons<HT1,TT1>& other) : head(other.head), tail(other.tail) { } | |||
cons& operator=(const cons& other) { head = other.head; tail = other.ta il; return *this; } | cons& operator=(const cons& other) { head = other.head; tail = other.ta il; return *this; } | |||
friend bool operator==(const cons& me, const cons& other) { | friend bool operator==(const cons& me, const cons& other) { | |||
return me.head == other.head && me.tail == other.tail; | return me.head == other.head && me.tail == other.tail; | |||
} | } | |||
friend bool operator<(const cons& me, const cons& other) { | friend bool operator<(const cons& me, const cons& other) { | |||
return me.head < other.head || (!(other.head < me.head) && me.tail < other.tail); | return me.head < other.head || (!(other.head < me.head) && me.tail < other.tail); | |||
} | } | |||
friend bool operator>(const cons& me, const cons& other) { return othe r<me; } | friend bool operator>(const cons& me, const cons& other) { return othe r<me; } | |||
friend bool operator!=(const cons& me, const cons& other) { return !(me ==other); } | friend bool operator!=(const cons& me, const cons& other) { return !(me ==other); } | |||
friend bool operator>=(const cons& me, const cons& other) { return !(me <other); } | friend bool operator>=(const cons& me, const cons& other) { return !(me <other); } | |||
friend bool operator<=(const cons& me, const cons& other) { return !(me >other); } | friend bool operator<=(const cons& me, const cons& other) { return !(me >other); } | |||
template<class HT1, class TT1> | template<typename HT1, typename TT1> | |||
friend bool operator==(const cons<HT,TT>& me, const cons<HT1,TT1>& othe r) { | friend bool operator==(const cons<HT,TT>& me, const cons<HT1,TT1>& othe r) { | |||
return me.head == other.head && me.tail == other.tail; | return me.head == other.head && me.tail == other.tail; | |||
} | } | |||
template<class HT1, class TT1> | template<typename HT1, typename TT1> | |||
friend bool operator<(const cons<HT,TT>& me, const cons<HT1,TT1>& other ) { | friend bool operator<(const cons<HT,TT>& me, const cons<HT1,TT1>& other ) { | |||
return me.head < other.head || (!(other.head < me.head) && me.tail < other.tail); | return me.head < other.head || (!(other.head < me.head) && me.tail < other.tail); | |||
} | } | |||
template<class HT1, class TT1> | template<typename HT1, typename TT1> | |||
friend bool operator>(const cons<HT,TT>& me, const cons<HT1,TT1>& other ) { return other<me; } | friend bool operator>(const cons<HT,TT>& me, const cons<HT1,TT1>& other ) { return other<me; } | |||
template<class HT1, class TT1> | template<typename HT1, typename TT1> | |||
friend bool operator!=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe r) { return !(me==other); } | friend bool operator!=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe r) { return !(me==other); } | |||
template<class HT1, class TT1> | template<typename HT1, typename TT1> | |||
friend bool operator>=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe r) { return !(me<other); } | friend bool operator>=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe r) { return !(me<other); } | |||
template<class HT1, class TT1> | template<typename HT1, typename TT1> | |||
friend bool operator<=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe r) { return !(me>other); } | friend bool operator<=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe r) { return !(me>other); } | |||
}; // cons | }; // cons | |||
template <class HT> | template <typename HT> | |||
struct cons<HT,null_type> { | struct cons<HT,null_type> { | |||
typedef HT head_type; | typedef HT head_type; | |||
typedef null_type tail_type; | typedef null_type tail_type; | |||
static const int length = 1; | ||||
head_type head; | head_type head; | |||
static const int length = 1; | ||||
// default constructor | // default constructor | |||
cons() : head() { /*std::cout << "default constructor 1\n";*/ } | cons() : head() { /*std::cout << "default constructor 1\n";*/ } | |||
cons(const null_type&, const null_type&, const null_type&, const null_t ype&, const null_type& __TBB_CONST_NULL_REF_PACK) : head() { /*std::cout << "default constructor 2\n";*/ } | cons(const null_type&, const null_type&, const null_type&, const null_t ype&, const null_type& __TBB_CONST_NULL_REF_PACK) : head() { /*std::cout << "default constructor 2\n";*/ } | |||
// non-default constructor | // non-default constructor | |||
template<class T1> | template<typename T1> | |||
cons(T1& t1, const null_type&, const null_type&, const null_type&, cons t null_type& __TBB_CONST_NULL_REF_PACK) : head(t1) { /*std::cout << "non-de fault a1, t1== " << t1 << "\n";*/} | cons(T1& t1, const null_type&, const null_type&, const null_type&, cons t null_type& __TBB_CONST_NULL_REF_PACK) : head(t1) { /*std::cout << "non-de fault a1, t1== " << t1 << "\n";*/} | |||
cons(head_type& h, const null_type& = null_type() ) : head(h) { } | cons(head_type& h, const null_type& = null_type() ) : head(h) { } | |||
cons(const head_type& t0, const null_type&, const null_type&, const nul l_type&, const null_type& __TBB_CONST_NULL_REF_PACK) : head(t0) { } | cons(const head_type& t0, const null_type&, const null_type&, const nul l_type&, const null_type& __TBB_CONST_NULL_REF_PACK) : head(t0) { } | |||
// converting constructor | // converting constructor | |||
template<class HT1> | template<typename HT1> | |||
cons(HT1 h1, const null_type&, const null_type&, const null_type&, cons t null_type& __TBB_CONST_NULL_REF_PACK) : head(h1) { } | cons(HT1 h1, const null_type&, const null_type&, const null_type&, cons t null_type& __TBB_CONST_NULL_REF_PACK) : head(h1) { } | |||
// copy constructor | // copy constructor | |||
template<class HT1> | template<typename HT1> | |||
cons( const cons<HT1, null_type>& other) : head(other.head) { } | cons( const cons<HT1, null_type>& other) : head(other.head) { } | |||
// assignment operator | // assignment operator | |||
cons& operator=(const cons& other) { head = other.head; return *this; } | cons& operator=(const cons& other) { head = other.head; return *this; } | |||
friend bool operator==(const cons& me, const cons& other) { return me.h ead == other.head; } | friend bool operator==(const cons& me, const cons& other) { return me.h ead == other.head; } | |||
friend bool operator<(const cons& me, const cons& other) { return me.he ad < other.head; } | friend bool operator<(const cons& me, const cons& other) { return me.he ad < other.head; } | |||
friend bool operator>(const cons& me, const cons& other) { return other <me; } | friend bool operator>(const cons& me, const cons& other) { return other <me; } | |||
friend bool operator!=(const cons& me, const cons& other) {return !(me= =other); } | friend bool operator!=(const cons& me, const cons& other) {return !(me= =other); } | |||
friend bool operator<=(const cons& me, const cons& other) {return !(me> other); } | friend bool operator<=(const cons& me, const cons& other) {return !(me> other); } | |||
friend bool operator>=(const cons& me, const cons& other) {return !(me< other); } | friend bool operator>=(const cons& me, const cons& other) {return !(me< other); } | |||
template<class HT1> | template<typename HT1> | |||
friend bool operator==(const cons<HT,null_type>& me, const cons<HT1,nul l_type>& other) { | friend bool operator==(const cons<HT,null_type>& me, const cons<HT1,nul l_type>& other) { | |||
return me.head == other.head; | return me.head == other.head; | |||
} | } | |||
template<class HT1> | template<typename HT1> | |||
friend bool operator<(const cons<HT,null_type>& me, const cons<HT1,null _type>& other) { | friend bool operator<(const cons<HT,null_type>& me, const cons<HT1,null _type>& other) { | |||
return me.head < other.head; | return me.head < other.head; | |||
} | } | |||
template<class HT1> | template<typename HT1> | |||
friend bool operator>(const cons<HT,null_type>& me, const cons<HT1,null _type>& other) { return other<me; } | friend bool operator>(const cons<HT,null_type>& me, const cons<HT1,null _type>& other) { return other<me; } | |||
template<class HT1> | template<typename HT1> | |||
friend bool operator!=(const cons<HT,null_type>& me, const cons<HT1,nul l_type>& other) { return !(me==other); } | friend bool operator!=(const cons<HT,null_type>& me, const cons<HT1,nul l_type>& other) { return !(me==other); } | |||
template<class HT1> | template<typename HT1> | |||
friend bool operator<=(const cons<HT,null_type>& me, const cons<HT1,nul l_type>& other) { return !(me>other); } | friend bool operator<=(const cons<HT,null_type>& me, const cons<HT1,nul l_type>& other) { return !(me>other); } | |||
template<class HT1> | template<typename HT1> | |||
friend bool operator>=(const cons<HT,null_type>& me, const cons<HT1,nul l_type>& other) { return !(me<other); } | friend bool operator>=(const cons<HT,null_type>& me, const cons<HT1,nul l_type>& other) { return !(me<other); } | |||
}; // cons | }; // cons | |||
template <> | template <> | |||
struct cons<null_type,null_type> { typedef null_type tail_type; static cons t int length = 0; }; | struct cons<null_type,null_type> { typedef null_type tail_type; static cons t int length = 0; }; | |||
// wrapper for default constructor | // wrapper for default constructor | |||
template<class T> | template<typename T> | |||
inline const T wrap_dcons(T*) { return T(); } | inline const T wrap_dcons(T*) { return T(); } | |||
} // namespace internal | } // namespace internal | |||
// tuple definition | // tuple definition | |||
template<class T0, class T1, class T2, class T3, class T4 __TBB_CLASS_T_PAC K > | template<typename T0, typename T1, typename T2, typename T3, typename T4 __ TBB_TYPENAME_T_PACK > | |||
class tuple : public internal::tuple_traits<T0, T1, T2, T3, T4 __TBB_T_PACK >::U { | class tuple : public internal::tuple_traits<T0, T1, T2, T3, T4 __TBB_T_PACK >::U { | |||
// friends | // friends | |||
template <class T> friend class tuple_size; | template <typename T> friend class tuple_size; | |||
template<int N, class T> friend struct tuple_element; | template<int N, typename T> friend struct tuple_element; | |||
// stl components | // stl components | |||
typedef tuple<T0,T1,T2,T3,T4 __TBB_T_PACK > value_type; | typedef tuple<T0,T1,T2,T3,T4 __TBB_T_PACK > value_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 size_t size_type; | typedef size_t size_type; | |||
typedef typename internal::tuple_traits<T0,T1,T2,T3, T4 __TBB_T_PACK >: :U my_cons; | typedef typename internal::tuple_traits<T0,T1,T2,T3, T4 __TBB_T_PACK >: :U my_cons; | |||
public: | ||||
public: | ||||
tuple(const T0& t0=internal::wrap_dcons((T0*)NULL) | tuple(const T0& t0=internal::wrap_dcons((T0*)NULL) | |||
,const T1& t1=internal::wrap_dcons((T1*)NULL) | ,const T1& t1=internal::wrap_dcons((T1*)NULL) | |||
,const T2& t2=internal::wrap_dcons((T2*)NULL) | ,const T2& t2=internal::wrap_dcons((T2*)NULL) | |||
,const T3& t3=internal::wrap_dcons((T3*)NULL) | ,const T3& t3=internal::wrap_dcons((T3*)NULL) | |||
,const T4& t4=internal::wrap_dcons((T4*)NULL) | ,const T4& t4=internal::wrap_dcons((T4*)NULL) | |||
#if __TBB_VARIADIC_MAX >= 6 | #if __TBB_VARIADIC_MAX >= 6 | |||
,const T5& t5=internal::wrap_dcons((T5*)NULL) | ,const T5& t5=internal::wrap_dcons((T5*)NULL) | |||
#if __TBB_VARIADIC_MAX >= 7 | #if __TBB_VARIADIC_MAX >= 7 | |||
,const T6& t6=internal::wrap_dcons((T6*)NULL) | ,const T6& t6=internal::wrap_dcons((T6*)NULL) | |||
#if __TBB_VARIADIC_MAX >= 8 | #if __TBB_VARIADIC_MAX >= 8 | |||
skipping to change at line 387 | skipping to change at line 392 | |||
#if __TBB_VARIADIC_MAX >= 9 | #if __TBB_VARIADIC_MAX >= 9 | |||
,const T8& t8=internal::wrap_dcons((T8*)NULL) | ,const T8& t8=internal::wrap_dcons((T8*)NULL) | |||
#if __TBB_VARIADIC_MAX >= 10 | #if __TBB_VARIADIC_MAX >= 10 | |||
,const T9& t9=internal::wrap_dcons((T9*)NULL) | ,const T9& t9=internal::wrap_dcons((T9*)NULL) | |||
#endif | #endif | |||
#endif | #endif | |||
#endif | #endif | |||
#endif | #endif | |||
#endif | #endif | |||
) : | ) : | |||
internal::tuple_traits<T0,T1,T2,T3,T4 __TBB_T_PACK >::U(t0,t1,t2,t3 ,t4 __TBB_T_PARAM_LIST_PACK) { } | my_cons(t0,t1,t2,t3,t4 __TBB_T_PARAM_LIST_PACK) { } | |||
template<int N> | template<int N> | |||
struct internal_tuple_element { | struct internal_tuple_element { | |||
typedef typename internal::component<N,my_cons>::type type; | typedef typename internal::component<N,my_cons>::type type; | |||
}; | }; | |||
template<int N> | template<int N> | |||
typename internal_tuple_element<N>::type& get() { return internal::get_ helper<N>::get(*this); } | typename internal_tuple_element<N>::type& get() { return internal::get_ helper<N>::get(*this); } | |||
template<int N> | template<int N> | |||
typename internal_tuple_element<N>::type const& get() const { return in ternal::get_helper<N>::get(*this); } | typename internal_tuple_element<N>::type const& get() const { return in ternal::get_helper<N>::get(*this); } | |||
template<class U1, class U2> | template<typename U1, typename U2> | |||
tuple& operator=(const internal::cons<U1,U2>& other) { | tuple& operator=(const internal::cons<U1,U2>& other) { | |||
my_cons::operator=(other); | my_cons::operator=(other); | |||
return *this; | return *this; | |||
} | } | |||
template<class U1, class U2> | template<typename U1, typename U2> | |||
tuple& operator=(const std::pair<U1,U2>& other) { | tuple& operator=(const std::pair<U1,U2>& other) { | |||
// __TBB_ASSERT(tuple_size<value_type>::value == 2, "Invalid size f or pair to tuple assignment"); | // __TBB_ASSERT(tuple_size<value_type>::value == 2, "Invalid size f or pair to tuple assignment"); | |||
this->head = other.first; | this->head = other.first; | |||
this->tail.head = other.second; | this->tail.head = other.second; | |||
return *this; | return *this; | |||
} | } | |||
friend bool operator==(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)==(other);} | friend bool operator==(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)==(other);} | |||
friend bool operator<(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)<(other);} | friend bool operator<(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)<(other);} | |||
friend bool operator>(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)>(other);} | friend bool operator>(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)>(other);} | |||
friend bool operator!=(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)!=(other);} | friend bool operator!=(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)!=(other);} | |||
friend bool operator>=(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)>=(other);} | friend bool operator>=(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)>=(other);} | |||
friend bool operator<=(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)<=(other);} | friend bool operator<=(const tuple& me, const tuple& other) {return sta tic_cast<const my_cons &>(me)<=(other);} | |||
template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | ||||
_PACK > | ||||
friend bool operator==(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TB | ||||
B_U_PACK >& other) { | ||||
return static_cast<const my_cons &>(me)==(other); | ||||
} | ||||
template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | ||||
_PACK > | ||||
friend bool operator<(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TBB | ||||
_U_PACK >& other) { | ||||
return static_cast<const my_cons &>(me)<(other); | ||||
} | ||||
template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | ||||
_PACK > | ||||
friend bool operator>(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TBB | ||||
_U_PACK >& other) { | ||||
return static_cast<const my_cons &>(me)>(other); | ||||
} | ||||
template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | ||||
_PACK > | ||||
friend bool operator!=(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TB | ||||
B_U_PACK >& other) { | ||||
return static_cast<const my_cons &>(me)!=(other); | ||||
} | ||||
template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | ||||
_PACK > | ||||
friend bool operator>=(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TB | ||||
B_U_PACK >& other) { | ||||
return static_cast<const my_cons &>(me)>=(other); | ||||
} | ||||
template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | ||||
_PACK > | ||||
friend bool operator<=(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TB | ||||
B_U_PACK >& other) { | ||||
return static_cast<const my_cons &>(me)<=(other); | ||||
} | ||||
}; // tuple | }; // tuple | |||
// empty tuple | // empty tuple | |||
template<> | template<> | |||
class tuple<null_type, null_type, null_type, null_type, null_type __TBB_NUL L_TYPE_PACK > : public null_type { | class tuple<null_type, null_type, null_type, null_type, null_type __TBB_NUL L_TYPE_PACK > : public null_type { | |||
typedef null_type inherited; | ||||
}; | }; | |||
// helper classes | // helper classes | |||
template < class T> | template < typename T> | |||
class tuple_size { | class tuple_size { | |||
public: | public: | |||
static const size_t value = 1 + tuple_size<typename T::tail_type>::valu e; | static const size_t value = 1 + tuple_size<typename T::tail_type>::valu e; | |||
}; | }; | |||
template <> | template <> | |||
class tuple_size<tuple<> > { | class tuple_size<tuple<> > { | |||
public: | public: | |||
static const size_t value = 0; | static const size_t value = 0; | |||
}; | }; | |||
template <> | template <> | |||
class tuple_size<null_type> { | class tuple_size<null_type> { | |||
public: | public: | |||
static const size_t value = 0; | static const size_t value = 0; | |||
}; | }; | |||
template<int N, class T> | template<int N, typename T> | |||
struct tuple_element { | struct tuple_element { | |||
typedef typename internal::component<N, typename T::my_cons>::type type ; | typedef typename internal::component<N, typename T::my_cons>::type type ; | |||
}; | }; | |||
template<int N, class T0, class T1, class T2, class T3, class T4 __TBB_CLAS S_T_PACK > | template<int N, typename T0, typename T1, typename T2, typename T3, typenam e T4 __TBB_TYPENAME_T_PACK > | |||
inline static typename tuple_element<N,tuple<T0,T1,T2,T3,T4 __TBB_T_PACK > >::type& | inline static typename tuple_element<N,tuple<T0,T1,T2,T3,T4 __TBB_T_PACK > >::type& | |||
get(tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >& t) { return t.get<N>(); } | get(tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >& t) { return internal::get_help er<N>::get(t); } | |||
template<int N, class T0, class T1, class T2, class T3, class T4 __TBB_CLAS S_T_PACK > | template<int N, typename T0, typename T1, typename T2, typename T3, typenam e T4 __TBB_TYPENAME_T_PACK > | |||
inline static typename tuple_element<N,tuple<T0,T1,T2,T3,T4 __TBB_T_PACK > >::type const& | inline static typename tuple_element<N,tuple<T0,T1,T2,T3,T4 __TBB_T_PACK > >::type const& | |||
get(const tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >& t) { return t.get<N>(); } | get(const tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >& t) { return internal::ge t_helper<N>::get(t); } | |||
} // interface5 | } // interface5 | |||
} // tbb | } // tbb | |||
#if !__TBB_CPP11_TUPLE_PRESENT | #if !__TBB_CPP11_TUPLE_PRESENT | |||
namespace std { | namespace tbb { | |||
using tbb::interface5::tuple; | namespace flow { | |||
using tbb::interface5::tuple_size; | using tbb::interface5::tuple; | |||
using tbb::interface5::tuple_element; | using tbb::interface5::tuple_size; | |||
using tbb::interface5::get; | using tbb::interface5::tuple_element; | |||
using tbb::interface5::get; | ||||
} | ||||
} | } | |||
#endif | #endif | |||
#undef __TBB_T_PACK | #undef __TBB_T_PACK | |||
#undef __TBB_U_PACK | #undef __TBB_U_PACK | |||
#undef __TBB_CLASS_T_PACK | #undef __TBB_TYPENAME_T_PACK | |||
#undef __TBB_CLASS_U_PACK | #undef __TBB_TYPENAME_U_PACK | |||
#undef __TBB_NULL_TYPE_PACK | #undef __TBB_NULL_TYPE_PACK | |||
#undef __TBB_REF_T_PARAM_PACK | #undef __TBB_REF_T_PARAM_PACK | |||
#undef __TBB_CONST_REF_T_PARAM_PACK | #undef __TBB_CONST_REF_T_PARAM_PACK | |||
#undef __TBB_T_PARAM_LIST_PACK | #undef __TBB_T_PARAM_LIST_PACK | |||
#undef __TBB_CONST_NULL_REF_PACK | #undef __TBB_CONST_NULL_REF_PACK | |||
#endif /* __TBB_tuple_H */ | #endif /* __TBB_tuple_H */ | |||
End of changes. 66 change blocks. | ||||
121 lines changed or deleted | 87 lines changed or added | |||
windows_api.h | windows_api.h | |||
---|---|---|---|---|
skipping to change at line 46 | skipping to change at line 46 | |||
#define NONET | #define NONET | |||
#define NOD3D | #define NOD3D | |||
#include <xtl.h> | #include <xtl.h> | |||
#else // Assume "usual" Windows | #else // Assume "usual" Windows | |||
#include <windows.h> | #include <windows.h> | |||
#endif // _XBOX | #endif // _XBOX | |||
#if !defined(_WIN32_WINNT) | #if _WIN32_WINNT < 0x0600 | |||
// 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 it fails to compile by VS2005. | |||
extern "C" BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION ); | #if !defined(WINBASEAPI) || (_WIN32_WINNT < 0x0501 && _MSC_VER == 1400) | |||
#define __TBB_WINBASEAPI extern "C" | ||||
#else | ||||
#define __TBB_WINBASEAPI WINBASEAPI | ||||
#endif | ||||
__TBB_WINBASEAPI BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION ); | ||||
__TBB_WINBASEAPI BOOL WINAPI InitializeCriticalSectionAndSpinCount( LPCRITI | ||||
CAL_SECTION, DWORD ); | ||||
// Overloading WINBASEAPI macro and using local functions missing in Window | ||||
s XP/2003 | ||||
#define InitializeCriticalSectionEx inlineInitializeCriticalSectionEx | ||||
#define CreateSemaphoreEx inlineCreateSemaphoreEx | ||||
#define CreateEventEx inlineCreateEventEx | ||||
inline BOOL WINAPI inlineInitializeCriticalSectionEx( LPCRITICAL_SECTION lp | ||||
CriticalSection, DWORD dwSpinCount, DWORD ) | ||||
{ | ||||
return InitializeCriticalSectionAndSpinCount( lpCriticalSection, dwSpin | ||||
Count ); | ||||
} | ||||
inline HANDLE WINAPI inlineCreateSemaphoreEx( LPSECURITY_ATTRIBUTES lpSemap | ||||
horeAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName, DWO | ||||
RD, DWORD ) | ||||
{ | ||||
return CreateSemaphore( lpSemaphoreAttributes, lInitialCount, lMaximumC | ||||
ount, lpName ); | ||||
} | ||||
inline HANDLE WINAPI inlineCreateEventEx( LPSECURITY_ATTRIBUTES lpEventAttr | ||||
ibutes, LPCTSTR lpName, DWORD dwFlags, DWORD ) | ||||
{ | ||||
BOOL manual_reset = dwFlags&0x00000001 ? TRUE : FALSE; // CREATE_EVENT_ | ||||
MANUAL_RESET | ||||
BOOL initial_set = dwFlags&0x00000002 ? TRUE : FALSE; // CREATE_EVENT_ | ||||
INITIAL_SET | ||||
return CreateEvent( lpEventAttributes, manual_reset, initial_set, lpNam | ||||
e ); | ||||
} | ||||
#endif | ||||
#if defined(RTL_SRWLOCK_INIT) | ||||
#ifndef __TBB_USE_SRWLOCK | ||||
// TODO: turn it on when bug 1952 will be fixed | ||||
#define __TBB_USE_SRWLOCK 0 | ||||
#endif | ||||
#endif | #endif | |||
#else | #else | |||
#error tbb/machine/windows_api.h should only be used for Windows based plat forms | #error tbb/machine/windows_api.h should only be used for Windows based plat forms | |||
#endif // _WIN32 || _WIN64 | #endif // _WIN32 || _WIN64 | |||
#endif // __TBB_machine_windows_api_H | #endif // __TBB_machine_windows_api_H | |||
End of changes. 2 change blocks. | ||||
3 lines changed or deleted | 45 lines changed or added | |||
windows_ia32.h | windows_ia32.h | |||
---|---|---|---|---|
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. | |||
*/ | */ | |||
#if !defined(__TBB_machine_H) || defined(__TBB_machine_windows_ia32_H) | #if !defined(__TBB_machine_H) || defined(__TBB_machine_windows_ia32_H) | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
#define __TBB_machine_windows_ia32_H | #define __TBB_machine_windows_ia32_H | |||
#include "msvc_ia32_common.h" | ||||
#define __TBB_WORDSIZE 4 | #define __TBB_WORDSIZE 4 | |||
#define __TBB_BIG_ENDIAN 0 | #define __TBB_BIG_ENDIAN 0 | |||
#if __INTEL_COMPILER | #if __INTEL_COMPILER && (__INTEL_COMPILER < 1100) | |||
#define __TBB_compiler_fence() __asm { __asm nop } | #define __TBB_compiler_fence() __asm { __asm nop } | |||
#elif _MSC_VER >= 1300 | #define __TBB_full_memory_fence() __asm { __asm mfence } | |||
extern "C" void _ReadWriteBarrier(); | #elif _MSC_VER >= 1300 || __INTEL_COMPILER | |||
#pragma intrinsic(_ReadWriteBarrier) | #pragma intrinsic(_ReadWriteBarrier) | |||
#define __TBB_compiler_fence() _ReadWriteBarrier() | #pragma intrinsic(_mm_mfence) | |||
#define __TBB_compiler_fence() _ReadWriteBarrier() | ||||
#define __TBB_full_memory_fence() _mm_mfence() | ||||
#else | #else | |||
#error Unsupported compiler - need to define __TBB_{control,acquire,rel ease}_consistency_helper to support it | #error Unsupported compiler - need to define __TBB_{control,acquire,rel ease}_consistency_helper to support it | |||
#endif | #endif | |||
#define __TBB_control_consistency_helper() __TBB_compiler_fence() | #define __TBB_control_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_acquire_consistency_helper() __TBB_compiler_fence() | #define __TBB_acquire_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_release_consistency_helper() __TBB_compiler_fence() | #define __TBB_release_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_full_memory_fence() __asm { __asm mfence } | ||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |||
// 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: 4244 4267) | #pragma warning (disable: 4244 4267) | |||
#endif | #endif | |||
extern "C" { | extern "C" { | |||
__int64 __TBB_EXPORTED_FUNC __TBB_machine_cmpswp8 (volatile void *ptr, __int64 value, __int64 comparand ); | __int64 __TBB_EXPORTED_FUNC __TBB_machine_cmpswp8 (volatile void *ptr, __int64 value, __int64 comparand ); | |||
__int64 __TBB_EXPORTED_FUNC __TBB_machine_fetchadd8 (volatile void *ptr , __int64 addend ); | __int64 __TBB_EXPORTED_FUNC __TBB_machine_fetchadd8 (volatile void *ptr , __int64 addend ); | |||
__int64 __TBB_EXPORTED_FUNC __TBB_machine_fetchstore8 (volatile void *p tr, __int64 value ); | __int64 __TBB_EXPORTED_FUNC __TBB_machine_fetchstore8 (volatile void *p tr, __int64 value ); | |||
void __TBB_EXPORTED_FUNC __TBB_machine_store8 (volatile void *ptr, __in t64 value ); | void __TBB_EXPORTED_FUNC __TBB_machine_store8 (volatile void *ptr, __in t64 value ); | |||
__int64 __TBB_EXPORTED_FUNC __TBB_machine_load8 (const volatile void *p tr); | __int64 __TBB_EXPORTED_FUNC __TBB_machine_load8 (const volatile void *p tr); | |||
} | } | |||
//TODO: use _InterlockedXXX intrinsics as they available since VC 2005 | ||||
#define __TBB_MACHINE_DEFINE_ATOMICS(S,T,U,A,C) \ | #define __TBB_MACHINE_DEFINE_ATOMICS(S,T,U,A,C) \ | |||
static inline T __TBB_machine_cmpswp##S ( volatile void * ptr, U value, U c omparand ) { \ | static inline T __TBB_machine_cmpswp##S ( volatile void * ptr, U value, U c omparand ) { \ | |||
T result; \ | T result; \ | |||
volatile T *p = (T *)ptr; \ | volatile T *p = (T *)ptr; \ | |||
__asm \ | __asm \ | |||
{ \ | { \ | |||
__asm mov edx, p \ | __asm mov edx, p \ | |||
__asm mov C , value \ | __asm mov C , value \ | |||
__asm mov A , comparand \ | __asm mov A , comparand \ | |||
__asm lock cmpxchg [edx], C \ | __asm lock cmpxchg [edx], C \ | |||
skipping to change at line 114 | skipping to change at line 118 | |||
} \ | } \ | |||
return result; \ | return result; \ | |||
} | } | |||
__TBB_MACHINE_DEFINE_ATOMICS(1, __int8, __int8, al, cl) | __TBB_MACHINE_DEFINE_ATOMICS(1, __int8, __int8, al, cl) | |||
__TBB_MACHINE_DEFINE_ATOMICS(2, __int16, __int16, ax, cx) | __TBB_MACHINE_DEFINE_ATOMICS(2, __int16, __int16, ax, cx) | |||
__TBB_MACHINE_DEFINE_ATOMICS(4, ptrdiff_t, ptrdiff_t, eax, ecx) | __TBB_MACHINE_DEFINE_ATOMICS(4, ptrdiff_t, ptrdiff_t, eax, ecx) | |||
#undef __TBB_MACHINE_DEFINE_ATOMICS | #undef __TBB_MACHINE_DEFINE_ATOMICS | |||
#if ( _MSC_VER>=1400 && !defined(__INTEL_COMPILER) ) || (__INTEL_COMPILER> | ||||
=1200) | ||||
// MSVC did not have this intrinsic prior to VC8. | ||||
// ICL 11.1 fails to compile a TBB example if __TBB_Log2 uses the intrinsic | ||||
. | ||||
#define __TBB_LOG2_USE_BSR_INTRINSIC 1 | ||||
extern "C" unsigned char _BitScanReverse( unsigned long* i, unsigned long w | ||||
); | ||||
#pragma intrinsic(_BitScanReverse) | ||||
#endif | ||||
static inline intptr_t __TBB_machine_lg( uintptr_t i ) { | ||||
unsigned long j; | ||||
#if __TBB_LOG2_USE_BSR_INTRINSIC | ||||
_BitScanReverse( &j, i ); | ||||
#else | ||||
__asm | ||||
{ | ||||
bsr eax, i | ||||
mov j, eax | ||||
} | ||||
#endif | ||||
return j; | ||||
} | ||||
static inline void __TBB_machine_OR( volatile void *operand, __int32 addend ) { | static inline void __TBB_machine_OR( volatile void *operand, __int32 addend ) { | |||
__asm | __asm | |||
{ | { | |||
mov eax, addend | mov eax, addend | |||
mov edx, [operand] | mov edx, [operand] | |||
lock or [edx], eax | lock or [edx], eax | |||
} | } | |||
} | } | |||
static inline void __TBB_machine_AND( volatile void *operand, __int32 adden d ) { | static inline void __TBB_machine_AND( volatile void *operand, __int32 adden d ) { | |||
__asm | __asm | |||
{ | { | |||
mov eax, addend | mov eax, addend | |||
mov edx, [operand] | mov edx, [operand] | |||
lock and [edx], eax | lock and [edx], eax | |||
} | } | |||
} | } | |||
static inline void __TBB_machine_pause (__int32 delay ) { | ||||
_asm | ||||
{ | ||||
mov eax, delay | ||||
__TBB_L1: | ||||
pause | ||||
add eax, -1 | ||||
jne __TBB_L1 | ||||
} | ||||
return; | ||||
} | ||||
#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) | |||
//TODO: Check if it possible and profitable for IA-32 on (Linux and Windows ) | //TODO: Check if it possible and profitable for IA-32 on (Linux and Windows ) | |||
//to use of 64-bit load/store via floating point registers together with fu ll fence | //to use of 64-bit load/store via floating point registers together with fu ll fence | |||
//for sequentially consistent load/store, instead of CAS. | //for sequentially consistent load/store, instead of CAS. | |||
#define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | #define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | |||
#define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1 | #define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1 | |||
// Definition of other functions | ||||
extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); | ||||
#define __TBB_Yield() SwitchToThread() | ||||
#define __TBB_Pause(V) __TBB_machine_pause(V) | ||||
#define __TBB_Log2(V) __TBB_machine_lg(V) | ||||
#if defined(_MSC_VER)&&_MSC_VER<1400 | ||||
static inline void* __TBB_machine_get_current_teb () { | ||||
void* pteb; | ||||
__asm mov eax, fs:[0x18] | ||||
__asm mov pteb, eax | ||||
return pteb; | ||||
} | ||||
#endif | ||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |||
#pragma warning (pop) | #pragma warning (pop) | |||
#endif // warnings 4244, 4267 are back | #endif // warnings 4244, 4267 are back | |||
// API to retrieve/update FPU control setting | ||||
#define __TBB_CPU_CTL_ENV_PRESENT 1 | ||||
struct __TBB_cpu_ctl_env_t { | ||||
int mxcsr; | ||||
short x87cw; | ||||
}; | ||||
inline void __TBB_get_cpu_ctl_env ( __TBB_cpu_ctl_env_t* ctl ) { | ||||
__asm { | ||||
__asm mov eax, ctl | ||||
__asm stmxcsr [eax] | ||||
__asm fstcw [eax+4] | ||||
} | ||||
} | ||||
inline void __TBB_set_cpu_ctl_env ( const __TBB_cpu_ctl_env_t* ctl ) { | ||||
__asm { | ||||
__asm mov eax, ctl | ||||
__asm ldmxcsr [eax] | ||||
__asm fldcw [eax+4] | ||||
} | ||||
} | ||||
End of changes. 9 change blocks. | ||||
58 lines changed or deleted | 10 lines changed or added | |||
windows_intel64.h | windows_intel64.h | |||
---|---|---|---|---|
skipping to change at line 39 | skipping to change at line 39 | |||
#if !defined(__TBB_machine_H) || defined(__TBB_machine_windows_intel64_H) | #if !defined(__TBB_machine_H) || defined(__TBB_machine_windows_intel64_H) | |||
#error Do not #include this internal file directly; use public TBB headers instead. | #error Do not #include this internal file directly; use public TBB headers instead. | |||
#endif | #endif | |||
#define __TBB_machine_windows_intel64_H | #define __TBB_machine_windows_intel64_H | |||
#define __TBB_WORDSIZE 8 | #define __TBB_WORDSIZE 8 | |||
#define __TBB_BIG_ENDIAN 0 | #define __TBB_BIG_ENDIAN 0 | |||
#include <intrin.h> | #include <intrin.h> | |||
#include "msvc_ia32_common.h" | ||||
//TODO: Use _InterlockedXXX16 intrinsics for 2 byte operations | ||||
#if !__INTEL_COMPILER | #if !__INTEL_COMPILER | |||
#pragma intrinsic(_InterlockedOr64) | #pragma intrinsic(_InterlockedOr64) | |||
#pragma intrinsic(_InterlockedAnd64) | #pragma intrinsic(_InterlockedAnd64) | |||
#pragma intrinsic(_InterlockedCompareExchange) | #pragma intrinsic(_InterlockedCompareExchange) | |||
#pragma intrinsic(_InterlockedCompareExchange64) | #pragma intrinsic(_InterlockedCompareExchange64) | |||
#pragma intrinsic(_InterlockedExchangeAdd) | #pragma intrinsic(_InterlockedExchangeAdd) | |||
#pragma intrinsic(_InterlockedExchangeAdd64) | #pragma intrinsic(_InterlockedExchangeAdd64) | |||
#pragma intrinsic(_InterlockedExchange) | #pragma intrinsic(_InterlockedExchange) | |||
#pragma intrinsic(_InterlockedExchange64) | #pragma intrinsic(_InterlockedExchange64) | |||
#endif /* !defined(__INTEL_COMPILER) */ | #endif /* !(__INTEL_COMPILER) */ | |||
#if __INTEL_COMPILER | #if __INTEL_COMPILER && (__INTEL_COMPILER < 1100) | |||
#define __TBB_compiler_fence() __asm { __asm nop } | #define __TBB_compiler_fence() __asm { __asm nop } | |||
#define __TBB_full_memory_fence() __asm { __asm mfence } | #define __TBB_full_memory_fence() __asm { __asm mfence } | |||
#elif _MSC_VER >= 1300 | #elif _MSC_VER >= 1300 || __INTEL_COMPILER | |||
extern "C" void _ReadWriteBarrier(); | ||||
#pragma intrinsic(_ReadWriteBarrier) | #pragma intrinsic(_ReadWriteBarrier) | |||
#pragma intrinsic(_mm_mfence) | #pragma intrinsic(_mm_mfence) | |||
#pragma intrinsic(_mm_pause) | ||||
#define __TBB_compiler_fence() _ReadWriteBarrier() | #define __TBB_compiler_fence() _ReadWriteBarrier() | |||
#define __TBB_full_memory_fence() _mm_mfence() | #define __TBB_full_memory_fence() _mm_mfence() | |||
#endif | #endif | |||
#define __TBB_control_consistency_helper() __TBB_compiler_fence() | #define __TBB_control_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_acquire_consistency_helper() __TBB_compiler_fence() | #define __TBB_acquire_consistency_helper() __TBB_compiler_fence() | |||
#define __TBB_release_consistency_helper() __TBB_compiler_fence() | #define __TBB_release_consistency_helper() __TBB_compiler_fence() | |||
// ATTENTION: if you ever change argument types in machine-specific primiti ves, | // ATTENTION: if you ever change argument types in machine-specific primiti ves, | |||
// please take care of atomic_word<> specializations in tbb/atomic.h | // please take care of atomic_word<> specializations in tbb/atomic.h | |||
skipping to change at line 98 | skipping to change at line 98 | |||
inline __int64 __TBB_machine_cmpswp8 (volatile void *ptr, __int64 value, __ int64 comparand ) { | inline __int64 __TBB_machine_cmpswp8 (volatile void *ptr, __int64 value, __ int64 comparand ) { | |||
return _InterlockedCompareExchange64( (__int64*)ptr, value, comparand ) ; | return _InterlockedCompareExchange64( (__int64*)ptr, value, comparand ) ; | |||
} | } | |||
inline __int64 __TBB_machine_fetchadd8 (volatile void *ptr, __int64 addend ) { | inline __int64 __TBB_machine_fetchadd8 (volatile void *ptr, __int64 addend ) { | |||
return _InterlockedExchangeAdd64( (__int64*)ptr, addend ); | return _InterlockedExchangeAdd64( (__int64*)ptr, addend ); | |||
} | } | |||
inline __int64 __TBB_machine_fetchstore8 (volatile void *ptr, __int64 value ) { | inline __int64 __TBB_machine_fetchstore8 (volatile void *ptr, __int64 value ) { | |||
return _InterlockedExchange64( (__int64*)ptr, value ); | return _InterlockedExchange64( (__int64*)ptr, value ); | |||
} | } | |||
inline void __TBB_machine_pause_v6 (__int32 delay ) { | ||||
for (;delay>0; --delay ) | ||||
_mm_pause(); | ||||
} | ||||
#define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | #define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | |||
#define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_RELAXED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1 | #define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1 | |||
extern "C" unsigned char _BitScanReverse64( unsigned long* i, unsigned __in | ||||
t64 w ); | ||||
#pragma intrinsic(_BitScanReverse64) | ||||
inline __int64 __TBB_machine_lg( unsigned __int64 i ) { | ||||
unsigned long j; | ||||
_BitScanReverse64( &j, i ); | ||||
return j; | ||||
} | ||||
inline void __TBB_machine_OR( volatile void *operand, intptr_t addend ) { | inline void __TBB_machine_OR( volatile void *operand, intptr_t addend ) { | |||
_InterlockedOr64((__int64*)operand, addend); | _InterlockedOr64((__int64*)operand, addend); | |||
} | } | |||
inline void __TBB_machine_AND( volatile void *operand, intptr_t addend ) { | inline void __TBB_machine_AND( volatile void *operand, intptr_t addend ) { | |||
_InterlockedAnd64((__int64*)operand, addend); | _InterlockedAnd64((__int64*)operand, addend); | |||
} | } | |||
#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) | |||
extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); | ||||
#define __TBB_Yield() SwitchToThread() | ||||
#define __TBB_Pause(V) __TBB_machine_pause_v6(V) | ||||
#define __TBB_Log2(V) __TBB_machine_lg(V) | ||||
// API to retrieve/update FPU control setting | ||||
#define __TBB_CPU_CTL_ENV_PRESENT 1 | ||||
struct __TBB_cpu_ctl_env_t { | ||||
int mxcsr; | ||||
short x87cw; | ||||
}; | ||||
extern "C" { | ||||
void __TBB_EXPORTED_FUNC __TBB_get_cpu_ctl_env ( __TBB_cpu_ctl_env_t* ) | ||||
; | ||||
void __TBB_EXPORTED_FUNC __TBB_set_cpu_ctl_env ( const __TBB_cpu_ctl_en | ||||
v_t* ); | ||||
} | ||||
End of changes. 9 change blocks. | ||||
20 lines changed or deleted | 5 lines changed or added | |||