task.h

00001 /*
00002     Copyright 2005-2010 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_task_H
00022 #define __TBB_task_H
00023 
00024 #include "tbb_stddef.h"
00025 #include "tbb_machine.h"
00026 
00027 typedef struct ___itt_caller *__itt_caller;
00028 
00029 namespace tbb {
00030 
00031 class task;
00032 class task_list;
00033 
00034 #if __TBB_TASK_GROUP_CONTEXT
00035 class task_group_context;
00036 #endif /* __TBB_TASK_GROUP_CONTEXT */
00037 
00038 // MSVC does not allow taking the address of a member that was defined 
00039 // privately in task_base and made public in class task via a using declaration.
00040 #if _MSC_VER || (__GNUC__==3 && __GNUC_MINOR__<3)
00041 #define __TBB_TASK_BASE_ACCESS public
00042 #else
00043 #define __TBB_TASK_BASE_ACCESS private
00044 #endif
00045 
00046 namespace internal {
00047 
00048     class allocate_additional_child_of_proxy: no_assign {
00050         task* self;
00051         task& parent;
00052     public:
00053         explicit allocate_additional_child_of_proxy( task& parent_ ) : self(NULL), parent(parent_) {}
00054         task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00055         void __TBB_EXPORTED_METHOD free( task& ) const;
00056     };
00057 
00058 }
00059 
00060 namespace interface5 {
00061     namespace internal {
00063 
00068         class task_base: tbb::internal::no_copy {
00069         __TBB_TASK_BASE_ACCESS:
00070             friend class tbb::task;
00071 
00073             static void spawn( task& t );
00074  
00076             static void spawn( task_list& list );
00077 
00079 
00081             static tbb::internal::allocate_additional_child_of_proxy allocate_additional_child_of( task& t ) {
00082                 return tbb::internal::allocate_additional_child_of_proxy(t);
00083             }
00084 
00086 
00090             static void __TBB_EXPORTED_FUNC destroy( task& victim );
00091         }; 
00092     } // internal
00093 } // interface5
00094 
00096 namespace internal {
00097 
00098     class scheduler: no_copy {
00099     public:
00101         virtual void spawn( task& first, task*& next ) = 0;
00102 
00104         virtual void wait_for_all( task& parent, task* child ) = 0;
00105 
00107         virtual void spawn_root_and_wait( task& first, task*& next ) = 0;
00108 
00110         //  Have to have it just to shut up overzealous compilation warnings
00111         virtual ~scheduler() = 0;
00112 #if __TBB_ARENA_PER_MASTER
00113 
00115         virtual void enqueue( task& t, void* reserved ) = 0;
00116 #endif /* __TBB_ARENA_PER_MASTER */
00117     };
00118 
00120 
00121     typedef intptr_t reference_count;
00122 
00124     typedef unsigned short affinity_id;
00125 
00126 #if __TBB_TASK_GROUP_CONTEXT
00127     struct context_list_node_t {
00128         context_list_node_t *my_prev,
00129                             *my_next;
00130     };
00131 
00132     class allocate_root_with_context_proxy: no_assign {
00133         task_group_context& my_context;
00134     public:
00135         allocate_root_with_context_proxy ( task_group_context& ctx ) : my_context(ctx) {}
00136         task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00137         void __TBB_EXPORTED_METHOD free( task& ) const;
00138     };
00139 #endif /* __TBB_TASK_GROUP_CONTEXT */
00140 
00141     class allocate_root_proxy: no_assign {
00142     public:
00143         static task& __TBB_EXPORTED_FUNC allocate( size_t size );
00144         static void __TBB_EXPORTED_FUNC free( task& );
00145     };
00146 
00147     class allocate_continuation_proxy: no_assign {
00148     public:
00149         task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00150         void __TBB_EXPORTED_METHOD free( task& ) const;
00151     };
00152 
00153     class allocate_child_proxy: no_assign {
00154     public:
00155         task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00156         void __TBB_EXPORTED_METHOD free( task& ) const;
00157     };
00158 
00160 
00165     class task_prefix {
00166     private:
00167         friend class tbb::task;
00168         friend class tbb::interface5::internal::task_base;
00169         friend class tbb::task_list;
00170         friend class internal::scheduler;
00171         friend class internal::allocate_root_proxy;
00172         friend class internal::allocate_child_proxy;
00173         friend class internal::allocate_continuation_proxy;
00174         friend class internal::allocate_additional_child_of_proxy;
00175 
00176 #if __TBB_TASK_GROUP_CONTEXT
00178 
00181         task_group_context  *context;
00182 #endif /* __TBB_TASK_GROUP_CONTEXT */
00183         
00185 
00190         scheduler* origin;
00191 
00193         scheduler* owner;
00194 
00196 
00199         tbb::task* parent;
00200 
00202 
00206         reference_count ref_count;
00207 
00209 
00210         int depth;
00211 
00213 
00214         unsigned char state;
00215 
00217 
00222         unsigned char extra_state;
00223 
00224         affinity_id affinity;
00225 
00227         tbb::task* next;
00228 
00230         tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);}
00231     };
00232 
00233 } // namespace internal
00235 
00236 #if __TBB_TASK_GROUP_CONTEXT
00237 
00238 #if TBB_USE_CAPTURED_EXCEPTION
00239     class tbb_exception;
00240 #else
00241     namespace internal {
00242         class tbb_exception_ptr;
00243     }
00244 #endif /* !TBB_USE_CAPTURED_EXCEPTION */
00245 
00247 
00267 class task_group_context : internal::no_copy {
00268 private:
00269 #if TBB_USE_CAPTURED_EXCEPTION
00270     typedef tbb_exception exception_container_type;
00271 #else
00272     typedef internal::tbb_exception_ptr exception_container_type;
00273 #endif
00274 
00275     enum version_traits_word_layout {
00276         traits_offset = 16,
00277         version_mask = 0xFFFF,
00278         traits_mask = 0xFFFFul << traits_offset
00279     };
00280 
00281 public:
00282     enum kind_type {
00283         isolated,
00284         bound
00285     };
00286 
00287     enum traits_type {
00288         exact_exception = 0x0001ul << traits_offset,
00289         concurrent_wait = 0x0004ul << traits_offset,
00290 #if TBB_USE_CAPTURED_EXCEPTION
00291         default_traits = 0
00292 #else
00293         default_traits = exact_exception
00294 #endif /* !TBB_USE_CAPTURED_EXCEPTION */
00295     };
00296 
00297 private:
00298     union {
00300         kind_type my_kind;
00301         uintptr_t _my_kind_aligner;
00302     };
00303 
00305     task_group_context *my_parent;
00306 
00308 
00310     internal::context_list_node_t my_node;
00311 
00313     __itt_caller itt_caller;
00314 
00316 
00319     char _leading_padding[internal::NFS_MaxLineSize - 
00320                     2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal::context_list_node_t)
00321                           - sizeof(__itt_caller)];
00322     
00324     uintptr_t my_cancellation_requested;
00325     
00327 
00330     uintptr_t  my_version_and_traits;
00331 
00333     exception_container_type *my_exception;
00334 
00336 
00339     void *my_owner;
00340 
00342 
00343     char _trailing_padding[internal::NFS_MaxLineSize - sizeof(intptr_t) - 2 * sizeof(void*)];
00344 
00345 public:
00347 
00374     task_group_context ( kind_type relation_with_parent = bound,
00375                          uintptr_t traits = default_traits )
00376         : my_kind(relation_with_parent)
00377         , my_version_and_traits(1 | traits)
00378     {
00379         init();
00380     }
00381 
00382     __TBB_EXPORTED_METHOD ~task_group_context ();
00383 
00385 
00392     void __TBB_EXPORTED_METHOD reset ();
00393 
00395 
00402     bool __TBB_EXPORTED_METHOD cancel_group_execution ();
00403 
00405     bool __TBB_EXPORTED_METHOD is_group_execution_cancelled () const;
00406 
00408 
00414     void __TBB_EXPORTED_METHOD register_pending_exception ();
00415 
00416 protected:
00418 
00419     void __TBB_EXPORTED_METHOD init ();
00420 
00421 private:
00422     friend class task;
00423     friend class internal::allocate_root_with_context_proxy;
00424 
00425     static const kind_type binding_required = bound;
00426     static const kind_type binding_completed = kind_type(bound+1);
00427     static const kind_type detached = kind_type(binding_completed+1);
00428     static const kind_type dying = kind_type(detached+1);
00429 
00432     void propagate_cancellation_from_ancestors ();
00433 
00435     bool is_alive () { 
00436 #if TBB_USE_DEBUG
00437         return my_version_and_traits != 0xDeadBeef;
00438 #else
00439         return true;
00440 #endif /* TBB_USE_DEBUG */
00441     }
00442 }; // class task_group_context
00443 
00444 #endif /* __TBB_TASK_GROUP_CONTEXT */
00445 
00447 
00448 class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base {
00449 
00451     void __TBB_EXPORTED_METHOD internal_set_ref_count( int count );
00452 
00454     internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_count();
00455 
00456 protected:
00458     task() {prefix().extra_state=1;}
00459 
00460 public:
00462     virtual ~task() {}
00463 
00465     virtual task* execute() = 0;
00466 
00468     enum state_type {
00470         executing,
00472         reexecute,
00474         ready,
00476         allocated,
00478         freed,
00480         recycle 
00481     };
00482 
00483     //------------------------------------------------------------------------
00484     // Allocating tasks
00485     //------------------------------------------------------------------------
00486 
00488     static internal::allocate_root_proxy allocate_root() {
00489         return internal::allocate_root_proxy();
00490     }
00491 
00492 #if __TBB_TASK_GROUP_CONTEXT
00494     static internal::allocate_root_with_context_proxy allocate_root( task_group_context& ctx ) {
00495         return internal::allocate_root_with_context_proxy(ctx);
00496     }
00497 #endif /* __TBB_TASK_GROUP_CONTEXT */
00498 
00500 
00501     internal::allocate_continuation_proxy& allocate_continuation() {
00502         return *reinterpret_cast<internal::allocate_continuation_proxy*>(this);
00503     }
00504 
00506     internal::allocate_child_proxy& allocate_child() {
00507         return *reinterpret_cast<internal::allocate_child_proxy*>(this);
00508     }
00509 
00511     using task_base::allocate_additional_child_of;
00512 
00513 #if __TBB_DEPRECATED_TASK_INTERFACE
00515 
00519     void __TBB_EXPORTED_METHOD destroy( task& t );
00520 #else /* !__TBB_DEPRECATED_TASK_INTERFACE */
00522     using task_base::destroy;
00523 #endif /* !__TBB_DEPRECATED_TASK_INTERFACE */
00524 
00525     //------------------------------------------------------------------------
00526     // Recycling of tasks
00527     //------------------------------------------------------------------------
00528 
00530 
00536     void recycle_as_continuation() {
00537         __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00538         prefix().state = allocated;
00539     }
00540 
00542 
00544     void recycle_as_safe_continuation() {
00545         __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00546         prefix().state = recycle;
00547     }
00548 
00550     void recycle_as_child_of( task& new_parent ) {
00551         internal::task_prefix& p = prefix();
00552         __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" );
00553         __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled as a child" );
00554         __TBB_ASSERT( p.parent==NULL, "parent must be null" );
00555         __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" );
00556         __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already freed" );
00557         p.state = allocated;
00558         p.parent = &new_parent;
00559 #if __TBB_TASK_GROUP_CONTEXT
00560         p.context = new_parent.prefix().context;
00561 #endif /* __TBB_TASK_GROUP_CONTEXT */
00562     }
00563 
00565 
00566     void recycle_to_reexecute() {
00567         __TBB_ASSERT( prefix().state==executing, "execute not running, or already recycled" );
00568         __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled for reexecution" );
00569         prefix().state = reexecute;
00570     }
00571 
00572     // All depth-related methods are obsolete, and are retained for the sake 
00573     // of backward source compatibility only
00574     intptr_t depth() const {return 0;}
00575     void set_depth( intptr_t ) {}
00576     void add_to_depth( int ) {}
00577 
00578 
00579     //------------------------------------------------------------------------
00580     // Spawning and blocking
00581     //------------------------------------------------------------------------
00582 
00584     void set_ref_count( int count ) {
00585 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00586         internal_set_ref_count(count);
00587 #else
00588         prefix().ref_count = count;
00589 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
00590     }
00591 
00593 
00594     void increment_ref_count() {
00595         __TBB_FetchAndIncrementWacquire( &prefix().ref_count );
00596     }
00597 
00599 
00600     int decrement_ref_count() {
00601 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00602         return int(internal_decrement_ref_count());
00603 #else
00604         return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))-1;
00605 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
00606     }
00607 
00609     using task_base::spawn;
00610 
00612     void spawn_and_wait_for_all( task& child ) {
00613         prefix().owner->wait_for_all( *this, &child );
00614     }
00615 
00617     void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list );
00618 
00620     static void spawn_root_and_wait( task& root ) {
00621         root.prefix().owner->spawn_root_and_wait( root, root.prefix().next );
00622     }
00623 
00625 
00627     static void spawn_root_and_wait( task_list& root_list );
00628 
00630 
00631     void wait_for_all() {
00632         prefix().owner->wait_for_all( *this, NULL );
00633     }
00634 
00635 #if __TBB_ARENA_PER_MASTER
00637     static void enqueue( task& t ) {
00638         t.prefix().owner->enqueue( t, NULL );
00639     }
00640 
00641 #endif /* __TBB_ARENA_PER_MASTER */
00643     static task& __TBB_EXPORTED_FUNC self();
00644 
00646     task* parent() const {return prefix().parent;}
00647 
00648 #if __TBB_TASK_GROUP_CONTEXT
00650     task_group_context* context() {return prefix().context;}
00651 #endif /* __TBB_TASK_GROUP_CONTEXT */   
00652 
00654     bool is_stolen_task() const {
00655         return (prefix().extra_state & 0x80)!=0;
00656     }
00657 
00658     //------------------------------------------------------------------------
00659     // Debugging
00660     //------------------------------------------------------------------------
00661 
00663     state_type state() const {return state_type(prefix().state);}
00664 
00666     int ref_count() const {
00667 #if TBB_USE_ASSERT
00668         internal::reference_count ref_count_ = prefix().ref_count;
00669         __TBB_ASSERT( ref_count_==int(ref_count_), "integer overflow error");
00670 #endif
00671         return int(prefix().ref_count);
00672     }
00673 
00675     bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const;
00676 
00677     //------------------------------------------------------------------------
00678     // Affinity
00679     //------------------------------------------------------------------------
00680  
00682 
00683     typedef internal::affinity_id affinity_id;
00684 
00686     void set_affinity( affinity_id id ) {prefix().affinity = id;}
00687 
00689     affinity_id affinity() const {return prefix().affinity;}
00690 
00692 
00696     virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id );
00697 
00698 #if __TBB_TASK_GROUP_CONTEXT
00700 
00701     bool cancel_group_execution () { return prefix().context->cancel_group_execution(); }
00702 
00704     bool is_cancelled () const { return prefix().context->is_group_execution_cancelled(); }
00705 #endif /* __TBB_TASK_GROUP_CONTEXT */
00706 
00707 private:
00708     friend class interface5::internal::task_base;
00709     friend class task_list;
00710     friend class internal::scheduler;
00711     friend class internal::allocate_root_proxy;
00712 #if __TBB_TASK_GROUP_CONTEXT
00713     friend class internal::allocate_root_with_context_proxy;
00714 #endif /* __TBB_TASK_GROUP_CONTEXT */
00715     friend class internal::allocate_continuation_proxy;
00716     friend class internal::allocate_child_proxy;
00717     friend class internal::allocate_additional_child_of_proxy;
00718     
00720 
00721     internal::task_prefix& prefix( internal::version_tag* = NULL ) const {
00722         return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(this))[-1];
00723     }
00724 }; // class task
00725 
00727 
00728 class empty_task: public task {
00729     /*override*/ task* execute() {
00730         return NULL;
00731     }
00732 };
00733 
00735 
00737 class task_list: internal::no_copy {
00738 private:
00739     task* first;
00740     task** next_ptr;
00741     friend class task;
00742     friend class interface5::internal::task_base;
00743 public:
00745     task_list() : first(NULL), next_ptr(&first) {}
00746 
00748     ~task_list() {}
00749 
00751     bool empty() const {return !first;}
00752 
00754     void push_back( task& task ) {
00755         task.prefix().next = NULL;
00756         *next_ptr = &task;
00757         next_ptr = &task.prefix().next;
00758     }
00759 
00761     task& pop_front() {
00762         __TBB_ASSERT( !empty(), "attempt to pop item from empty task_list" );
00763         task* result = first;
00764         first = result->prefix().next;
00765         if( !first ) next_ptr = &first;
00766         return *result;
00767     }
00768 
00770     void clear() {
00771         first=NULL;
00772         next_ptr=&first;
00773     }
00774 };
00775 
00776 inline void interface5::internal::task_base::spawn( task& t ) {
00777     t.prefix().owner->spawn( t, t.prefix().next );
00778 }
00779 
00780 inline void interface5::internal::task_base::spawn( task_list& list ) {
00781     if( task* t = list.first ) {
00782         t->prefix().owner->spawn( *t, *list.next_ptr );
00783         list.clear();
00784     }
00785 }
00786 
00787 inline void task::spawn_root_and_wait( task_list& root_list ) {
00788     if( task* t = root_list.first ) {
00789         t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr );
00790         root_list.clear();
00791     }
00792 }
00793 
00794 } // namespace tbb
00795 
00796 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_proxy& ) {
00797     return &tbb::internal::allocate_root_proxy::allocate(bytes);
00798 }
00799 
00800 inline void operator delete( void* task, const tbb::internal::allocate_root_proxy& ) {
00801     tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task) );
00802 }
00803 
00804 #if __TBB_TASK_GROUP_CONTEXT
00805 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_with_context_proxy& p ) {
00806     return &p.allocate(bytes);
00807 }
00808 
00809 inline void operator delete( void* task, const tbb::internal::allocate_root_with_context_proxy& p ) {
00810     p.free( *static_cast<tbb::task*>(task) );
00811 }
00812 #endif /* __TBB_TASK_GROUP_CONTEXT */
00813 
00814 inline void *operator new( size_t bytes, const tbb::internal::allocate_continuation_proxy& p ) {
00815     return &p.allocate(bytes);
00816 }
00817 
00818 inline void operator delete( void* task, const tbb::internal::allocate_continuation_proxy& p ) {
00819     p.free( *static_cast<tbb::task*>(task) );
00820 }
00821 
00822 inline void *operator new( size_t bytes, const tbb::internal::allocate_child_proxy& p ) {
00823     return &p.allocate(bytes);
00824 }
00825 
00826 inline void operator delete( void* task, const tbb::internal::allocate_child_proxy& p ) {
00827     p.free( *static_cast<tbb::task*>(task) );
00828 }
00829 
00830 inline void *operator new( size_t bytes, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00831     return &p.allocate(bytes);
00832 }
00833 
00834 inline void operator delete( void* task, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00835     p.free( *static_cast<tbb::task*>(task) );
00836 }
00837 
00838 #endif /* __TBB_task_H */

Copyright © 2005-2010 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.