00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __TBB_pipeline_H
00030 #define __TBB_pipeline_H
00031
00032 #include "atomic.h"
00033 #include "task.h"
00034 #include "tbb_allocator.h"
00035 #include <cstddef>
00036
00037 #if !TBB_IMPLEMENT_CPP0X
00038 #include <type_traits>
00039 #endif
00040
00041 namespace tbb {
00042
00043 class pipeline;
00044 class filter;
00045
00047 namespace internal {
00048
00049
00050 #define __TBB_PIPELINE_VERSION(x) (unsigned char)(x-2)<<1
00051
00052 typedef unsigned long Token;
00053 typedef long tokendiff_t;
00054 class stage_task;
00055 class input_buffer;
00056 class pipeline_root_task;
00057 class pipeline_cleaner;
00058
00059 }
00060
00061 namespace interface6 {
00062 template<typename T, typename U> class filter_t;
00063
00064 namespace internal {
00065 class pipeline_proxy;
00066 }
00067 }
00068
00070
00072
00073 class filter: internal::no_copy {
00074 private:
00076 static filter* not_in_pipeline() {return reinterpret_cast<filter*>(intptr_t(-1));}
00077 protected:
00079 static const unsigned char filter_is_serial = 0x1;
00080
00082
00084 static const unsigned char filter_is_out_of_order = 0x1<<4;
00085
00087 static const unsigned char filter_is_bound = 0x1<<5;
00088
00090 static const unsigned char filter_may_emit_null = 0x1<<6;
00091
00093 static const unsigned char exact_exception_propagation =
00094 #if TBB_USE_CAPTURED_EXCEPTION
00095 0x0;
00096 #else
00097 0x1<<7;
00098 #endif
00099
00100 static const unsigned char current_version = __TBB_PIPELINE_VERSION(5);
00101 static const unsigned char version_mask = 0x7<<1;
00102 public:
00103 enum mode {
00105 parallel = current_version | filter_is_out_of_order,
00107 serial_in_order = current_version | filter_is_serial,
00109 serial_out_of_order = current_version | filter_is_serial | filter_is_out_of_order,
00111 serial = serial_in_order
00112 };
00113 protected:
00114 filter( bool is_serial_ ) :
00115 next_filter_in_pipeline(not_in_pipeline()),
00116 my_input_buffer(NULL),
00117 my_filter_mode(static_cast<unsigned char>((is_serial_ ? serial : parallel) | exact_exception_propagation)),
00118 prev_filter_in_pipeline(not_in_pipeline()),
00119 my_pipeline(NULL),
00120 next_segment(NULL)
00121 {}
00122
00123 filter( mode filter_mode ) :
00124 next_filter_in_pipeline(not_in_pipeline()),
00125 my_input_buffer(NULL),
00126 my_filter_mode(static_cast<unsigned char>(filter_mode | exact_exception_propagation)),
00127 prev_filter_in_pipeline(not_in_pipeline()),
00128 my_pipeline(NULL),
00129 next_segment(NULL)
00130 {}
00131
00132
00133 void __TBB_EXPORTED_METHOD set_end_of_input();
00134
00135 public:
00137 bool is_serial() const {
00138 return bool( my_filter_mode & filter_is_serial );
00139 }
00140
00142 bool is_ordered() const {
00143 return (my_filter_mode & (filter_is_out_of_order|filter_is_serial))==filter_is_serial;
00144 }
00145
00147 bool is_bound() const {
00148 return ( my_filter_mode & filter_is_bound )==filter_is_bound;
00149 }
00150
00152 bool object_may_be_null() {
00153 return ( my_filter_mode & filter_may_emit_null ) == filter_may_emit_null;
00154 }
00155
00157
00158 virtual void* operator()( void* item ) = 0;
00159
00161
00162 virtual __TBB_EXPORTED_METHOD ~filter();
00163
00164 #if __TBB_TASK_GROUP_CONTEXT
00166
00168 virtual void finalize( void* ) {};
00169 #endif
00170
00171 private:
00173 filter* next_filter_in_pipeline;
00174
00176
00177
00178 bool has_more_work();
00179
00181
00182 internal::input_buffer* my_input_buffer;
00183
00184 friend class internal::stage_task;
00185 friend class internal::pipeline_root_task;
00186 friend class pipeline;
00187 friend class thread_bound_filter;
00188
00190 const unsigned char my_filter_mode;
00191
00193 filter* prev_filter_in_pipeline;
00194
00196 pipeline* my_pipeline;
00197
00199
00200 filter* next_segment;
00201 };
00202
00204
00205 class thread_bound_filter: public filter {
00206 public:
00207 enum result_type {
00208
00209 success,
00210
00211 item_not_available,
00212
00213 end_of_stream
00214 };
00215 protected:
00216 thread_bound_filter(mode filter_mode):
00217 filter(static_cast<mode>(filter_mode | filter::filter_is_bound))
00218 {}
00219 public:
00221
00226 result_type __TBB_EXPORTED_METHOD try_process_item();
00227
00229
00233 result_type __TBB_EXPORTED_METHOD process_item();
00234
00235 private:
00237 result_type internal_process_item(bool is_blocking);
00238 };
00239
00241
00242 class pipeline {
00243 public:
00245 __TBB_EXPORTED_METHOD pipeline();
00246
00249 virtual __TBB_EXPORTED_METHOD ~pipeline();
00250
00252 void __TBB_EXPORTED_METHOD add_filter( filter& filter_ );
00253
00255 void __TBB_EXPORTED_METHOD run( size_t max_number_of_live_tokens );
00256
00257 #if __TBB_TASK_GROUP_CONTEXT
00259 void __TBB_EXPORTED_METHOD run( size_t max_number_of_live_tokens, tbb::task_group_context& context );
00260 #endif
00261
00263 void __TBB_EXPORTED_METHOD clear();
00264
00265 private:
00266 friend class internal::stage_task;
00267 friend class internal::pipeline_root_task;
00268 friend class filter;
00269 friend class thread_bound_filter;
00270 friend class internal::pipeline_cleaner;
00271 friend class tbb::interface6::internal::pipeline_proxy;
00272
00274 filter* filter_list;
00275
00277 filter* filter_end;
00278
00280 task* end_counter;
00281
00283 atomic<internal::Token> input_tokens;
00284
00286 atomic<internal::Token> token_counter;
00287
00289 bool end_of_input;
00290
00292 bool has_thread_bound_filters;
00293
00295 void remove_filter( filter& filter_ );
00296
00298 void __TBB_EXPORTED_METHOD inject_token( task& self );
00299
00300 #if __TBB_TASK_GROUP_CONTEXT
00302 void clear_filters();
00303 #endif
00304 };
00305
00306
00307
00308
00309
00310 namespace interface6 {
00311
00312 namespace internal {
00313 template<typename T, typename U, typename Body> class concrete_filter;
00314 }
00315
00317 class flow_control {
00318 bool is_pipeline_stopped;
00319 flow_control() { is_pipeline_stopped = false; }
00320 template<typename T, typename U, typename Body> friend class internal::concrete_filter;
00321 public:
00322 void stop() { is_pipeline_stopped = true; }
00323 };
00324
00326 namespace internal {
00327
00328 template<typename T> struct tbb_large_object {enum { value = sizeof(T) > sizeof(void *) }; };
00329
00330 #if TBB_IMPLEMENT_CPP0X
00331
00332
00333 template<typename T> struct tbb_trivially_copyable { enum { value = false }; };
00334 template<typename T> struct tbb_trivially_copyable <T*> { enum { value = true }; };
00335 template<> struct tbb_trivially_copyable <short> { enum { value = true }; };
00336 template<> struct tbb_trivially_copyable <unsigned short> { enum { value = true }; };
00337 template<> struct tbb_trivially_copyable <int> { enum { value = !tbb_large_object<int>::value }; };
00338 template<> struct tbb_trivially_copyable <unsigned int> { enum { value = !tbb_large_object<int>::value }; };
00339 template<> struct tbb_trivially_copyable <long> { enum { value = !tbb_large_object<long>::value }; };
00340 template<> struct tbb_trivially_copyable <unsigned long> { enum { value = !tbb_large_object<long>::value }; };
00341 template<> struct tbb_trivially_copyable <float> { enum { value = !tbb_large_object<float>::value }; };
00342 template<> struct tbb_trivially_copyable <double> { enum { value = !tbb_large_object<double>::value }; };
00343 #else
00344 #if __GNUC__==4 && __GNUC_MINOR__>=4 && __GXX_EXPERIMENTAL_CXX0X__
00345 template<typename T> struct tbb_trivially_copyable { enum { value = std::has_trivial_copy_constructor<T>::value }; };
00346 #else
00347 template<typename T> struct tbb_trivially_copyable { enum { value = std::is_trivially_copyable<T>::value }; };
00348 #endif //
00349 #endif // __TBB_USE_CPP0X
00350
00351 template<typename T> struct is_large_object {enum { value = tbb_large_object<T>::value || !tbb_trivially_copyable<T>::value }; };
00352
00353 template<typename T, bool> class token_helper;
00354
00355
00356 template<typename T>
00357 class token_helper<T, true> {
00358 public:
00359 typedef typename tbb::tbb_allocator<T> allocator;
00360 typedef T* pointer;
00361 typedef T value_type;
00362 static pointer create_token(const value_type & source) {
00363 pointer output_t = allocator().allocate(1);
00364 return new (output_t) T(source);
00365 }
00366 static value_type & token(pointer & t) { return *t;}
00367 static void * cast_to_void_ptr(pointer ref) { return (void *) ref; }
00368 static pointer cast_from_void_ptr(void * ref) { return (pointer)ref; }
00369 static void destroy_token(pointer token) {
00370 allocator().destroy(token);
00371 allocator().deallocate(token,1);
00372 }
00373 };
00374
00375
00376 template<typename T>
00377 class token_helper<T*, false > {
00378 public:
00379 typedef T* pointer;
00380 typedef T* value_type;
00381 static pointer create_token(const value_type & source) { return source; }
00382 static value_type & token(pointer & t) { return t;}
00383 static void * cast_to_void_ptr(pointer ref) { return (void *)ref; }
00384 static pointer cast_from_void_ptr(void * ref) { return (pointer)ref; }
00385 static void destroy_token( pointer ) {}
00386 };
00387
00388
00389 template<typename T>
00390 class token_helper<T, false> {
00391 typedef union {
00392 T actual_value;
00393 void * void_overlay;
00394 } type_to_void_ptr_map;
00395 public:
00396 typedef T pointer;
00397 typedef T value_type;
00398 static pointer create_token(const value_type & source) {
00399 return source; }
00400 static value_type & token(pointer & t) { return t;}
00401 static void * cast_to_void_ptr(pointer ref) {
00402 type_to_void_ptr_map mymap;
00403 mymap.void_overlay = NULL;
00404 mymap.actual_value = ref;
00405 return mymap.void_overlay;
00406 }
00407 static pointer cast_from_void_ptr(void * ref) {
00408 type_to_void_ptr_map mymap;
00409 mymap.void_overlay = ref;
00410 return mymap.actual_value;
00411 }
00412 static void destroy_token( pointer ) {}
00413 };
00414
00415 template<typename T, typename U, typename Body>
00416 class concrete_filter: public tbb::filter {
00417 const Body& my_body;
00418 typedef token_helper<T,is_large_object<T>::value > t_helper;
00419 typedef typename t_helper::pointer t_pointer;
00420 typedef token_helper<U,is_large_object<U>::value > u_helper;
00421 typedef typename u_helper::pointer u_pointer;
00422
00423 void* operator()(void* input) {
00424 t_pointer temp_input = t_helper::cast_from_void_ptr(input);
00425 u_pointer output_u = u_helper::create_token(my_body(t_helper::token(temp_input)));
00426 t_helper::destroy_token(temp_input);
00427 return u_helper::cast_to_void_ptr(output_u);
00428 }
00429
00430 void finalize(void * input) {
00431 t_pointer temp_input = t_helper::cast_from_void_ptr(input);
00432 t_helper::destroy_token(temp_input);
00433 }
00434
00435 public:
00436 concrete_filter(tbb::filter::mode filter_mode, const Body& body) : filter(filter_mode), my_body(body) {}
00437 };
00438
00439
00440 template<typename U, typename Body>
00441 class concrete_filter<void,U,Body>: public filter {
00442 const Body& my_body;
00443 typedef token_helper<U, is_large_object<U>::value > u_helper;
00444 typedef typename u_helper::pointer u_pointer;
00445
00446 void* operator()(void*) {
00447 flow_control control;
00448 u_pointer output_u = u_helper::create_token(my_body(control));
00449 if(control.is_pipeline_stopped) {
00450 u_helper::destroy_token(output_u);
00451 set_end_of_input();
00452 return NULL;
00453 }
00454 return u_helper::cast_to_void_ptr(output_u);
00455 }
00456
00457 public:
00458 concrete_filter(tbb::filter::mode filter_mode, const Body& body) :
00459 filter(static_cast<tbb::filter::mode>(filter_mode | filter_may_emit_null)),
00460 my_body(body)
00461 {}
00462 };
00463
00464 template<typename T, typename Body>
00465 class concrete_filter<T,void,Body>: public filter {
00466 const Body& my_body;
00467 typedef token_helper<T, is_large_object<T>::value > t_helper;
00468 typedef typename t_helper::pointer t_pointer;
00469
00470 void* operator()(void* input) {
00471 t_pointer temp_input = t_helper::cast_from_void_ptr(input);
00472 my_body(t_helper::token(temp_input));
00473 t_helper::destroy_token(temp_input);
00474 return NULL;
00475 }
00476 void finalize(void* input) {
00477 t_pointer temp_input = t_helper::cast_from_void_ptr(input);
00478 t_helper::destroy_token(temp_input);
00479 }
00480
00481 public:
00482 concrete_filter(tbb::filter::mode filter_mode, const Body& body) : filter(filter_mode), my_body(body) {}
00483 };
00484
00485 template<typename Body>
00486 class concrete_filter<void,void,Body>: public filter {
00487 const Body& my_body;
00488
00490 void* operator()(void*) {
00491 flow_control control;
00492 my_body(control);
00493 void* output = control.is_pipeline_stopped ? NULL : (void*)(intptr_t)-1;
00494 return output;
00495 }
00496 public:
00497 concrete_filter(filter::mode filter_mode, const Body& body) : filter(filter_mode), my_body(body) {}
00498 };
00499
00501
00502 class pipeline_proxy {
00503 tbb::pipeline my_pipe;
00504 public:
00505 pipeline_proxy( const filter_t<void,void>& filter_chain );
00506 ~pipeline_proxy() {
00507 while( filter* f = my_pipe.filter_list )
00508 delete f;
00509 }
00510 tbb::pipeline* operator->() { return &my_pipe; }
00511 };
00512
00514
00515 class filter_node: tbb::internal::no_copy {
00517 tbb::atomic<intptr_t> ref_count;
00518 protected:
00519 filter_node() {
00520 ref_count = 0;
00521 #ifdef __TBB_TEST_FILTER_NODE_COUNT
00522 ++(__TBB_TEST_FILTER_NODE_COUNT);
00523 #endif
00524 }
00525 public:
00527 virtual void add_to( pipeline& ) = 0;
00529 void add_ref() {++ref_count;}
00531 void remove_ref() {
00532 __TBB_ASSERT(ref_count>0,"ref_count underflow");
00533 if( --ref_count==0 )
00534 delete this;
00535 }
00536 virtual ~filter_node() {
00537 #ifdef __TBB_TEST_FILTER_NODE_COUNT
00538 --(__TBB_TEST_FILTER_NODE_COUNT);
00539 #endif
00540 }
00541 };
00542
00544 template<typename T, typename U, typename Body>
00545 class filter_node_leaf: public filter_node {
00546 const tbb::filter::mode mode;
00547 const Body body;
00548 void add_to( pipeline& p ) {
00549 concrete_filter<T,U,Body>* f = new concrete_filter<T,U,Body>(mode,body);
00550 p.add_filter( *f );
00551 }
00552 public:
00553 filter_node_leaf( tbb::filter::mode m, const Body& b ) : mode(m), body(b) {}
00554 };
00555
00557 class filter_node_join: public filter_node {
00558 friend class filter_node;
00559 filter_node& left;
00560 filter_node& right;
00561 ~filter_node_join() {
00562 left.remove_ref();
00563 right.remove_ref();
00564 }
00565 void add_to( pipeline& p ) {
00566 left.add_to(p);
00567 right.add_to(p);
00568 }
00569 public:
00570 filter_node_join( filter_node& x, filter_node& y ) : left(x), right(y) {
00571 left.add_ref();
00572 right.add_ref();
00573 }
00574 };
00575
00576 }
00578
00580 template<typename T, typename U, typename Body>
00581 filter_t<T,U> make_filter(tbb::filter::mode mode, const Body& body) {
00582 return new internal::filter_node_leaf<T,U,Body>(mode, body);
00583 }
00584
00585 template<typename T, typename V, typename U>
00586 filter_t<T,U> operator& (const filter_t<T,V>& left, const filter_t<V,U>& right) {
00587 __TBB_ASSERT(left.root,"cannot use default-constructed filter_t as left argument of '&'");
00588 __TBB_ASSERT(right.root,"cannot use default-constructed filter_t as right argument of '&'");
00589 return new internal::filter_node_join(*left.root,*right.root);
00590 }
00591
00593 template<typename T, typename U>
00594 class filter_t {
00595 typedef internal::filter_node filter_node;
00596 filter_node* root;
00597 filter_t( filter_node* root_ ) : root(root_) {
00598 root->add_ref();
00599 }
00600 friend class internal::pipeline_proxy;
00601 template<typename T_, typename U_, typename Body>
00602 friend filter_t<T_,U_> make_filter(tbb::filter::mode, const Body& );
00603 template<typename T_, typename V_, typename U_>
00604 friend filter_t<T_,U_> operator& (const filter_t<T_,V_>& , const filter_t<V_,U_>& );
00605 public:
00606 filter_t() : root(NULL) {}
00607 filter_t( const filter_t<T,U>& rhs ) : root(rhs.root) {
00608 if( root ) root->add_ref();
00609 }
00610 template<typename Body>
00611 filter_t( tbb::filter::mode mode, const Body& body ) :
00612 root( new internal::filter_node_leaf<T,U,Body>(mode, body) ) {
00613 root->add_ref();
00614 }
00615
00616 void operator=( const filter_t<T,U>& rhs ) {
00617
00618
00619 filter_node* old = root;
00620 root = rhs.root;
00621 if( root ) root->add_ref();
00622 if( old ) old->remove_ref();
00623 }
00624 ~filter_t() {
00625 if( root ) root->remove_ref();
00626 }
00627 void clear() {
00628
00629 if( root ) {
00630 filter_node* old = root;
00631 root = NULL;
00632 old->remove_ref();
00633 }
00634 }
00635 };
00636
00637 inline internal::pipeline_proxy::pipeline_proxy( const filter_t<void,void>& filter_chain ) : my_pipe() {
00638 __TBB_ASSERT( filter_chain.root, "cannot apply parallel_pipeline to default-constructed filter_t" );
00639 filter_chain.root->add_to(my_pipe);
00640 }
00641
00642 inline void parallel_pipeline(size_t max_number_of_live_tokens, const filter_t<void,void>& filter_chain
00643 #if __TBB_TASK_GROUP_CONTEXT
00644 , tbb::task_group_context& context
00645 #endif
00646 ) {
00647 internal::pipeline_proxy pipe(filter_chain);
00648
00649 pipe->run(max_number_of_live_tokens
00650 #if __TBB_TASK_GROUP_CONTEXT
00651 , context
00652 #endif
00653 );
00654 }
00655
00656 #if __TBB_TASK_GROUP_CONTEXT
00657 inline void parallel_pipeline(size_t max_number_of_live_tokens, const filter_t<void,void>& filter_chain) {
00658 tbb::task_group_context context;
00659 parallel_pipeline(max_number_of_live_tokens, filter_chain, context);
00660 }
00661 #endif // __TBB_TASK_GROUP_CONTEXT
00662
00663 }
00664
00665 using interface6::flow_control;
00666 using interface6::filter_t;
00667 using interface6::make_filter;
00668 using interface6::parallel_pipeline;
00669
00670 }
00671
00672 #endif