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 #include <climits>
00027
00028 typedef struct ___itt_caller *__itt_caller;
00029
00030 namespace tbb {
00031
00032 class task;
00033 class task_list;
00034
00035 #if __TBB_TASK_GROUP_CONTEXT
00036 class task_group_context;
00037 #endif
00038
00039
00040
00041 #if _MSC_VER || (__GNUC__==3 && __GNUC_MINOR__<3)
00042 #define __TBB_TASK_BASE_ACCESS public
00043 #else
00044 #define __TBB_TASK_BASE_ACCESS private
00045 #endif
00046
00047 namespace internal {
00048
00049 class allocate_additional_child_of_proxy: no_assign {
00051 task* self;
00052 task& parent;
00053 public:
00054 explicit allocate_additional_child_of_proxy( task& parent_ ) : self(NULL), parent(parent_) {}
00055 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00056 void __TBB_EXPORTED_METHOD free( task& ) const;
00057 };
00058
00059 }
00060
00061 namespace interface5 {
00062 namespace internal {
00064
00069 class task_base: tbb::internal::no_copy {
00070 __TBB_TASK_BASE_ACCESS:
00071 friend class tbb::task;
00072
00074 static void spawn( task& t );
00075
00077 static void spawn( task_list& list );
00078
00080
00082 static tbb::internal::allocate_additional_child_of_proxy allocate_additional_child_of( task& t ) {
00083 return tbb::internal::allocate_additional_child_of_proxy(t);
00084 }
00085
00087
00091 static void __TBB_EXPORTED_FUNC destroy( task& victim );
00092 };
00093 }
00094 }
00095
00097 namespace internal {
00098
00099 class scheduler: no_copy {
00100 public:
00102 virtual void spawn( task& first, task*& next ) = 0;
00103
00105 virtual void wait_for_all( task& parent, task* child ) = 0;
00106
00108 virtual void spawn_root_and_wait( task& first, task*& next ) = 0;
00109
00111
00112 virtual ~scheduler() = 0;
00113
00115 virtual void enqueue( task& t, void* reserved ) = 0;
00116 };
00117
00119
00120 typedef intptr_t reference_count;
00121
00123 typedef unsigned short affinity_id;
00124
00125 #if __TBB_TASK_GROUP_CONTEXT
00126 class generic_scheduler;
00127
00128 struct context_list_node_t {
00129 context_list_node_t *my_prev,
00130 *my_next;
00131 };
00132
00133 class allocate_root_with_context_proxy: no_assign {
00134 task_group_context& my_context;
00135 public:
00136 allocate_root_with_context_proxy ( task_group_context& ctx ) : my_context(ctx) {}
00137 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00138 void __TBB_EXPORTED_METHOD free( task& ) const;
00139 };
00140 #endif
00141
00142 class allocate_root_proxy: no_assign {
00143 public:
00144 static task& __TBB_EXPORTED_FUNC allocate( size_t size );
00145 static void __TBB_EXPORTED_FUNC free( task& );
00146 };
00147
00148 class allocate_continuation_proxy: no_assign {
00149 public:
00150 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00151 void __TBB_EXPORTED_METHOD free( task& ) const;
00152 };
00153
00154 class allocate_child_proxy: no_assign {
00155 public:
00156 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00157 void __TBB_EXPORTED_METHOD free( task& ) const;
00158 };
00159
00161
00166 class task_prefix {
00167 private:
00168 friend class tbb::task;
00169 friend class tbb::interface5::internal::task_base;
00170 friend class tbb::task_list;
00171 friend class internal::scheduler;
00172 friend class internal::allocate_root_proxy;
00173 friend class internal::allocate_child_proxy;
00174 friend class internal::allocate_continuation_proxy;
00175 friend class internal::allocate_additional_child_of_proxy;
00176
00177 #if __TBB_TASK_GROUP_CONTEXT
00179
00182 task_group_context *context;
00183 #endif
00184
00186
00191 scheduler* origin;
00192
00193 #if TBB_PREVIEW_TASK_PRIORITY
00194 union {
00195 #endif
00197
00199 scheduler* owner;
00200
00201 #if TBB_PREVIEW_TASK_PRIORITY
00203
00204 task* next_offloaded;
00205 };
00206 #endif
00207
00209
00212 tbb::task* parent;
00213
00215
00219 reference_count ref_count;
00220
00222
00224 int depth;
00225
00227
00228 unsigned char state;
00229
00231
00236 unsigned char extra_state;
00237
00238 affinity_id affinity;
00239
00241 tbb::task* next;
00242
00244 tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);}
00245 };
00246
00247 }
00249
00250 #if __TBB_TASK_GROUP_CONTEXT
00251
00252 #if TBB_PREVIEW_TASK_PRIORITY
00253 namespace internal {
00254 static const int priority_stride_v4 = INT_MAX / 4;
00255 }
00256
00257 enum priority_t {
00258 priority_normal = internal::priority_stride_v4 * 2,
00259 priority_low = priority_normal - internal::priority_stride_v4,
00260 priority_high = priority_normal + internal::priority_stride_v4
00261 };
00262
00263 #endif
00264
00265 #if TBB_USE_CAPTURED_EXCEPTION
00266 class tbb_exception;
00267 #else
00268 namespace internal {
00269 class tbb_exception_ptr;
00270 }
00271 #endif
00272
00273 class task_scheduler_init;
00274
00276
00296 class task_group_context : internal::no_copy {
00297 private:
00298 friend class internal::generic_scheduler;
00299 friend class task_scheduler_init;
00300
00301 #if TBB_USE_CAPTURED_EXCEPTION
00302 typedef tbb_exception exception_container_type;
00303 #else
00304 typedef internal::tbb_exception_ptr exception_container_type;
00305 #endif
00306
00307 enum version_traits_word_layout {
00308 traits_offset = 16,
00309 version_mask = 0xFFFF,
00310 traits_mask = 0xFFFFul << traits_offset
00311 };
00312
00313 public:
00314 enum kind_type {
00315 isolated,
00316 bound
00317 };
00318
00319 enum traits_type {
00320 exact_exception = 0x0001ul << traits_offset,
00321 concurrent_wait = 0x0004ul << traits_offset,
00322 #if TBB_USE_CAPTURED_EXCEPTION
00323 default_traits = 0
00324 #else
00325 default_traits = exact_exception
00326 #endif
00327 };
00328
00329 private:
00330 enum state {
00331 may_have_children = 1
00332 };
00333
00334 union {
00336 kind_type my_kind;
00337 uintptr_t _my_kind_aligner;
00338 };
00339
00341 task_group_context *my_parent;
00342
00344
00346 internal::context_list_node_t my_node;
00347
00349 __itt_caller itt_caller;
00350
00352
00355 char _leading_padding[internal::NFS_MaxLineSize
00356 - 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal::context_list_node_t)
00357 - sizeof(__itt_caller)];
00358
00360 uintptr_t my_cancellation_requested;
00361
00363
00366 uintptr_t my_version_and_traits;
00367
00369 exception_container_type *my_exception;
00370
00372 internal::generic_scheduler *my_owner;
00373
00375 uintptr_t my_state;
00376
00377 #if TBB_PREVIEW_TASK_PRIORITY
00379 intptr_t my_priority;
00380 #endif
00381
00383
00384 char _trailing_padding[internal::NFS_MaxLineSize - 2 * sizeof(uintptr_t) - 2 * sizeof(void*)
00385 #if TBB_PREVIEW_TASK_PRIORITY
00386 - sizeof(intptr_t)
00387 #endif
00388 ];
00389
00390 public:
00392
00420 task_group_context ( kind_type relation_with_parent = bound,
00421 uintptr_t traits = default_traits )
00422 : my_kind(relation_with_parent)
00423 , my_version_and_traits(1 | traits)
00424 {
00425 init();
00426 }
00427
00428 __TBB_EXPORTED_METHOD ~task_group_context ();
00429
00431
00438 void __TBB_EXPORTED_METHOD reset ();
00439
00441
00448 bool __TBB_EXPORTED_METHOD cancel_group_execution ();
00449
00451 bool __TBB_EXPORTED_METHOD is_group_execution_cancelled () const;
00452
00454
00460 void __TBB_EXPORTED_METHOD register_pending_exception ();
00461
00462 #if TBB_PREVIEW_TASK_PRIORITY
00464 void set_priority ( priority_t );
00465
00467 priority_t priority () const;
00468 #endif
00469
00470 protected:
00472
00473 void __TBB_EXPORTED_METHOD init ();
00474
00475 private:
00476 friend class task;
00477 friend class internal::allocate_root_with_context_proxy;
00478
00479 static const kind_type binding_required = bound;
00480 static const kind_type binding_completed = kind_type(bound+1);
00481 static const kind_type detached = kind_type(binding_completed+1);
00482 static const kind_type dying = kind_type(detached+1);
00483
00485
00487 template <typename T>
00488 void propagate_state_from_ancestors ( T task_group_context::*mptr_state, T new_state );
00489
00491 inline void finish_initialization ( internal::generic_scheduler *local_sched );
00492
00494 void bind_to ( internal::generic_scheduler *local_sched );
00495
00497 void register_with ( internal::generic_scheduler *local_sched );
00498
00499 };
00500
00501 #endif
00502
00504
00505 class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base {
00506
00508 void __TBB_EXPORTED_METHOD internal_set_ref_count( int count );
00509
00511 internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_count();
00512
00513 protected:
00515 task() {prefix().extra_state=1;}
00516
00517 public:
00519 virtual ~task() {}
00520
00522 virtual task* execute() = 0;
00523
00525 enum state_type {
00527 executing,
00529 reexecute,
00531 ready,
00533 allocated,
00535 freed,
00537 recycle
00538 };
00539
00540
00541
00542
00543
00545 static internal::allocate_root_proxy allocate_root() {
00546 return internal::allocate_root_proxy();
00547 }
00548
00549 #if __TBB_TASK_GROUP_CONTEXT
00551 static internal::allocate_root_with_context_proxy allocate_root( task_group_context& ctx ) {
00552 return internal::allocate_root_with_context_proxy(ctx);
00553 }
00554 #endif
00555
00557
00558 internal::allocate_continuation_proxy& allocate_continuation() {
00559 return *reinterpret_cast<internal::allocate_continuation_proxy*>(this);
00560 }
00561
00563 internal::allocate_child_proxy& allocate_child() {
00564 return *reinterpret_cast<internal::allocate_child_proxy*>(this);
00565 }
00566
00568 using task_base::allocate_additional_child_of;
00569
00570 #if __TBB_DEPRECATED_TASK_INTERFACE
00572
00576 void __TBB_EXPORTED_METHOD destroy( task& t );
00577 #else
00579 using task_base::destroy;
00580 #endif
00581
00582
00583
00584
00585
00587
00593 void recycle_as_continuation() {
00594 __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00595 prefix().state = allocated;
00596 }
00597
00599
00601 void recycle_as_safe_continuation() {
00602 __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00603 prefix().state = recycle;
00604 }
00605
00607 void recycle_as_child_of( task& new_parent ) {
00608 internal::task_prefix& p = prefix();
00609 __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" );
00610 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled as a child" );
00611 __TBB_ASSERT( p.parent==NULL, "parent must be null" );
00612 __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" );
00613 __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already freed" );
00614 p.state = allocated;
00615 p.parent = &new_parent;
00616 #if __TBB_TASK_GROUP_CONTEXT
00617 p.context = new_parent.prefix().context;
00618 #endif
00619 }
00620
00622
00623 void recycle_to_reexecute() {
00624 __TBB_ASSERT( prefix().state==executing, "execute not running, or already recycled" );
00625 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled for reexecution" );
00626 prefix().state = reexecute;
00627 }
00628
00629
00630
00631 intptr_t depth() const {return 0;}
00632 void set_depth( intptr_t ) {}
00633 void add_to_depth( int ) {}
00634
00635
00636
00637
00638
00639
00641 void set_ref_count( int count ) {
00642 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00643 internal_set_ref_count(count);
00644 #else
00645 prefix().ref_count = count;
00646 #endif
00647 }
00648
00650
00651 void increment_ref_count() {
00652 __TBB_FetchAndIncrementWacquire( &prefix().ref_count );
00653 }
00654
00656
00657 int decrement_ref_count() {
00658 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00659 return int(internal_decrement_ref_count());
00660 #else
00661 return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))-1;
00662 #endif
00663 }
00664
00666 using task_base::spawn;
00667
00669 void spawn_and_wait_for_all( task& child ) {
00670 prefix().owner->wait_for_all( *this, &child );
00671 }
00672
00674 void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list );
00675
00677 static void spawn_root_and_wait( task& root ) {
00678 root.prefix().owner->spawn_root_and_wait( root, root.prefix().next );
00679 }
00680
00682
00684 static void spawn_root_and_wait( task_list& root_list );
00685
00687
00688 void wait_for_all() {
00689 prefix().owner->wait_for_all( *this, NULL );
00690 }
00691
00693 #if TBB_PREVIEW_TASK_PRIORITY
00694
00704 #endif
00705 static void enqueue( task& t ) {
00706 t.prefix().owner->enqueue( t, NULL );
00707 }
00708
00709 #if TBB_PREVIEW_TASK_PRIORITY
00711 static void enqueue( task& t, priority_t p ) {
00712 __TBB_ASSERT( p == priority_low || p == priority_normal || p == priority_high, "Invalid priority level value" );
00713 t.prefix().owner->enqueue( t, (void*)p );
00714 }
00715 #endif
00716
00718 static task& __TBB_EXPORTED_FUNC self();
00719
00721 task* parent() const {return prefix().parent;}
00722
00723 #if __TBB_TASK_GROUP_CONTEXT
00725
00726 task_group_context* context() {return prefix().context;}
00727
00729 task_group_context* group () { return prefix().context; }
00730 #endif
00731
00733 bool is_stolen_task() const {
00734 return (prefix().extra_state & 0x80)!=0;
00735 }
00736
00737
00738
00739
00740
00742 state_type state() const {return state_type(prefix().state);}
00743
00745 int ref_count() const {
00746 #if TBB_USE_ASSERT
00747 internal::reference_count ref_count_ = prefix().ref_count;
00748 __TBB_ASSERT( ref_count_==int(ref_count_), "integer overflow error");
00749 #endif
00750 return int(prefix().ref_count);
00751 }
00752
00754 bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const;
00755
00756
00757
00758
00759
00761
00762 typedef internal::affinity_id affinity_id;
00763
00765 void set_affinity( affinity_id id ) {prefix().affinity = id;}
00766
00768 affinity_id affinity() const {return prefix().affinity;}
00769
00771
00775 virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id );
00776
00777 #if __TBB_TASK_GROUP_CONTEXT
00779
00789 void __TBB_EXPORTED_METHOD change_group ( task_group_context& ctx );
00790
00792
00793 bool cancel_group_execution () { return prefix().context->cancel_group_execution(); }
00794
00796 bool is_cancelled () const { return prefix().context->is_group_execution_cancelled(); }
00797 #endif
00798
00799 #if TBB_PREVIEW_TASK_PRIORITY
00801 void set_group_priority ( priority_t p ) { prefix().context->set_priority(p); }
00802
00804 priority_t group_priority () const { return prefix().context->priority(); }
00805
00806 #endif
00807
00808 private:
00809 friend class interface5::internal::task_base;
00810 friend class task_list;
00811 friend class internal::scheduler;
00812 friend class internal::allocate_root_proxy;
00813 #if __TBB_TASK_GROUP_CONTEXT
00814 friend class internal::allocate_root_with_context_proxy;
00815 #endif
00816 friend class internal::allocate_continuation_proxy;
00817 friend class internal::allocate_child_proxy;
00818 friend class internal::allocate_additional_child_of_proxy;
00819
00821
00822 internal::task_prefix& prefix( internal::version_tag* = NULL ) const {
00823 return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(this))[-1];
00824 }
00825 };
00826
00828
00829 class empty_task: public task {
00830 task* execute() {
00831 return NULL;
00832 }
00833 };
00834
00836
00838 class task_list: internal::no_copy {
00839 private:
00840 task* first;
00841 task** next_ptr;
00842 friend class task;
00843 friend class interface5::internal::task_base;
00844 public:
00846 task_list() : first(NULL), next_ptr(&first) {}
00847
00849 ~task_list() {}
00850
00852 bool empty() const {return !first;}
00853
00855 void push_back( task& task ) {
00856 task.prefix().next = NULL;
00857 *next_ptr = &task;
00858 next_ptr = &task.prefix().next;
00859 }
00860
00862 task& pop_front() {
00863 __TBB_ASSERT( !empty(), "attempt to pop item from empty task_list" );
00864 task* result = first;
00865 first = result->prefix().next;
00866 if( !first ) next_ptr = &first;
00867 return *result;
00868 }
00869
00871 void clear() {
00872 first=NULL;
00873 next_ptr=&first;
00874 }
00875 };
00876
00877 inline void interface5::internal::task_base::spawn( task& t ) {
00878 t.prefix().owner->spawn( t, t.prefix().next );
00879 }
00880
00881 inline void interface5::internal::task_base::spawn( task_list& list ) {
00882 if( task* t = list.first ) {
00883 t->prefix().owner->spawn( *t, *list.next_ptr );
00884 list.clear();
00885 }
00886 }
00887
00888 inline void task::spawn_root_and_wait( task_list& root_list ) {
00889 if( task* t = root_list.first ) {
00890 t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr );
00891 root_list.clear();
00892 }
00893 }
00894
00895 }
00896
00897 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_proxy& ) {
00898 return &tbb::internal::allocate_root_proxy::allocate(bytes);
00899 }
00900
00901 inline void operator delete( void* task, const tbb::internal::allocate_root_proxy& ) {
00902 tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task) );
00903 }
00904
00905 #if __TBB_TASK_GROUP_CONTEXT
00906 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_with_context_proxy& p ) {
00907 return &p.allocate(bytes);
00908 }
00909
00910 inline void operator delete( void* task, const tbb::internal::allocate_root_with_context_proxy& p ) {
00911 p.free( *static_cast<tbb::task*>(task) );
00912 }
00913 #endif
00914
00915 inline void *operator new( size_t bytes, const tbb::internal::allocate_continuation_proxy& p ) {
00916 return &p.allocate(bytes);
00917 }
00918
00919 inline void operator delete( void* task, const tbb::internal::allocate_continuation_proxy& p ) {
00920 p.free( *static_cast<tbb::task*>(task) );
00921 }
00922
00923 inline void *operator new( size_t bytes, const tbb::internal::allocate_child_proxy& p ) {
00924 return &p.allocate(bytes);
00925 }
00926
00927 inline void operator delete( void* task, const tbb::internal::allocate_child_proxy& p ) {
00928 p.free( *static_cast<tbb::task*>(task) );
00929 }
00930
00931 inline void *operator new( size_t bytes, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00932 return &p.allocate(bytes);
00933 }
00934
00935 inline void operator delete( void* task, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00936 p.free( *static_cast<tbb::task*>(task) );
00937 }
00938
00939 #endif