00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00037
00038
00039
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 }
00093 }
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
00111 virtual ~scheduler() = 0;
00112 #if __TBB_ARENA_PER_MASTER
00113
00115 virtual void enqueue( task& t, void* reserved ) = 0;
00116 #endif
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
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
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 }
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
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
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
00441 }
00442 };
00443
00444 #endif
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
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
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
00522 using task_base::destroy;
00523 #endif
00524
00525
00526
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
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
00573
00574 intptr_t depth() const {return 0;}
00575 void set_depth( intptr_t ) {}
00576 void add_to_depth( int ) {}
00577
00578
00579
00580
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
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
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
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
00652
00654 bool is_stolen_task() const {
00655 return (prefix().extra_state & 0x80)!=0;
00656 }
00657
00658
00659
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
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
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
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 };
00725
00727
00728 class empty_task: public task {
00729 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 }
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
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