pipeline.h Source File

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

- File List
- File Members

# pipeline.h

    00001 /*
    00002     Copyright 2005-2012 Intel Corporation.  All Rights Reserved.
    00003
    00004     The source code contained or described herein and all documents related
    00005     to the source code ("Material") are owned by Intel Corporation or its
    00006     suppliers or licensors.  Title to the Material remains with Intel
    00007     Corporation or its suppliers and licensors.  The Material is protected
    00008     by worldwide copyright laws and treaty provisions.  No part of the
    00009     Material may be used, copied, reproduced, modified, published, uploaded,
    00010     posted, transmitted, distributed, or disclosed in any way without
    00011     Intel's prior express written permission.
    00012
    00013     No license under any patent, copyright, trade secret or other
    00014     intellectual property right is granted to or conferred upon you by
    00015     disclosure or delivery of the Materials, either expressly, by
    00016     implication, inducement, estoppel or otherwise.  Any license under such
    00017     intellectual property rights must be express and approved by Intel in
    00018     writing.
    00019 */
    00020
    00021 #ifndef __TBB_pipeline_H
    00022 #define __TBB_pipeline_H
    00023
    00024 #include "atomic.h"
    00025 #include "task.h"
    00026 #include "tbb_allocator.h"
    00027 #include <cstddef>
    00028
    00029 #if !TBB_IMPLEMENT_CPP0X
    00030 #include <type_traits>
    00031 #endif
    00032
    00033 namespace tbb {
    00034
    00035 class pipeline;
    00036 class filter;
    00037
    00039 namespace internal {
    00040
    00041 // The argument for PIPELINE_VERSION should be an integer between 2 and 9
    00042 #define __TBB_PIPELINE_VERSION(x) (unsigned char)(x-2)<<1
    00043
    00044 typedef unsigned long Token;
    00045 typedef long tokendiff_t;
    00046 class stage_task;
    00047 class input_buffer;
    00048 class pipeline_root_task;
    00049 class pipeline_cleaner;
    00050
    00051 } // namespace internal
    00052
    00053 namespace interface6 {
    00054     template<typename T, typename U> class filter_t;
    00055
    00056     namespace internal {
    00057         class pipeline_proxy;
    00058     }
    00059 }
    00060
    00062
    00064
    00065 class filter: internal::no_copy {
    00066 private:
    00068     static filter* not_in_pipeline() {return reinterpret_cast<filter*>(intptr_t(-1));}
    00069 protected:
    00071     static const unsigned char filter_is_serial = 0x1;
    00072
    00074
    00076     static const unsigned char filter_is_out_of_order = 0x1<<4;
    00077
    00079     static const unsigned char filter_is_bound = 0x1<<5;
    00080
    00082     static const unsigned char filter_may_emit_null = 0x1<<6;
    00083
    00085     static const unsigned char exact_exception_propagation =
    00086 #if TBB_USE_CAPTURED_EXCEPTION
    00087             0x0;
    00088 #else
    00089             0x1<<7;
    00090 #endif /* TBB_USE_CAPTURED_EXCEPTION */
    00091
    00092     static const unsigned char current_version = __TBB_PIPELINE_VERSION(5);
    00093     static const unsigned char version_mask = 0x7<<1; // bits 1-3 are for version
    00094 public:
    00095     enum mode {
    00097         parallel = current_version | filter_is_out_of_order,
    00099         serial_in_order = current_version | filter_is_serial,
    00101         serial_out_of_order = current_version | filter_is_serial | filter_is_out_of_order,
    00103         serial = serial_in_order
    00104     };
    00105 protected:
    00106     filter( bool is_serial_ ) :
    00107         next_filter_in_pipeline(not_in_pipeline()),
    00108         my_input_buffer(NULL),
    00109         my_filter_mode(static_cast<unsigned char>((is_serial_ ? serial : parallel) | exact_exception_propagation)),
    00110         prev_filter_in_pipeline(not_in_pipeline()),
    00111         my_pipeline(NULL),
    00112         next_segment(NULL)
    00113     {}
    00114
    00115     filter( mode filter_mode ) :
    00116         next_filter_in_pipeline(not_in_pipeline()),
    00117         my_input_buffer(NULL),
    00118         my_filter_mode(static_cast<unsigned char>(filter_mode | exact_exception_propagation)),
    00119         prev_filter_in_pipeline(not_in_pipeline()),
    00120         my_pipeline(NULL),
    00121         next_segment(NULL)
    00122     {}
    00123
    00124     // signal end-of-input for concrete_filters
    00125     void __TBB_EXPORTED_METHOD set_end_of_input();
    00126
    00127 public:
    00129     bool is_serial() const {
    00130         return bool( my_filter_mode & filter_is_serial );
    00131     }
    00132
    00134     bool is_ordered() const {
    00135         return (my_filter_mode & (filter_is_out_of_order|filter_is_serial))==filter_is_serial;
    00136     }
    00137
    00139     bool is_bound() const {
    00140         return ( my_filter_mode & filter_is_bound )==filter_is_bound;
    00141     }
    00142
    00144     bool object_may_be_null() {
    00145         return ( my_filter_mode & filter_may_emit_null ) == filter_may_emit_null;
    00146     }
    00147
    00149
    00150     virtual void* operator()( void* item ) = 0;
    00151
    00153
    00154     virtual __TBB_EXPORTED_METHOD ~filter();
    00155
    00156 #if __TBB_TASK_GROUP_CONTEXT
    00158
    00160     virtual void finalize( void* /*item*/ ) {};
    00161 #endif
    00162
    00163 private:
    00165     filter* next_filter_in_pipeline;
    00166
    00168     //  (pipeline has not yet reached end_of_input or this filter has not yet
    00169     //  seen the last token produced by input_filter)
    00170     bool has_more_work();
    00171
    00173
    00174     internal::input_buffer* my_input_buffer;
    00175
    00176     friend class internal::stage_task;
    00177     friend class internal::pipeline_root_task;
    00178     friend class pipeline;
    00179     friend class thread_bound_filter;
    00180
    00182     const unsigned char my_filter_mode;
    00183
    00185     filter* prev_filter_in_pipeline;
    00186
    00188     pipeline* my_pipeline;
    00189
    00191
    00192     filter* next_segment;
    00193 };
    00194
    00196
    00197 class thread_bound_filter: public filter {
    00198 public:
    00199     enum result_type {
    00200         // item was processed
    00201         success,
    00202         // item is currently not available
    00203         item_not_available,
    00204         // there are no more items to process
    00205         end_of_stream
    00206     };
    00207 protected:
    00208     thread_bound_filter(mode filter_mode):
    00209          filter(static_cast<mode>(filter_mode | filter::filter_is_bound))
    00210     {}
    00211 public:
    00213
    00218     result_type __TBB_EXPORTED_METHOD try_process_item();
    00219
    00221
    00225     result_type __TBB_EXPORTED_METHOD process_item();
    00226
    00227 private:
    00229     result_type internal_process_item(bool is_blocking);
    00230 };
    00231
    00233
    00234 class pipeline {
    00235 public:
    00237     __TBB_EXPORTED_METHOD pipeline();
    00238
    00241     virtual __TBB_EXPORTED_METHOD ~pipeline();
    00242
    00244     void __TBB_EXPORTED_METHOD add_filter( filter& filter_ );
    00245
    00247     void __TBB_EXPORTED_METHOD run( size_t max_number_of_live_tokens );
    00248
    00249 #if __TBB_TASK_GROUP_CONTEXT
    00251     void __TBB_EXPORTED_METHOD run( size_t max_number_of_live_tokens, tbb::task_group_context& context );
    00252 #endif
    00253
    00255     void __TBB_EXPORTED_METHOD clear();
    00256
    00257 private:
    00258     friend class internal::stage_task;
    00259     friend class internal::pipeline_root_task;
    00260     friend class filter;
    00261     friend class thread_bound_filter;
    00262     friend class internal::pipeline_cleaner;
    00263     friend class tbb::interface6::internal::pipeline_proxy;
    00264
    00266     filter* filter_list;
    00267
    00269     filter* filter_end;
    00270
    00272     task* end_counter;
    00273
    00275     atomic<internal::Token> input_tokens;
    00276
    00278     atomic<internal::Token> token_counter;
    00279
    00281     bool end_of_input;
    00282
    00284     bool has_thread_bound_filters;
    00285
    00287     void remove_filter( filter& filter_ );
    00288
    00290     void __TBB_EXPORTED_METHOD inject_token( task& self );
    00291
    00292 #if __TBB_TASK_GROUP_CONTEXT
    00294     void clear_filters();
    00295 #endif
    00296 };
    00297
    00298 //------------------------------------------------------------------------
    00299 // Support for lambda-friendly parallel_pipeline interface
    00300 //------------------------------------------------------------------------
    00301
    00302 namespace interface6 {
    00303
    00304 namespace internal {
    00305     template<typename T, typename U, typename Body> class concrete_filter;
    00306 }
    00307
    00309 class flow_control {
    00310     bool is_pipeline_stopped;
    00311     flow_control() { is_pipeline_stopped = false; }
    00312     template<typename T, typename U, typename Body> friend class internal::concrete_filter;
    00313 public:
    00314     void stop() { is_pipeline_stopped = true; }
    00315 };
    00316
    00318 namespace internal {
    00319
    00320 template<typename T> struct tbb_large_object {enum { value = sizeof(T) > sizeof(void *) }; };
    00321
    00322 #if TBB_IMPLEMENT_CPP0X
    00323 // cannot use SFINAE in current compilers.  Explicitly list the types we wish to be
    00324 // placed as-is in the pipeline input_buffers.
    00325 template<typename T> struct tbb_trivially_copyable { enum { value = false }; };
    00326 template<typename T> struct tbb_trivially_copyable <T*> { enum { value = true }; };
    00327 template<> struct tbb_trivially_copyable <short> { enum { value = true }; };
    00328 template<> struct tbb_trivially_copyable <unsigned short> { enum { value = true }; };
    00329 template<> struct tbb_trivially_copyable <int> { enum { value = !tbb_large_object<int>::value }; };
    00330 template<> struct tbb_trivially_copyable <unsigned int> { enum { value = !tbb_large_object<int>::value }; };
    00331 template<> struct tbb_trivially_copyable <long> { enum { value = !tbb_large_object<long>::value }; };
    00332 template<> struct tbb_trivially_copyable <unsigned long> { enum { value = !tbb_large_object<long>::value }; };
    00333 template<> struct tbb_trivially_copyable <float> { enum { value = !tbb_large_object<float>::value }; };
    00334 template<> struct tbb_trivially_copyable <double> { enum { value = !tbb_large_object<double>::value }; };
    00335 #else
    00336 #if __GNUC__==4 && __GNUC_MINOR__>=4 && __GXX_EXPERIMENTAL_CXX0X__
    00337 template<typename T> struct tbb_trivially_copyable { enum { value = std::has_trivial_copy_constructor<T>::value }; };
    00338 #else
    00339 template<typename T> struct tbb_trivially_copyable { enum { value = std::is_trivially_copyable<T>::value }; };
    00340 #endif //
    00341 #endif // __TBB_USE_CPP0X
    00342
    00343 template<typename T> struct is_large_object {enum { value = tbb_large_object<T>::value || !tbb_trivially_copyable<T>::value }; };
    00344
    00345 template<typename T, bool> class token_helper;
    00346
    00347 // large object helper (uses tbb_allocator)
    00348 template<typename T>
    00349 class token_helper<T, true> {
    00350     public:
    00351     typedef typename tbb::tbb_allocator<T> allocator;
    00352     typedef T* pointer;
    00353     typedef T value_type;
    00354     static pointer create_token(const value_type & source) {
    00355         pointer output_t = allocator().allocate(1);
    00356         return new (output_t) T(source);
    00357     }
    00358     static value_type & token(pointer & t) { return *t;}
    00359     static void * cast_to_void_ptr(pointer ref) { return (void *) ref; }
    00360     static pointer cast_from_void_ptr(void * ref) { return (pointer)ref; }
    00361     static void destroy_token(pointer token) {
    00362         allocator().destroy(token);
    00363         allocator().deallocate(token,1);
    00364     }
    00365 };
    00366
    00367 // pointer specialization
    00368 template<typename T>
    00369 class token_helper<T*, false > {
    00370     public:
    00371     typedef T* pointer;
    00372     typedef T* value_type;
    00373     static pointer create_token(const value_type & source) { return source; }
    00374     static value_type & token(pointer & t) { return t;}
    00375     static void * cast_to_void_ptr(pointer ref) { return (void *)ref; }
    00376     static pointer cast_from_void_ptr(void * ref) { return (pointer)ref; }
    00377     static void destroy_token( pointer /*token*/) {}
    00378 };
    00379
    00380 // small object specialization (converts void* to the correct type, passes objects directly.)
    00381 template<typename T>
    00382 class token_helper<T, false> {
    00383     typedef union {
    00384         T actual_value;
    00385         void * void_overlay;
    00386     } type_to_void_ptr_map;
    00387     public:
    00388     typedef T pointer;  // not really a pointer in this case.
    00389     typedef T value_type;
    00390     static pointer create_token(const value_type & source) {
    00391         return source; }
    00392     static value_type & token(pointer & t) { return t;}
    00393     static void * cast_to_void_ptr(pointer ref) {
    00394         type_to_void_ptr_map mymap;
    00395         mymap.void_overlay = NULL;
    00396         mymap.actual_value = ref;
    00397         return mymap.void_overlay;
    00398     }
    00399     static pointer cast_from_void_ptr(void * ref) {
    00400         type_to_void_ptr_map mymap;
    00401         mymap.void_overlay = ref;
    00402         return mymap.actual_value;
    00403     }
    00404     static void destroy_token( pointer /*token*/) {}
    00405 };
    00406
    00407 template<typename T, typename U, typename Body>
    00408 class concrete_filter: public tbb::filter {
    00409     const Body& my_body;
    00410     typedef token_helper<T,is_large_object<T>::value > t_helper;
    00411     typedef typename t_helper::pointer t_pointer;
    00412     typedef token_helper<U,is_large_object<U>::value > u_helper;
    00413     typedef typename u_helper::pointer u_pointer;
    00414
    00415     /*override*/ void* operator()(void* input) {
    00416         t_pointer temp_input = t_helper::cast_from_void_ptr(input);
    00417         u_pointer output_u = u_helper::create_token(my_body(t_helper::token(temp_input)));
    00418         t_helper::destroy_token(temp_input);
    00419         return u_helper::cast_to_void_ptr(output_u);
    00420     }
    00421
    00422     /*override*/ void finalize(void * input) {
    00423         t_pointer temp_input = t_helper::cast_from_void_ptr(input);
    00424         t_helper::destroy_token(temp_input);
    00425     }
    00426
    00427 public:
    00428     concrete_filter(tbb::filter::mode filter_mode, const Body& body) : filter(filter_mode), my_body(body) {}
    00429 };
    00430
    00431 // input
    00432 template<typename U, typename Body>
    00433 class concrete_filter<void,U,Body>: public filter {
    00434     const Body& my_body;
    00435     typedef token_helper<U, is_large_object<U>::value > u_helper;
    00436     typedef typename u_helper::pointer u_pointer;
    00437
    00438     /*override*/void* operator()(void*) {
    00439         flow_control control;
    00440         u_pointer output_u = u_helper::create_token(my_body(control));
    00441         if(control.is_pipeline_stopped) {
    00442             u_helper::destroy_token(output_u);
    00443             set_end_of_input();
    00444             return NULL;
    00445         }
    00446         return u_helper::cast_to_void_ptr(output_u);
    00447     }
    00448
    00449 public:
    00450     concrete_filter(tbb::filter::mode filter_mode, const Body& body) :
    00451         filter(static_cast<tbb::filter::mode>(filter_mode | filter_may_emit_null)),
    00452         my_body(body)
    00453     {}
    00454 };
    00455
    00456 template<typename T, typename Body>
    00457 class concrete_filter<T,void,Body>: public filter {
    00458     const Body& my_body;
    00459     typedef token_helper<T, is_large_object<T>::value > t_helper;
    00460     typedef typename t_helper::pointer t_pointer;
    00461
    00462     /*override*/ void* operator()(void* input) {
    00463         t_pointer temp_input = t_helper::cast_from_void_ptr(input);
    00464         my_body(t_helper::token(temp_input));
    00465         t_helper::destroy_token(temp_input);
    00466         return NULL;
    00467     }
    00468     /*override*/ void finalize(void* input) {
    00469         t_pointer temp_input = t_helper::cast_from_void_ptr(input);
    00470         t_helper::destroy_token(temp_input);
    00471     }
    00472
    00473 public:
    00474     concrete_filter(tbb::filter::mode filter_mode, const Body& body) : filter(filter_mode), my_body(body) {}
    00475 };
    00476
    00477 template<typename Body>
    00478 class concrete_filter<void,void,Body>: public filter {
    00479     const Body& my_body;
    00480
    00482     /*override*/ void* operator()(void*) {
    00483         flow_control control;
    00484         my_body(control);
    00485         void* output = control.is_pipeline_stopped ? NULL : (void*)(intptr_t)-1;
    00486         return output;
    00487     }
    00488 public:
    00489     concrete_filter(filter::mode filter_mode, const Body& body) : filter(filter_mode), my_body(body) {}
    00490 };
    00491
    00493
    00494 class pipeline_proxy {
    00495     tbb::pipeline my_pipe;
    00496 public:
    00497     pipeline_proxy( const filter_t<void,void>& filter_chain );
    00498     ~pipeline_proxy() {
    00499         while( filter* f = my_pipe.filter_list )
    00500             delete f; // filter destructor removes it from the pipeline
    00501     }
    00502     tbb::pipeline* operator->() { return &my_pipe; }
    00503 };
    00504
    00506
    00507 class filter_node: tbb::internal::no_copy {
    00509     tbb::atomic<intptr_t> ref_count;
    00510 protected:
    00511     filter_node() {
    00512         ref_count = 0;
    00513 #ifdef __TBB_TEST_FILTER_NODE_COUNT
    00514         ++(__TBB_TEST_FILTER_NODE_COUNT);
    00515 #endif
    00516     }
    00517 public:
    00519     virtual void add_to( pipeline& ) = 0;
    00521     void add_ref() {++ref_count;}
    00523     void remove_ref() {
    00524         __TBB_ASSERT(ref_count>0,"ref_count underflow");
    00525         if( --ref_count==0 )
    00526             delete this;
    00527     }
    00528     virtual ~filter_node() {
    00529 #ifdef __TBB_TEST_FILTER_NODE_COUNT
    00530         --(__TBB_TEST_FILTER_NODE_COUNT);
    00531 #endif
    00532     }
    00533 };
    00534
    00536 template<typename T, typename U, typename Body>
    00537 class filter_node_leaf: public filter_node  {
    00538     const tbb::filter::mode mode;
    00539     const Body body;
    00540     /*override*/void add_to( pipeline& p ) {
    00541         concrete_filter<T,U,Body>* f = new concrete_filter<T,U,Body>(mode,body);
    00542         p.add_filter( *f );
    00543     }
    00544 public:
    00545     filter_node_leaf( tbb::filter::mode m, const Body& b ) : mode(m), body(b) {}
    00546 };
    00547
    00549 class filter_node_join: public filter_node {
    00550     friend class filter_node; // to suppress GCC 3.2 warnings
    00551     filter_node& left;
    00552     filter_node& right;
    00553     /*override*/~filter_node_join() {
    00554        left.remove_ref();
    00555        right.remove_ref();
    00556     }
    00557     /*override*/void add_to( pipeline& p ) {
    00558         left.add_to(p);
    00559         right.add_to(p);
    00560     }
    00561 public:
    00562     filter_node_join( filter_node& x, filter_node& y ) : left(x), right(y) {
    00563        left.add_ref();
    00564        right.add_ref();
    00565     }
    00566 };
    00567
    00568 } // namespace internal
    00570
    00572 template<typename T, typename U, typename Body>
    00573 filter_t<T,U> make_filter(tbb::filter::mode mode, const Body& body) {
    00574     return new internal::filter_node_leaf<T,U,Body>(mode, body);
    00575 }
    00576
    00577 template<typename T, typename V, typename U>
    00578 filter_t<T,U> operator& (const filter_t<T,V>& left, const filter_t<V,U>& right) {
    00579     __TBB_ASSERT(left.root,"cannot use default-constructed filter_t as left argument of '&'");
    00580     __TBB_ASSERT(right.root,"cannot use default-constructed filter_t as right argument of '&'");
    00581     return new internal::filter_node_join(*left.root,*right.root);
    00582 }
    00583
    00585 template<typename T, typename U>
    00586 class filter_t {
    00587     typedef internal::filter_node filter_node;
    00588     filter_node* root;
    00589     filter_t( filter_node* root_ ) : root(root_) {
    00590         root->add_ref();
    00591     }
    00592     friend class internal::pipeline_proxy;
    00593     template<typename T_, typename U_, typename Body>
    00594     friend filter_t<T_,U_> make_filter(tbb::filter::mode, const Body& );
    00595     template<typename T_, typename V_, typename U_>
    00596     friend filter_t<T_,U_> operator& (const filter_t<T_,V_>& , const filter_t<V_,U_>& );
    00597 public:
    00598     filter_t() : root(NULL) {}
    00599     filter_t( const filter_t<T,U>& rhs ) : root(rhs.root) {
    00600         if( root ) root->add_ref();
    00601     }
    00602     template<typename Body>
    00603     filter_t( tbb::filter::mode mode, const Body& body ) :
    00604         root( new internal::filter_node_leaf<T,U,Body>(mode, body) ) {
    00605         root->add_ref();
    00606     }
    00607
    00608     void operator=( const filter_t<T,U>& rhs ) {
    00609         // Order of operations below carefully chosen so that reference counts remain correct
    00610         // in unlikely event that remove_ref throws exception.
    00611         filter_node* old = root;
    00612         root = rhs.root;
    00613         if( root ) root->add_ref();
    00614         if( old ) old->remove_ref();
    00615     }
    00616     ~filter_t() {
    00617         if( root ) root->remove_ref();
    00618     }
    00619     void clear() {
    00620         // Like operator= with filter_t() on right side.
    00621         if( root ) {
    00622             filter_node* old = root;
    00623             root = NULL;
    00624             old->remove_ref();
    00625         }
    00626     }
    00627 };
    00628
    00629 inline internal::pipeline_proxy::pipeline_proxy( const filter_t<void,void>& filter_chain ) : my_pipe() {
    00630     __TBB_ASSERT( filter_chain.root, "cannot apply parallel_pipeline to default-constructed filter_t"  );
    00631     filter_chain.root->add_to(my_pipe);
    00632 }
    00633
    00634 inline void parallel_pipeline(size_t max_number_of_live_tokens, const filter_t<void,void>& filter_chain
    00635 #if __TBB_TASK_GROUP_CONTEXT
    00636     , tbb::task_group_context& context
    00637 #endif
    00638     ) {
    00639     internal::pipeline_proxy pipe(filter_chain);
    00640     // tbb::pipeline::run() is called via the proxy
    00641     pipe->run(max_number_of_live_tokens
    00642 #if __TBB_TASK_GROUP_CONTEXT
    00643               , context
    00644 #endif
    00645     );
    00646 }
    00647
    00648 #if __TBB_TASK_GROUP_CONTEXT
    00649 inline void parallel_pipeline(size_t max_number_of_live_tokens, const filter_t<void,void>& filter_chain) {
    00650     tbb::task_group_context context;
    00651     parallel_pipeline(max_number_of_live_tokens, filter_chain, context);
    00652 }
    00653 #endif // __TBB_TASK_GROUP_CONTEXT
    00654
    00655 } // interface6
    00656
    00657 using interface6::flow_control;
    00658 using interface6::filter_t;
    00659 using interface6::make_filter;
    00660 using interface6::parallel_pipeline;
    00661
    00662 } // tbb
    00663
    00664 #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.