00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __TBB_task_H
00030 #define __TBB_task_H
00031
00032 #include "tbb_stddef.h"
00033 #include "tbb_machine.h"
00034 #include <climits>
00035
00036 typedef struct ___itt_caller *__itt_caller;
00037
00038 namespace tbb {
00039
00040 class task;
00041 class task_list;
00042
00043 #if __TBB_TASK_GROUP_CONTEXT
00044 class task_group_context;
00045 #endif
00046
00047
00048
00049 #if _MSC_VER || (__GNUC__==3 && __GNUC_MINOR__<3)
00050 #define __TBB_TASK_BASE_ACCESS public
00051 #else
00052 #define __TBB_TASK_BASE_ACCESS private
00053 #endif
00054
00055 namespace internal {
00056
00057 class allocate_additional_child_of_proxy: no_assign {
00059 task* self;
00060 task& parent;
00061 public:
00062 explicit allocate_additional_child_of_proxy( task& parent_ ) : self(NULL), parent(parent_) {}
00063 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00064 void __TBB_EXPORTED_METHOD free( task& ) const;
00065 };
00066
00067 }
00068
00069 namespace interface5 {
00070 namespace internal {
00072
00077 class task_base: tbb::internal::no_copy {
00078 __TBB_TASK_BASE_ACCESS:
00079 friend class tbb::task;
00080
00082 static void spawn( task& t );
00083
00085 static void spawn( task_list& list );
00086
00088
00090 static tbb::internal::allocate_additional_child_of_proxy allocate_additional_child_of( task& t ) {
00091 return tbb::internal::allocate_additional_child_of_proxy(t);
00092 }
00093
00095
00099 static void __TBB_EXPORTED_FUNC destroy( task& victim );
00100 };
00101 }
00102 }
00103
00105 namespace internal {
00106
00107 class scheduler: no_copy {
00108 public:
00110 virtual void spawn( task& first, task*& next ) = 0;
00111
00113 virtual void wait_for_all( task& parent, task* child ) = 0;
00114
00116 virtual void spawn_root_and_wait( task& first, task*& next ) = 0;
00117
00119
00120 virtual ~scheduler() = 0;
00121
00123 virtual void enqueue( task& t, void* reserved ) = 0;
00124 };
00125
00127
00128 typedef intptr_t reference_count;
00129
00131 typedef unsigned short affinity_id;
00132
00133 #if __TBB_TASK_GROUP_CONTEXT
00134 class generic_scheduler;
00135
00136 struct context_list_node_t {
00137 context_list_node_t *my_prev,
00138 *my_next;
00139 };
00140
00141 class allocate_root_with_context_proxy: no_assign {
00142 task_group_context& my_context;
00143 public:
00144 allocate_root_with_context_proxy ( task_group_context& ctx ) : my_context(ctx) {}
00145 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00146 void __TBB_EXPORTED_METHOD free( task& ) const;
00147 };
00148 #endif
00149
00150 class allocate_root_proxy: no_assign {
00151 public:
00152 static task& __TBB_EXPORTED_FUNC allocate( size_t size );
00153 static void __TBB_EXPORTED_FUNC free( task& );
00154 };
00155
00156 class allocate_continuation_proxy: no_assign {
00157 public:
00158 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00159 void __TBB_EXPORTED_METHOD free( task& ) const;
00160 };
00161
00162 class allocate_child_proxy: no_assign {
00163 public:
00164 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00165 void __TBB_EXPORTED_METHOD free( task& ) const;
00166 };
00167
00169
00180 class task_prefix {
00181 private:
00182 friend class tbb::task;
00183 friend class tbb::interface5::internal::task_base;
00184 friend class tbb::task_list;
00185 friend class internal::scheduler;
00186 friend class internal::allocate_root_proxy;
00187 friend class internal::allocate_child_proxy;
00188 friend class internal::allocate_continuation_proxy;
00189 friend class internal::allocate_additional_child_of_proxy;
00190
00191 #if __TBB_TASK_GROUP_CONTEXT
00193
00196 task_group_context *context;
00197 #endif
00198
00200
00205 scheduler* origin;
00206
00207 #if __TBB_TASK_PRIORITY
00208 union {
00209 #endif
00211
00213 scheduler* owner;
00214
00215 #if __TBB_TASK_PRIORITY
00217
00218 task* next_offloaded;
00219 };
00220 #endif
00221
00223
00226 tbb::task* parent;
00227
00229
00233 __TBB_atomic reference_count ref_count;
00234
00236
00238 int depth;
00239
00241
00242 unsigned char state;
00243
00245
00251 unsigned char extra_state;
00252
00253 affinity_id affinity;
00254
00256 tbb::task* next;
00257
00259 tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);}
00260 };
00261
00262 }
00264
00265 #if __TBB_TASK_GROUP_CONTEXT
00266
00267 #if __TBB_TASK_PRIORITY
00268 namespace internal {
00269 static const int priority_stride_v4 = INT_MAX / 4;
00270 }
00271
00272 enum priority_t {
00273 priority_normal = internal::priority_stride_v4 * 2,
00274 priority_low = priority_normal - internal::priority_stride_v4,
00275 priority_high = priority_normal + internal::priority_stride_v4
00276 };
00277
00278 #endif
00279
00280 #if TBB_USE_CAPTURED_EXCEPTION
00281 class tbb_exception;
00282 #else
00283 namespace internal {
00284 class tbb_exception_ptr;
00285 }
00286 #endif
00287
00288 class task_scheduler_init;
00289
00291
00311 class task_group_context : internal::no_copy {
00312 private:
00313 friend class internal::generic_scheduler;
00314 friend class task_scheduler_init;
00315
00316 #if TBB_USE_CAPTURED_EXCEPTION
00317 typedef tbb_exception exception_container_type;
00318 #else
00319 typedef internal::tbb_exception_ptr exception_container_type;
00320 #endif
00321
00322 enum version_traits_word_layout {
00323 traits_offset = 16,
00324 version_mask = 0xFFFF,
00325 traits_mask = 0xFFFFul << traits_offset
00326 };
00327
00328 public:
00329 enum kind_type {
00330 isolated,
00331 bound
00332 };
00333
00334 enum traits_type {
00335 exact_exception = 0x0001ul << traits_offset,
00336 concurrent_wait = 0x0004ul << traits_offset,
00337 #if TBB_USE_CAPTURED_EXCEPTION
00338 default_traits = 0
00339 #else
00340 default_traits = exact_exception
00341 #endif
00342 };
00343
00344 private:
00345 enum state {
00346 may_have_children = 1
00347 };
00348
00349 union {
00351 kind_type my_kind;
00352 uintptr_t _my_kind_aligner;
00353 };
00354
00356 task_group_context *my_parent;
00357
00359
00361 internal::context_list_node_t my_node;
00362
00364 __itt_caller itt_caller;
00365
00367
00370 char _leading_padding[internal::NFS_MaxLineSize
00371 - 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal::context_list_node_t)
00372 - sizeof(__itt_caller)];
00373
00375 uintptr_t my_cancellation_requested;
00376
00378
00381 uintptr_t my_version_and_traits;
00382
00384 exception_container_type *my_exception;
00385
00387 internal::generic_scheduler *my_owner;
00388
00390 uintptr_t my_state;
00391
00392 #if __TBB_TASK_PRIORITY
00394 intptr_t my_priority;
00395 #endif
00396
00398
00399 char _trailing_padding[internal::NFS_MaxLineSize - 2 * sizeof(uintptr_t) - 2 * sizeof(void*)
00400 #if __TBB_TASK_PRIORITY
00401 - sizeof(intptr_t)
00402 #endif
00403 ];
00404
00405 public:
00407
00435 task_group_context ( kind_type relation_with_parent = bound,
00436 uintptr_t traits = default_traits )
00437 : my_kind(relation_with_parent)
00438 , my_version_and_traits(1 | traits)
00439 {
00440 init();
00441 }
00442
00443 __TBB_EXPORTED_METHOD ~task_group_context ();
00444
00446
00453 void __TBB_EXPORTED_METHOD reset ();
00454
00456
00463 bool __TBB_EXPORTED_METHOD cancel_group_execution ();
00464
00466 bool __TBB_EXPORTED_METHOD is_group_execution_cancelled () const;
00467
00469
00475 void __TBB_EXPORTED_METHOD register_pending_exception ();
00476
00477 #if __TBB_TASK_PRIORITY
00479 void set_priority ( priority_t );
00480
00482 priority_t priority () const;
00483 #endif
00484
00485 protected:
00487
00488 void __TBB_EXPORTED_METHOD init ();
00489
00490 private:
00491 friend class task;
00492 friend class internal::allocate_root_with_context_proxy;
00493
00494 static const kind_type binding_required = bound;
00495 static const kind_type binding_completed = kind_type(bound+1);
00496 static const kind_type detached = kind_type(binding_completed+1);
00497 static const kind_type dying = kind_type(detached+1);
00498
00500
00502 template <typename T>
00503 void propagate_state_from_ancestors ( T task_group_context::*mptr_state, T new_state );
00504
00506 inline void finish_initialization ( internal::generic_scheduler *local_sched );
00507
00509 void bind_to ( internal::generic_scheduler *local_sched );
00510
00512 void register_with ( internal::generic_scheduler *local_sched );
00513
00514 };
00515
00516 #endif
00517
00519
00520 class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base {
00521
00523 void __TBB_EXPORTED_METHOD internal_set_ref_count( int count );
00524
00526 internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_count();
00527
00528 protected:
00530 task() {prefix().extra_state=1;}
00531
00532 public:
00534 virtual ~task() {}
00535
00537 virtual task* execute() = 0;
00538
00540 enum state_type {
00542 executing,
00544 reexecute,
00546 ready,
00548 allocated,
00550 freed,
00552 recycle
00553 };
00554
00555
00556
00557
00558
00560 static internal::allocate_root_proxy allocate_root() {
00561 return internal::allocate_root_proxy();
00562 }
00563
00564 #if __TBB_TASK_GROUP_CONTEXT
00566 static internal::allocate_root_with_context_proxy allocate_root( task_group_context& ctx ) {
00567 return internal::allocate_root_with_context_proxy(ctx);
00568 }
00569 #endif
00570
00572
00573 internal::allocate_continuation_proxy& allocate_continuation() {
00574 return *reinterpret_cast<internal::allocate_continuation_proxy*>(this);
00575 }
00576
00578 internal::allocate_child_proxy& allocate_child() {
00579 return *reinterpret_cast<internal::allocate_child_proxy*>(this);
00580 }
00581
00583 using task_base::allocate_additional_child_of;
00584
00585 #if __TBB_DEPRECATED_TASK_INTERFACE
00587
00591 void __TBB_EXPORTED_METHOD destroy( task& t );
00592 #else
00594 using task_base::destroy;
00595 #endif
00596
00597
00598
00599
00600
00602
00608 void recycle_as_continuation() {
00609 __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00610 prefix().state = allocated;
00611 }
00612
00614
00616 void recycle_as_safe_continuation() {
00617 __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00618 prefix().state = recycle;
00619 }
00620
00622 void recycle_as_child_of( task& new_parent ) {
00623 internal::task_prefix& p = prefix();
00624 __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" );
00625 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled as a child" );
00626 __TBB_ASSERT( p.parent==NULL, "parent must be null" );
00627 __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" );
00628 __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already freed" );
00629 p.state = allocated;
00630 p.parent = &new_parent;
00631 #if __TBB_TASK_GROUP_CONTEXT
00632 p.context = new_parent.prefix().context;
00633 #endif
00634 }
00635
00637
00638 void recycle_to_reexecute() {
00639 __TBB_ASSERT( prefix().state==executing, "execute not running, or already recycled" );
00640 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled for reexecution" );
00641 prefix().state = reexecute;
00642 }
00643
00644
00645
00646 intptr_t depth() const {return 0;}
00647 void set_depth( intptr_t ) {}
00648 void add_to_depth( int ) {}
00649
00650
00651
00652
00653
00654
00656 void set_ref_count( int count ) {
00657 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00658 internal_set_ref_count(count);
00659 #else
00660 prefix().ref_count = count;
00661 #endif
00662 }
00663
00665
00666 void increment_ref_count() {
00667 __TBB_FetchAndIncrementWacquire( &prefix().ref_count );
00668 }
00669
00671
00672 int decrement_ref_count() {
00673 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00674 return int(internal_decrement_ref_count());
00675 #else
00676 return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))-1;
00677 #endif
00678 }
00679
00681 using task_base::spawn;
00682
00684 void spawn_and_wait_for_all( task& child ) {
00685 prefix().owner->wait_for_all( *this, &child );
00686 }
00687
00689 void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list );
00690
00692 static void spawn_root_and_wait( task& root ) {
00693 root.prefix().owner->spawn_root_and_wait( root, root.prefix().next );
00694 }
00695
00697
00699 static void spawn_root_and_wait( task_list& root_list );
00700
00702
00703 void wait_for_all() {
00704 prefix().owner->wait_for_all( *this, NULL );
00705 }
00706
00708 #if __TBB_TASK_PRIORITY
00709
00719 #endif
00720 static void enqueue( task& t ) {
00721 t.prefix().owner->enqueue( t, NULL );
00722 }
00723
00724 #if __TBB_TASK_PRIORITY
00726 static void enqueue( task& t, priority_t p ) {
00727 __TBB_ASSERT( p == priority_low || p == priority_normal || p == priority_high, "Invalid priority level value" );
00728 t.prefix().owner->enqueue( t, (void*)p );
00729 }
00730 #endif
00731
00733 static task& __TBB_EXPORTED_FUNC self();
00734
00736 task* parent() const {return prefix().parent;}
00737
00739 void set_parent(task* p) {
00740 #if __TBB_TASK_GROUP_CONTEXT
00741 __TBB_ASSERT(prefix().context == p->prefix().context, "The tasks must be in the same context");
00742 #endif
00743 prefix().parent = p;
00744 }
00745
00746 #if __TBB_TASK_GROUP_CONTEXT
00748
00749 task_group_context* context() {return prefix().context;}
00750
00752 task_group_context* group () { return prefix().context; }
00753 #endif
00754
00756 bool is_stolen_task() const {
00757 return (prefix().extra_state & 0x80)!=0;
00758 }
00759
00760
00761
00762
00763
00765 state_type state() const {return state_type(prefix().state);}
00766
00768 int ref_count() const {
00769 #if TBB_USE_ASSERT
00770 internal::reference_count ref_count_ = prefix().ref_count;
00771 __TBB_ASSERT( ref_count_==int(ref_count_), "integer overflow error");
00772 #endif
00773 return int(prefix().ref_count);
00774 }
00775
00777 bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const;
00778
00779
00780
00781
00782
00784
00785 typedef internal::affinity_id affinity_id;
00786
00788 void set_affinity( affinity_id id ) {prefix().affinity = id;}
00789
00791 affinity_id affinity() const {return prefix().affinity;}
00792
00794
00798 virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id );
00799
00800 #if __TBB_TASK_GROUP_CONTEXT
00802
00812 void __TBB_EXPORTED_METHOD change_group ( task_group_context& ctx );
00813
00815
00816 bool cancel_group_execution () { return prefix().context->cancel_group_execution(); }
00817
00819 bool is_cancelled () const { return prefix().context->is_group_execution_cancelled(); }
00820 #else
00821 bool is_cancelled () const { return false; }
00822 #endif
00823
00824 #if __TBB_TASK_PRIORITY
00826 void set_group_priority ( priority_t p ) { prefix().context->set_priority(p); }
00827
00829 priority_t group_priority () const { return prefix().context->priority(); }
00830
00831 #endif
00832
00833 private:
00834 friend class interface5::internal::task_base;
00835 friend class task_list;
00836 friend class internal::scheduler;
00837 friend class internal::allocate_root_proxy;
00838 #if __TBB_TASK_GROUP_CONTEXT
00839 friend class internal::allocate_root_with_context_proxy;
00840 #endif
00841 friend class internal::allocate_continuation_proxy;
00842 friend class internal::allocate_child_proxy;
00843 friend class internal::allocate_additional_child_of_proxy;
00844
00846
00847 internal::task_prefix& prefix( internal::version_tag* = NULL ) const {
00848 return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(this))[-1];
00849 }
00850 };
00851
00853
00854 class empty_task: public task {
00855 task* execute() {
00856 return NULL;
00857 }
00858 };
00859
00861
00863 class task_list: internal::no_copy {
00864 private:
00865 task* first;
00866 task** next_ptr;
00867 friend class task;
00868 friend class interface5::internal::task_base;
00869 public:
00871 task_list() : first(NULL), next_ptr(&first) {}
00872
00874 ~task_list() {}
00875
00877 bool empty() const {return !first;}
00878
00880 void push_back( task& task ) {
00881 task.prefix().next = NULL;
00882 *next_ptr = &task;
00883 next_ptr = &task.prefix().next;
00884 }
00885
00887 task& pop_front() {
00888 __TBB_ASSERT( !empty(), "attempt to pop item from empty task_list" );
00889 task* result = first;
00890 first = result->prefix().next;
00891 if( !first ) next_ptr = &first;
00892 return *result;
00893 }
00894
00896 void clear() {
00897 first=NULL;
00898 next_ptr=&first;
00899 }
00900 };
00901
00902 inline void interface5::internal::task_base::spawn( task& t ) {
00903 t.prefix().owner->spawn( t, t.prefix().next );
00904 }
00905
00906 inline void interface5::internal::task_base::spawn( task_list& list ) {
00907 if( task* t = list.first ) {
00908 t->prefix().owner->spawn( *t, *list.next_ptr );
00909 list.clear();
00910 }
00911 }
00912
00913 inline void task::spawn_root_and_wait( task_list& root_list ) {
00914 if( task* t = root_list.first ) {
00915 t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr );
00916 root_list.clear();
00917 }
00918 }
00919
00920 }
00921
00922 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_proxy& ) {
00923 return &tbb::internal::allocate_root_proxy::allocate(bytes);
00924 }
00925
00926 inline void operator delete( void* task, const tbb::internal::allocate_root_proxy& ) {
00927 tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task) );
00928 }
00929
00930 #if __TBB_TASK_GROUP_CONTEXT
00931 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_with_context_proxy& p ) {
00932 return &p.allocate(bytes);
00933 }
00934
00935 inline void operator delete( void* task, const tbb::internal::allocate_root_with_context_proxy& p ) {
00936 p.free( *static_cast<tbb::task*>(task) );
00937 }
00938 #endif
00939
00940 inline void *operator new( size_t bytes, const tbb::internal::allocate_continuation_proxy& p ) {
00941 return &p.allocate(bytes);
00942 }
00943
00944 inline void operator delete( void* task, const tbb::internal::allocate_continuation_proxy& p ) {
00945 p.free( *static_cast<tbb::task*>(task) );
00946 }
00947
00948 inline void *operator new( size_t bytes, const tbb::internal::allocate_child_proxy& p ) {
00949 return &p.allocate(bytes);
00950 }
00951
00952 inline void operator delete( void* task, const tbb::internal::allocate_child_proxy& p ) {
00953 p.free( *static_cast<tbb::task*>(task) );
00954 }
00955
00956 inline void *operator new( size_t bytes, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00957 return &p.allocate(bytes);
00958 }
00959
00960 inline void operator delete( void* task, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00961 p.free( *static_cast<tbb::task*>(task) );
00962 }
00963
00964 #endif