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
00195 scheduler* owner;
00196
00198
00201 tbb::task* parent;
00202
00204
00208 reference_count ref_count;
00209
00211
00213 int depth;
00214
00216
00217 unsigned char state;
00218
00220
00225 unsigned char extra_state;
00226
00227 affinity_id affinity;
00228
00230 tbb::task* next;
00231
00233 tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);}
00234 };
00235
00236 }
00238
00239 #if __TBB_TASK_GROUP_CONTEXT
00240
00241 #if TBB_USE_CAPTURED_EXCEPTION
00242 class tbb_exception;
00243 #else
00244 namespace internal {
00245 class tbb_exception_ptr;
00246 }
00247 #endif
00248
00250
00270 class task_group_context : internal::no_copy {
00271 private:
00272 #if TBB_USE_CAPTURED_EXCEPTION
00273 typedef tbb_exception exception_container_type;
00274 #else
00275 typedef internal::tbb_exception_ptr exception_container_type;
00276 #endif
00277
00278 enum version_traits_word_layout {
00279 traits_offset = 16,
00280 version_mask = 0xFFFF,
00281 traits_mask = 0xFFFFul << traits_offset
00282 };
00283
00284 public:
00285 enum kind_type {
00286 isolated,
00287 bound
00288 };
00289
00290 enum traits_type {
00291 exact_exception = 0x0001ul << traits_offset,
00292 concurrent_wait = 0x0004ul << traits_offset,
00293 #if TBB_USE_CAPTURED_EXCEPTION
00294 default_traits = 0
00295 #else
00296 default_traits = exact_exception
00297 #endif
00298 };
00299
00300 private:
00301 union {
00303 kind_type my_kind;
00304 uintptr_t _my_kind_aligner;
00305 };
00306
00308 task_group_context *my_parent;
00309
00311
00313 internal::context_list_node_t my_node;
00314
00316 __itt_caller itt_caller;
00317
00319
00322 char _leading_padding[internal::NFS_MaxLineSize -
00323 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal::context_list_node_t)
00324 - sizeof(__itt_caller)];
00325
00327 uintptr_t my_cancellation_requested;
00328
00330
00333 uintptr_t my_version_and_traits;
00334
00336 exception_container_type *my_exception;
00337
00339
00342 void *my_owner;
00343
00345
00346 char _trailing_padding[internal::NFS_MaxLineSize - sizeof(intptr_t) - 2 * sizeof(void*)];
00347
00348 public:
00350
00377 task_group_context ( kind_type relation_with_parent = bound,
00378 uintptr_t traits = default_traits )
00379 : my_kind(relation_with_parent)
00380 , my_version_and_traits(1 | traits)
00381 {
00382 init();
00383 }
00384
00385 __TBB_EXPORTED_METHOD ~task_group_context ();
00386
00388
00395 void __TBB_EXPORTED_METHOD reset ();
00396
00398
00405 bool __TBB_EXPORTED_METHOD cancel_group_execution ();
00406
00408 bool __TBB_EXPORTED_METHOD is_group_execution_cancelled () const;
00409
00411
00417 void __TBB_EXPORTED_METHOD register_pending_exception ();
00418
00419 protected:
00421
00422 void __TBB_EXPORTED_METHOD init ();
00423
00424 private:
00425 friend class task;
00426 friend class internal::allocate_root_with_context_proxy;
00427
00428 static const kind_type binding_required = bound;
00429 static const kind_type binding_completed = kind_type(bound+1);
00430 static const kind_type detached = kind_type(binding_completed+1);
00431 static const kind_type dying = kind_type(detached+1);
00432
00435 void propagate_cancellation_from_ancestors ();
00436
00437 };
00438
00439 #endif
00440
00442
00443 class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base {
00444
00446 void __TBB_EXPORTED_METHOD internal_set_ref_count( int count );
00447
00449 internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_count();
00450
00451 protected:
00453 task() {prefix().extra_state=1;}
00454
00455 public:
00457 virtual ~task() {}
00458
00460 virtual task* execute() = 0;
00461
00463 enum state_type {
00465 executing,
00467 reexecute,
00469 ready,
00471 allocated,
00473 freed,
00475 recycle
00476 };
00477
00478
00479
00480
00481
00483 static internal::allocate_root_proxy allocate_root() {
00484 return internal::allocate_root_proxy();
00485 }
00486
00487 #if __TBB_TASK_GROUP_CONTEXT
00489 static internal::allocate_root_with_context_proxy allocate_root( task_group_context& ctx ) {
00490 return internal::allocate_root_with_context_proxy(ctx);
00491 }
00492 #endif
00493
00495
00496 internal::allocate_continuation_proxy& allocate_continuation() {
00497 return *reinterpret_cast<internal::allocate_continuation_proxy*>(this);
00498 }
00499
00501 internal::allocate_child_proxy& allocate_child() {
00502 return *reinterpret_cast<internal::allocate_child_proxy*>(this);
00503 }
00504
00506 using task_base::allocate_additional_child_of;
00507
00508 #if __TBB_DEPRECATED_TASK_INTERFACE
00510
00514 void __TBB_EXPORTED_METHOD destroy( task& t );
00515 #else
00517 using task_base::destroy;
00518 #endif
00519
00520
00521
00522
00523
00525
00531 void recycle_as_continuation() {
00532 __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00533 prefix().state = allocated;
00534 }
00535
00537
00539 void recycle_as_safe_continuation() {
00540 __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00541 prefix().state = recycle;
00542 }
00543
00545 void recycle_as_child_of( task& new_parent ) {
00546 internal::task_prefix& p = prefix();
00547 __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" );
00548 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled as a child" );
00549 __TBB_ASSERT( p.parent==NULL, "parent must be null" );
00550 __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" );
00551 __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already freed" );
00552 p.state = allocated;
00553 p.parent = &new_parent;
00554 #if __TBB_TASK_GROUP_CONTEXT
00555 p.context = new_parent.prefix().context;
00556 #endif
00557 }
00558
00560
00561 void recycle_to_reexecute() {
00562 __TBB_ASSERT( prefix().state==executing, "execute not running, or already recycled" );
00563 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled for reexecution" );
00564 prefix().state = reexecute;
00565 }
00566
00567
00568
00569 intptr_t depth() const {return 0;}
00570 void set_depth( intptr_t ) {}
00571 void add_to_depth( int ) {}
00572
00573
00574
00575
00576
00577
00579 void set_ref_count( int count ) {
00580 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00581 internal_set_ref_count(count);
00582 #else
00583 prefix().ref_count = count;
00584 #endif
00585 }
00586
00588
00589 void increment_ref_count() {
00590 __TBB_FetchAndIncrementWacquire( &prefix().ref_count );
00591 }
00592
00594
00595 int decrement_ref_count() {
00596 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00597 return int(internal_decrement_ref_count());
00598 #else
00599 return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))-1;
00600 #endif
00601 }
00602
00604 using task_base::spawn;
00605
00607 void spawn_and_wait_for_all( task& child ) {
00608 prefix().owner->wait_for_all( *this, &child );
00609 }
00610
00612 void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list );
00613
00615 static void spawn_root_and_wait( task& root ) {
00616 root.prefix().owner->spawn_root_and_wait( root, root.prefix().next );
00617 }
00618
00620
00622 static void spawn_root_and_wait( task_list& root_list );
00623
00625
00626 void wait_for_all() {
00627 prefix().owner->wait_for_all( *this, NULL );
00628 }
00629
00630 #if __TBB_ARENA_PER_MASTER
00632 static void enqueue( task& t ) {
00633 t.prefix().owner->enqueue( t, NULL );
00634 }
00635
00636 #endif
00637
00639 static task& __TBB_EXPORTED_FUNC self();
00640
00642 task* parent() const {return prefix().parent;}
00643
00644 #if __TBB_TASK_GROUP_CONTEXT
00646 task_group_context* context() {return prefix().context;}
00647 #endif
00648
00650 bool is_stolen_task() const {
00651 return (prefix().extra_state & 0x80)!=0;
00652 }
00653
00654
00655
00656
00657
00659 state_type state() const {return state_type(prefix().state);}
00660
00662 int ref_count() const {
00663 #if TBB_USE_ASSERT
00664 internal::reference_count ref_count_ = prefix().ref_count;
00665 __TBB_ASSERT( ref_count_==int(ref_count_), "integer overflow error");
00666 #endif
00667 return int(prefix().ref_count);
00668 }
00669
00671 bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const;
00672
00673
00674
00675
00676
00678
00679 typedef internal::affinity_id affinity_id;
00680
00682 void set_affinity( affinity_id id ) {prefix().affinity = id;}
00683
00685 affinity_id affinity() const {return prefix().affinity;}
00686
00688
00692 virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id );
00693
00694 #if __TBB_TASK_GROUP_CONTEXT
00696
00697 bool cancel_group_execution () { return prefix().context->cancel_group_execution(); }
00698
00700 bool is_cancelled () const { return prefix().context->is_group_execution_cancelled(); }
00701 #endif
00702
00703 private:
00704 friend class interface5::internal::task_base;
00705 friend class task_list;
00706 friend class internal::scheduler;
00707 friend class internal::allocate_root_proxy;
00708 #if __TBB_TASK_GROUP_CONTEXT
00709 friend class internal::allocate_root_with_context_proxy;
00710 #endif
00711 friend class internal::allocate_continuation_proxy;
00712 friend class internal::allocate_child_proxy;
00713 friend class internal::allocate_additional_child_of_proxy;
00714
00716
00717 internal::task_prefix& prefix( internal::version_tag* = NULL ) const {
00718 return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(this))[-1];
00719 }
00720 };
00721
00723
00724 class empty_task: public task {
00725 task* execute() {
00726 return NULL;
00727 }
00728 };
00729
00731
00733 class task_list: internal::no_copy {
00734 private:
00735 task* first;
00736 task** next_ptr;
00737 friend class task;
00738 friend class interface5::internal::task_base;
00739 public:
00741 task_list() : first(NULL), next_ptr(&first) {}
00742
00744 ~task_list() {}
00745
00747 bool empty() const {return !first;}
00748
00750 void push_back( task& task ) {
00751 task.prefix().next = NULL;
00752 *next_ptr = &task;
00753 next_ptr = &task.prefix().next;
00754 }
00755
00757 task& pop_front() {
00758 __TBB_ASSERT( !empty(), "attempt to pop item from empty task_list" );
00759 task* result = first;
00760 first = result->prefix().next;
00761 if( !first ) next_ptr = &first;
00762 return *result;
00763 }
00764
00766 void clear() {
00767 first=NULL;
00768 next_ptr=&first;
00769 }
00770 };
00771
00772 inline void interface5::internal::task_base::spawn( task& t ) {
00773 t.prefix().owner->spawn( t, t.prefix().next );
00774 }
00775
00776 inline void interface5::internal::task_base::spawn( task_list& list ) {
00777 if( task* t = list.first ) {
00778 t->prefix().owner->spawn( *t, *list.next_ptr );
00779 list.clear();
00780 }
00781 }
00782
00783 inline void task::spawn_root_and_wait( task_list& root_list ) {
00784 if( task* t = root_list.first ) {
00785 t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr );
00786 root_list.clear();
00787 }
00788 }
00789
00790 }
00791
00792 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_proxy& ) {
00793 return &tbb::internal::allocate_root_proxy::allocate(bytes);
00794 }
00795
00796 inline void operator delete( void* task, const tbb::internal::allocate_root_proxy& ) {
00797 tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task) );
00798 }
00799
00800 #if __TBB_TASK_GROUP_CONTEXT
00801 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_with_context_proxy& p ) {
00802 return &p.allocate(bytes);
00803 }
00804
00805 inline void operator delete( void* task, const tbb::internal::allocate_root_with_context_proxy& p ) {
00806 p.free( *static_cast<tbb::task*>(task) );
00807 }
00808 #endif
00809
00810 inline void *operator new( size_t bytes, const tbb::internal::allocate_continuation_proxy& p ) {
00811 return &p.allocate(bytes);
00812 }
00813
00814 inline void operator delete( void* task, const tbb::internal::allocate_continuation_proxy& p ) {
00815 p.free( *static_cast<tbb::task*>(task) );
00816 }
00817
00818 inline void *operator new( size_t bytes, const tbb::internal::allocate_child_proxy& p ) {
00819 return &p.allocate(bytes);
00820 }
00821
00822 inline void operator delete( void* task, const tbb::internal::allocate_child_proxy& p ) {
00823 p.free( *static_cast<tbb::task*>(task) );
00824 }
00825
00826 inline void *operator new( size_t bytes, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00827 return &p.allocate(bytes);
00828 }
00829
00830 inline void operator delete( void* task, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00831 p.free( *static_cast<tbb::task*>(task) );
00832 }
00833
00834 #endif