- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

# pipeline.h

    00001 /*
    00002     Copyright 2005-2012 Intel Corporation.  All Rights Reserved.
    00003
    00004     This file is part of Threading Building Blocks.
    00005
    00006     Threading Building Blocks is free software; you can redistribute it
    00007     and/or modify it under the terms of the GNU General Public License
    00008     version 2 as published by the Free Software Foundation.
    00009
    00010     Threading Building Blocks is distributed in the hope that it will be
    00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
    00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00013     GNU General Public License for more details.
    00014
    00015     You should have received a copy of the GNU General Public License
    00016     along with Threading Building Blocks; if not, write to the Free Software
    00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    00018
    00019     As a special exception, you may use this file as part of a free software
    00020     library without restriction.  Specifically, if other files instantiate
    00021     templates or use macros or inline functions from this file, or you compile
    00022     this file and link it with other files to produce an executable, this
    00023     file does not by itself cause the resulting executable to be covered by
    00024     the GNU General Public License.  This exception does not however
    00025     invalidate any other reasons why the executable file might be covered by
    00026     the GNU General Public License.
    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 // The argument for PIPELINE_VERSION should be an integer between 2 and 9
    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 } // namespace internal
    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 /* TBB_USE_CAPTURED_EXCEPTION */
    00099
    00100     static const unsigned char current_version = __TBB_PIPELINE_VERSION(5);
    00101     static const unsigned char version_mask = 0x7<<1; // bits 1-3 are for version
    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     // signal end-of-input for concrete_filters
    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* /*item*/ ) {};
    00169 #endif
    00170
    00171 private:
    00173     filter* next_filter_in_pipeline;
    00174
    00176     //  (pipeline has not yet reached end_of_input or this filter has not yet
    00177     //  seen the last token produced by input_filter)
    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         // item was processed
    00209         success,
    00210         // item is currently not available
    00211         item_not_available,
    00212         // there are no more items to process
    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 // Support for lambda-friendly parallel_pipeline interface
    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 // cannot use SFINAE in current compilers.  Explicitly list the types we wish to be
    00332 // placed as-is in the pipeline input_buffers.
    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 // large object helper (uses tbb_allocator)
    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 // pointer specialization
    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 /*token*/) {}
    00386 };
    00387
    00388 // small object specialization (converts void* to the correct type, passes objects directly.)
    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;  // not really a pointer in this case.
    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 /*token*/) {}
    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     /*override*/ 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     /*override*/ 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 // input
    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     /*override*/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     /*override*/ 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     /*override*/ 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     /*override*/ 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; // filter destructor removes it from the pipeline
    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     /*override*/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; // to suppress GCC 3.2 warnings
    00559     filter_node& left;
    00560     filter_node& right;
    00561     /*override*/~filter_node_join() {
    00562        left.remove_ref();
    00563        right.remove_ref();
    00564     }
    00565     /*override*/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 } // namespace internal
    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         // Order of operations below carefully chosen so that reference counts remain correct
    00618         // in unlikely event that remove_ref throws exception.
    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         // Like operator= with filter_t() on right side.
    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     // tbb::pipeline::run() is called via the proxy
    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 } // interface6
    00664
    00665 using interface6::flow_control;
    00666 using interface6::filter_t;
    00667 using interface6::make_filter;
    00668 using interface6::parallel_pipeline;
    00669
    00670 } // tbb
    00671
    00672 #endif /* __TBB_pipeline_H */

Copyright © 2005-2012 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.