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 #if __TBB_EXCEPTIONS
00028 #include "cache_aligned_allocator.h"
00029 #endif
00030
00031 namespace tbb {
00032
00033 class task;
00034 class task_list;
00035
00036 #if __TBB_EXCEPTIONS
00037 class task_group_context;
00038 #endif
00039
00041 namespace internal {
00042
00043 class scheduler: no_copy {
00044 public:
00046 virtual void spawn( task& first, task*& next ) = 0;
00047
00049 virtual void wait_for_all( task& parent, task* child ) = 0;
00050
00052 virtual void spawn_root_and_wait( task& first, task*& next ) = 0;
00053
00055
00056 virtual ~scheduler() = 0;
00057 };
00058
00060
00061 typedef intptr reference_count;
00062
00064 typedef unsigned short affinity_id;
00065
00066 #if __TBB_EXCEPTIONS
00067 struct context_list_node_t {
00068 context_list_node_t *my_prev,
00069 *my_next;
00070 };
00071
00072 class allocate_root_with_context_proxy: no_assign {
00073 task_group_context& my_context;
00074 public:
00075 allocate_root_with_context_proxy ( task_group_context& ctx ) : my_context(ctx) {}
00076 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00077 void __TBB_EXPORTED_METHOD free( task& ) const;
00078 };
00079 #endif
00080
00081 class allocate_root_proxy: no_assign {
00082 public:
00083 static task& __TBB_EXPORTED_FUNC allocate( size_t size );
00084 static void __TBB_EXPORTED_FUNC free( task& );
00085 };
00086
00087 class allocate_continuation_proxy: no_assign {
00088 public:
00089 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00090 void __TBB_EXPORTED_METHOD free( task& ) const;
00091 };
00092
00093 class allocate_child_proxy: no_assign {
00094 public:
00095 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00096 void __TBB_EXPORTED_METHOD free( task& ) const;
00097 };
00098
00099 class allocate_additional_child_of_proxy: no_assign {
00100 task& self;
00101 task& parent;
00102 public:
00103 allocate_additional_child_of_proxy( task& self_, task& parent_ ) : self(self_), parent(parent_) {}
00104 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00105 void __TBB_EXPORTED_METHOD free( task& ) const;
00106 };
00107
00108 class task_group_base;
00109
00111
00116 class task_prefix {
00117 private:
00118 friend class tbb::task;
00119 friend class tbb::task_list;
00120 friend class internal::scheduler;
00121 friend class internal::allocate_root_proxy;
00122 friend class internal::allocate_child_proxy;
00123 friend class internal::allocate_continuation_proxy;
00124 friend class internal::allocate_additional_child_of_proxy;
00125 friend class internal::task_group_base;
00126
00127 #if __TBB_EXCEPTIONS
00129
00132 task_group_context *context;
00133 #endif
00134
00136
00141 scheduler* origin;
00142
00144 scheduler* owner;
00145
00147
00150 tbb::task* parent;
00151
00153
00157 reference_count ref_count;
00158
00160
00161 int depth;
00162
00164
00165 unsigned char state;
00166
00168
00172 unsigned char extra_state;
00173
00174 affinity_id affinity;
00175
00177 tbb::task* next;
00178
00180 tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);}
00181 };
00182
00183 }
00185
00186 #if __TBB_EXCEPTIONS
00187
00188 #if TBB_USE_CAPTURED_EXCEPTION
00189 class tbb_exception;
00190 #else
00191 namespace internal {
00192 class tbb_exception_ptr;
00193 }
00194 #endif
00195
00197
00217 class task_group_context : internal::no_copy
00218 {
00219 private:
00220 #if TBB_USE_CAPTURED_EXCEPTION
00221 typedef tbb_exception exception_container_type;
00222 #else
00223 typedef internal::tbb_exception_ptr exception_container_type;
00224 #endif
00225
00226 enum version_traits_word_layout {
00227 traits_offset = 16,
00228 version_mask = 0xFFFF,
00229 traits_mask = 0xFFFFul << traits_offset
00230 };
00231
00232 public:
00233 enum kind_type {
00234 isolated,
00235 bound
00236 };
00237
00238 enum traits_type {
00239 exact_exception = 0x0001ul << traits_offset,
00240 no_cancellation = 0x0002ul << traits_offset,
00241 concurrent_wait = 0x0004ul << traits_offset,
00242 #if TBB_USE_CAPTURED_EXCEPTION
00243 default_traits = 0
00244 #else
00245 default_traits = exact_exception
00246 #endif
00247 };
00248
00249 private:
00250 union {
00252 kind_type my_kind;
00253 uintptr_t _my_kind_aligner;
00254 };
00255
00257 task_group_context *my_parent;
00258
00260
00262 internal::context_list_node_t my_node;
00263
00265
00268 char _leading_padding[internal::NFS_MaxLineSize -
00269 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal::context_list_node_t)];
00270
00272 uintptr_t my_cancellation_requested;
00273
00275
00278 uintptr_t my_version_and_traits;
00279
00281 exception_container_type *my_exception;
00282
00284
00287 void *my_owner;
00288
00290
00291 char _trailing_padding[internal::NFS_MaxLineSize - sizeof(intptr_t) - 2 * sizeof(void*)];
00292
00293 public:
00295
00322 task_group_context ( kind_type relation_with_parent = bound,
00323 uintptr_t traits = default_traits )
00324 : my_kind(relation_with_parent)
00325 , my_version_and_traits(1 | traits)
00326 {
00327 init();
00328 }
00329
00330 __TBB_EXPORTED_METHOD ~task_group_context ();
00331
00333
00340 void __TBB_EXPORTED_METHOD reset ();
00341
00343
00350 bool __TBB_EXPORTED_METHOD cancel_group_execution ();
00351
00353 bool __TBB_EXPORTED_METHOD is_group_execution_cancelled () const;
00354
00356
00362 void __TBB_EXPORTED_METHOD register_pending_exception ();
00363
00364 protected:
00366
00367 void __TBB_EXPORTED_METHOD init ();
00368
00369 private:
00370 friend class task;
00371 friend class internal::allocate_root_with_context_proxy;
00372
00373 static const kind_type binding_required = bound;
00374 static const kind_type binding_completed = kind_type(bound+1);
00375
00378 void propagate_cancellation_from_ancestors ();
00379
00381 bool is_alive () {
00382 #if TBB_USE_DEBUG
00383 return my_version_and_traits != 0xDeadBeef;
00384 #else
00385 return true;
00386 #endif
00387 }
00388 };
00389
00390 #endif
00391
00393
00394 class task: internal::no_copy {
00396 void __TBB_EXPORTED_METHOD internal_set_ref_count( int count );
00397
00399 internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_count();
00400
00401 protected:
00403 task() {prefix().extra_state=1;}
00404
00405 public:
00407 virtual ~task() {}
00408
00410 virtual task* execute() = 0;
00411
00413 enum state_type {
00415 executing,
00417 reexecute,
00419 ready,
00421 allocated,
00423 freed,
00425 recycle
00426 };
00427
00428
00429
00430
00431
00433 static internal::allocate_root_proxy allocate_root() {
00434 return internal::allocate_root_proxy();
00435 }
00436
00437 #if __TBB_EXCEPTIONS
00439 static internal::allocate_root_with_context_proxy allocate_root( task_group_context& ctx ) {
00440 return internal::allocate_root_with_context_proxy(ctx);
00441 }
00442 #endif
00443
00445
00446 internal::allocate_continuation_proxy& allocate_continuation() {
00447 return *reinterpret_cast<internal::allocate_continuation_proxy*>(this);
00448 }
00449
00451 internal::allocate_child_proxy& allocate_child() {
00452 return *reinterpret_cast<internal::allocate_child_proxy*>(this);
00453 }
00454
00456
00458 internal::allocate_additional_child_of_proxy allocate_additional_child_of( task& t ) {
00459 return internal::allocate_additional_child_of_proxy(*this,t);
00460 }
00461
00463
00467 void __TBB_EXPORTED_METHOD destroy( task& victim );
00468
00469
00470
00471
00472
00474
00480 void recycle_as_continuation() {
00481 __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00482 prefix().state = allocated;
00483 }
00484
00486
00487 void recycle_as_safe_continuation() {
00488 __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00489 prefix().state = recycle;
00490 }
00491
00493 void recycle_as_child_of( task& new_parent ) {
00494 internal::task_prefix& p = prefix();
00495 __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" );
00496 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled as a child" );
00497 __TBB_ASSERT( p.parent==NULL, "parent must be null" );
00498 __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" );
00499 __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already freed" );
00500 p.state = allocated;
00501 p.parent = &new_parent;
00502 #if __TBB_EXCEPTIONS
00503 p.context = new_parent.prefix().context;
00504 #endif
00505 }
00506
00508
00509 void recycle_to_reexecute() {
00510 __TBB_ASSERT( prefix().state==executing, "execute not running, or already recycled" );
00511 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled for reexecution" );
00512 prefix().state = reexecute;
00513 }
00514
00515
00516
00517 intptr_t depth() const {return 0;}
00518 void set_depth( intptr_t ) {}
00519 void add_to_depth( int ) {}
00520
00521
00522
00523
00524
00525
00527 void set_ref_count( int count ) {
00528 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00529 internal_set_ref_count(count);
00530 #else
00531 prefix().ref_count = count;
00532 #endif
00533 }
00534
00536
00537 void increment_ref_count() {
00538 __TBB_FetchAndIncrementWacquire( &prefix().ref_count );
00539 }
00540
00542
00543 int decrement_ref_count() {
00544 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00545 return int(internal_decrement_ref_count());
00546 #else
00547 return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))-1;
00548 #endif
00549 }
00550
00552
00556 void spawn( task& child ) {
00557 prefix().owner->spawn( child, child.prefix().next );
00558 }
00559
00561 void spawn( task_list& list );
00562
00564 void spawn_and_wait_for_all( task& child ) {
00565 prefix().owner->wait_for_all( *this, &child );
00566 }
00567
00569 void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list );
00570
00572
00574 static void spawn_root_and_wait( task& root ) {
00575 root.prefix().owner->spawn_root_and_wait( root, root.prefix().next );
00576 }
00577
00579
00581 static void spawn_root_and_wait( task_list& root_list );
00582
00584
00585 void wait_for_all() {
00586 prefix().owner->wait_for_all( *this, NULL );
00587 }
00588
00590 static task& __TBB_EXPORTED_FUNC self();
00591
00593 task* parent() const {return prefix().parent;}
00594
00595 #if __TBB_EXCEPTIONS
00597 task_group_context* context() {return prefix().context;}
00598 #endif
00599
00601 bool is_stolen_task() const {
00602 internal::task_prefix& p = prefix();
00603 internal::task_prefix& q = parent()->prefix();
00604 return p.owner!=q.owner;
00605 }
00606
00607
00608
00609
00610
00612 state_type state() const {return state_type(prefix().state);}
00613
00615 int ref_count() const {
00616 #if TBB_USE_ASSERT
00617 internal::reference_count ref_count = prefix().ref_count;
00618 __TBB_ASSERT( ref_count==int(ref_count), "integer overflow error");
00619 #endif
00620 return int(prefix().ref_count);
00621 }
00622
00624 bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const;
00625
00626
00627
00628
00629
00631
00632 typedef internal::affinity_id affinity_id;
00633
00635 void set_affinity( affinity_id id ) {prefix().affinity = id;}
00636
00638 affinity_id affinity() const {return prefix().affinity;}
00639
00641
00645 virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id );
00646
00647 #if __TBB_EXCEPTIONS
00649
00650 bool cancel_group_execution () { return prefix().context->cancel_group_execution(); }
00651
00653 bool is_cancelled () const { return prefix().context->is_group_execution_cancelled(); }
00654 #endif
00655
00656 private:
00657 friend class task_list;
00658 friend class internal::scheduler;
00659 friend class internal::allocate_root_proxy;
00660 #if __TBB_EXCEPTIONS
00661 friend class internal::allocate_root_with_context_proxy;
00662 #endif
00663 friend class internal::allocate_continuation_proxy;
00664 friend class internal::allocate_child_proxy;
00665 friend class internal::allocate_additional_child_of_proxy;
00666
00667 friend class internal::task_group_base;
00668
00670
00671 internal::task_prefix& prefix( internal::version_tag* = NULL ) const {
00672 return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(this))[-1];
00673 }
00674 };
00675
00677
00678 class empty_task: public task {
00679 task* execute() {
00680 return NULL;
00681 }
00682 };
00683
00685
00687 class task_list: internal::no_copy {
00688 private:
00689 task* first;
00690 task** next_ptr;
00691 friend class task;
00692 public:
00694 task_list() : first(NULL), next_ptr(&first) {}
00695
00697 ~task_list() {}
00698
00700 bool empty() const {return !first;}
00701
00703 void push_back( task& task ) {
00704 task.prefix().next = NULL;
00705 *next_ptr = &task;
00706 next_ptr = &task.prefix().next;
00707 }
00708
00710 task& pop_front() {
00711 __TBB_ASSERT( !empty(), "attempt to pop item from empty task_list" );
00712 task* result = first;
00713 first = result->prefix().next;
00714 if( !first ) next_ptr = &first;
00715 return *result;
00716 }
00717
00719 void clear() {
00720 first=NULL;
00721 next_ptr=&first;
00722 }
00723 };
00724
00725 inline void task::spawn( task_list& list ) {
00726 if( task* t = list.first ) {
00727 prefix().owner->spawn( *t, *list.next_ptr );
00728 list.clear();
00729 }
00730 }
00731
00732 inline void task::spawn_root_and_wait( task_list& root_list ) {
00733 if( task* t = root_list.first ) {
00734 t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr );
00735 root_list.clear();
00736 }
00737 }
00738
00739 }
00740
00741 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_proxy& ) {
00742 return &tbb::internal::allocate_root_proxy::allocate(bytes);
00743 }
00744
00745 inline void operator delete( void* task, const tbb::internal::allocate_root_proxy& ) {
00746 tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task) );
00747 }
00748
00749 #if __TBB_EXCEPTIONS
00750 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_with_context_proxy& p ) {
00751 return &p.allocate(bytes);
00752 }
00753
00754 inline void operator delete( void* task, const tbb::internal::allocate_root_with_context_proxy& p ) {
00755 p.free( *static_cast<tbb::task*>(task) );
00756 }
00757 #endif
00758
00759 inline void *operator new( size_t bytes, const tbb::internal::allocate_continuation_proxy& p ) {
00760 return &p.allocate(bytes);
00761 }
00762
00763 inline void operator delete( void* task, const tbb::internal::allocate_continuation_proxy& p ) {
00764 p.free( *static_cast<tbb::task*>(task) );
00765 }
00766
00767 inline void *operator new( size_t bytes, const tbb::internal::allocate_child_proxy& p ) {
00768 return &p.allocate(bytes);
00769 }
00770
00771 inline void operator delete( void* task, const tbb::internal::allocate_child_proxy& p ) {
00772 p.free( *static_cast<tbb::task*>(task) );
00773 }
00774
00775 inline void *operator new( size_t bytes, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00776 return &p.allocate(bytes);
00777 }
00778
00779 inline void operator delete( void* task, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00780 p.free( *static_cast<tbb::task*>(task) );
00781 }
00782
00783 #endif