00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 #ifndef __TBB_task_H 00030 #define __TBB_task_H 00031 00032 #include "tbb_stddef.h" 00033 #include "tbb_machine.h" 00034 00035 typedef struct ___itt_caller *__itt_caller; 00036 00037 namespace tbb { 00038 00039 class task; 00040 class task_list; 00041 00042 #if __TBB_TASK_GROUP_CONTEXT 00043 class task_group_context; 00044 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00045 00046 // MSVC does not allow taking the address of a member that was defined 00047 // privately in task_base and made public in class task via a using declaration. 00048 #if _MSC_VER || (__GNUC__==3 && __GNUC_MINOR__<3) 00049 #define __TBB_TASK_BASE_ACCESS public 00050 #else 00051 #define __TBB_TASK_BASE_ACCESS private 00052 #endif 00053 00054 namespace internal { 00055 00056 class allocate_additional_child_of_proxy: no_assign { 00058 task* self; 00059 task& parent; 00060 public: 00061 explicit allocate_additional_child_of_proxy( task& parent_ ) : self(NULL), parent(parent_) {} 00062 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; 00063 void __TBB_EXPORTED_METHOD free( task& ) const; 00064 }; 00065 00066 } 00067 00068 namespace interface5 { 00069 namespace internal { 00071 00076 class task_base: tbb::internal::no_copy { 00077 __TBB_TASK_BASE_ACCESS: 00078 friend class tbb::task; 00079 00081 static void spawn( task& t ); 00082 00084 static void spawn( task_list& list ); 00085 00087 00089 static tbb::internal::allocate_additional_child_of_proxy allocate_additional_child_of( task& t ) { 00090 return tbb::internal::allocate_additional_child_of_proxy(t); 00091 } 00092 00094 00098 static void __TBB_EXPORTED_FUNC destroy( task& victim ); 00099 }; 00100 } // internal 00101 } // interface5 00102 00104 namespace internal { 00105 00106 class scheduler: no_copy { 00107 public: 00109 virtual void spawn( task& first, task*& next ) = 0; 00110 00112 virtual void wait_for_all( task& parent, task* child ) = 0; 00113 00115 virtual void spawn_root_and_wait( task& first, task*& next ) = 0; 00116 00118 // Have to have it just to shut up overzealous compilation warnings 00119 virtual ~scheduler() = 0; 00120 #if __TBB_ARENA_PER_MASTER 00121 00123 virtual void enqueue( task& t, void* reserved ) = 0; 00124 #endif /* __TBB_ARENA_PER_MASTER */ 00125 }; 00126 00128 00129 typedef intptr_t reference_count; 00130 00132 typedef unsigned short affinity_id; 00133 00134 #if __TBB_TASK_GROUP_CONTEXT 00135 struct context_list_node_t { 00136 context_list_node_t *my_prev, 00137 *my_next; 00138 }; 00139 00140 class allocate_root_with_context_proxy: no_assign { 00141 task_group_context& my_context; 00142 public: 00143 allocate_root_with_context_proxy ( task_group_context& ctx ) : my_context(ctx) {} 00144 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; 00145 void __TBB_EXPORTED_METHOD free( task& ) const; 00146 }; 00147 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00148 00149 class allocate_root_proxy: no_assign { 00150 public: 00151 static task& __TBB_EXPORTED_FUNC allocate( size_t size ); 00152 static void __TBB_EXPORTED_FUNC free( task& ); 00153 }; 00154 00155 class allocate_continuation_proxy: no_assign { 00156 public: 00157 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; 00158 void __TBB_EXPORTED_METHOD free( task& ) const; 00159 }; 00160 00161 class allocate_child_proxy: no_assign { 00162 public: 00163 task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; 00164 void __TBB_EXPORTED_METHOD free( task& ) const; 00165 }; 00166 00168 00173 class task_prefix { 00174 private: 00175 friend class tbb::task; 00176 friend class tbb::interface5::internal::task_base; 00177 friend class tbb::task_list; 00178 friend class internal::scheduler; 00179 friend class internal::allocate_root_proxy; 00180 friend class internal::allocate_child_proxy; 00181 friend class internal::allocate_continuation_proxy; 00182 friend class internal::allocate_additional_child_of_proxy; 00183 00184 #if __TBB_TASK_GROUP_CONTEXT 00185 00186 00189 task_group_context *context; 00190 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00191 00193 00198 scheduler* origin; 00199 00201 scheduler* owner; 00202 00204 00207 tbb::task* parent; 00208 00210 00214 reference_count ref_count; 00215 00217 00218 int depth; 00219 00221 00222 unsigned char state; 00223 00225 00230 unsigned char extra_state; 00231 00232 affinity_id affinity; 00233 00235 tbb::task* next; 00236 00238 tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);} 00239 }; 00240 00241 } // namespace internal 00243 00244 #if __TBB_TASK_GROUP_CONTEXT 00245 00246 #if TBB_USE_CAPTURED_EXCEPTION 00247 class tbb_exception; 00248 #else 00249 namespace internal { 00250 class tbb_exception_ptr; 00251 } 00252 #endif /* !TBB_USE_CAPTURED_EXCEPTION */ 00253 00255 00275 class task_group_context : internal::no_copy { 00276 private: 00277 #if TBB_USE_CAPTURED_EXCEPTION 00278 typedef tbb_exception exception_container_type; 00279 #else 00280 typedef internal::tbb_exception_ptr exception_container_type; 00281 #endif 00282 00283 enum version_traits_word_layout { 00284 traits_offset = 16, 00285 version_mask = 0xFFFF, 00286 traits_mask = 0xFFFFul << traits_offset 00287 }; 00288 00289 public: 00290 enum kind_type { 00291 isolated, 00292 bound 00293 }; 00294 00295 enum traits_type { 00296 exact_exception = 0x0001ul << traits_offset, 00297 concurrent_wait = 0x0004ul << traits_offset, 00298 #if TBB_USE_CAPTURED_EXCEPTION 00299 default_traits = 0 00300 #else 00301 default_traits = exact_exception 00302 #endif /* !TBB_USE_CAPTURED_EXCEPTION */ 00303 }; 00304 00305 private: 00306 union { 00308 kind_type my_kind; 00309 uintptr_t _my_kind_aligner; 00310 }; 00311 00313 task_group_context *my_parent; 00314 00316 00318 internal::context_list_node_t my_node; 00319 00321 __itt_caller itt_caller; 00322 00324 00327 char _leading_padding[internal::NFS_MaxLineSize - 00328 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal::context_list_node_t) 00329 - sizeof(__itt_caller)]; 00330 00332 uintptr_t my_cancellation_requested; 00333 00335 00338 uintptr_t my_version_and_traits; 00339 00341 exception_container_type *my_exception; 00342 00344 00347 void *my_owner; 00348 00350 00351 char _trailing_padding[internal::NFS_MaxLineSize - sizeof(intptr_t) - 2 * sizeof(void*)]; 00352 00353 public: 00355 00382 task_group_context ( kind_type relation_with_parent = bound, 00383 uintptr_t traits = default_traits ) 00384 : my_kind(relation_with_parent) 00385 , my_version_and_traits(1 | traits) 00386 { 00387 init(); 00388 } 00389 00390 __TBB_EXPORTED_METHOD ~task_group_context (); 00391 00393 00400 void __TBB_EXPORTED_METHOD reset (); 00401 00403 00410 bool __TBB_EXPORTED_METHOD cancel_group_execution (); 00411 00413 bool __TBB_EXPORTED_METHOD is_group_execution_cancelled () const; 00414 00416 00422 void __TBB_EXPORTED_METHOD register_pending_exception (); 00423 00424 protected: 00426 00427 void __TBB_EXPORTED_METHOD init (); 00428 00429 private: 00430 friend class task; 00431 friend class internal::allocate_root_with_context_proxy; 00432 00433 static const kind_type binding_required = bound; 00434 static const kind_type binding_completed = kind_type(bound+1); 00435 static const kind_type detached = kind_type(binding_completed+1); 00436 static const kind_type dying = kind_type(detached+1); 00437 00440 void propagate_cancellation_from_ancestors (); 00441 00443 bool is_alive () { 00444 #if TBB_USE_DEBUG 00445 return my_version_and_traits != 0xDeadBeef; 00446 #else 00447 return true; 00448 #endif /* TBB_USE_DEBUG */ 00449 } 00450 }; // class task_group_context 00451 00452 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00453 00455 00456 class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base { 00457 00459 void __TBB_EXPORTED_METHOD internal_set_ref_count( int count ); 00460 00462 internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_count(); 00463 00464 protected: 00466 task() {prefix().extra_state=1;} 00467 00468 public: 00470 virtual ~task() {} 00471 00473 virtual task* execute() = 0; 00474 00476 enum state_type { 00478 executing, 00480 reexecute, 00482 ready, 00484 allocated, 00486 freed, 00488 recycle 00489 }; 00490 00491 //------------------------------------------------------------------------ 00492 // Allocating tasks 00493 //------------------------------------------------------------------------ 00494 00496 static internal::allocate_root_proxy allocate_root() { 00497 return internal::allocate_root_proxy(); 00498 } 00499 00500 #if __TBB_TASK_GROUP_CONTEXT 00501 00502 static internal::allocate_root_with_context_proxy allocate_root( task_group_context& ctx ) { 00503 return internal::allocate_root_with_context_proxy(ctx); 00504 } 00505 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00506 00508 00509 internal::allocate_continuation_proxy& allocate_continuation() { 00510 return *reinterpret_cast<internal::allocate_continuation_proxy*>(this); 00511 } 00512 00514 internal::allocate_child_proxy& allocate_child() { 00515 return *reinterpret_cast<internal::allocate_child_proxy*>(this); 00516 } 00517 00519 using task_base::allocate_additional_child_of; 00520 00521 #if __TBB_DEPRECATED_TASK_INTERFACE 00522 00523 00527 void __TBB_EXPORTED_METHOD destroy( task& t ); 00528 #else /* !__TBB_DEPRECATED_TASK_INTERFACE */ 00529 00530 using task_base::destroy; 00531 #endif /* !__TBB_DEPRECATED_TASK_INTERFACE */ 00532 00533 //------------------------------------------------------------------------ 00534 // Recycling of tasks 00535 //------------------------------------------------------------------------ 00536 00538 00544 void recycle_as_continuation() { 00545 __TBB_ASSERT( prefix().state==executing, "execute not running?" ); 00546 prefix().state = allocated; 00547 } 00548 00550 00552 void recycle_as_safe_continuation() { 00553 __TBB_ASSERT( prefix().state==executing, "execute not running?" ); 00554 prefix().state = recycle; 00555 } 00556 00558 void recycle_as_child_of( task& new_parent ) { 00559 internal::task_prefix& p = prefix(); 00560 __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" ); 00561 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled as a child" ); 00562 __TBB_ASSERT( p.parent==NULL, "parent must be null" ); 00563 __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" ); 00564 __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already freed" ); 00565 p.state = allocated; 00566 p.parent = &new_parent; 00567 #if __TBB_TASK_GROUP_CONTEXT 00568 p.context = new_parent.prefix().context; 00569 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00570 } 00571 00573 00574 void recycle_to_reexecute() { 00575 __TBB_ASSERT( prefix().state==executing, "execute not running, or already recycled" ); 00576 __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled for reexecution" ); 00577 prefix().state = reexecute; 00578 } 00579 00580 // All depth-related methods are obsolete, and are retained for the sake 00581 // of backward source compatibility only 00582 intptr_t depth() const {return 0;} 00583 void set_depth( intptr_t ) {} 00584 void add_to_depth( int ) {} 00585 00586 00587 //------------------------------------------------------------------------ 00588 // Spawning and blocking 00589 //------------------------------------------------------------------------ 00590 00592 void set_ref_count( int count ) { 00593 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT 00594 internal_set_ref_count(count); 00595 #else 00596 prefix().ref_count = count; 00597 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */ 00598 } 00599 00601 00602 void increment_ref_count() { 00603 __TBB_FetchAndIncrementWacquire( &prefix().ref_count ); 00604 } 00605 00607 00608 int decrement_ref_count() { 00609 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT 00610 return int(internal_decrement_ref_count()); 00611 #else 00612 return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))-1; 00613 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */ 00614 } 00615 00617 using task_base::spawn; 00618 00620 void spawn_and_wait_for_all( task& child ) { 00621 prefix().owner->wait_for_all( *this, &child ); 00622 } 00623 00625 void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list ); 00626 00628 static void spawn_root_and_wait( task& root ) { 00629 root.prefix().owner->spawn_root_and_wait( root, root.prefix().next ); 00630 } 00631 00633 00635 static void spawn_root_and_wait( task_list& root_list ); 00636 00638 00639 void wait_for_all() { 00640 prefix().owner->wait_for_all( *this, NULL ); 00641 } 00642 00643 #if __TBB_ARENA_PER_MASTER 00644 00645 static void enqueue( task& t ) { 00646 t.prefix().owner->enqueue( t, NULL ); 00647 } 00648 00649 #endif /* __TBB_ARENA_PER_MASTER */ 00650 00651 static task& __TBB_EXPORTED_FUNC self(); 00652 00654 task* parent() const {return prefix().parent;} 00655 00656 #if __TBB_TASK_GROUP_CONTEXT 00657 00658 task_group_context* context() {return prefix().context;} 00659 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00660 00662 bool is_stolen_task() const { 00663 return (prefix().extra_state & 0x80)!=0; 00664 } 00665 00666 //------------------------------------------------------------------------ 00667 // Debugging 00668 //------------------------------------------------------------------------ 00669 00671 state_type state() const {return state_type(prefix().state);} 00672 00674 int ref_count() const { 00675 #if TBB_USE_ASSERT 00676 internal::reference_count ref_count_ = prefix().ref_count; 00677 __TBB_ASSERT( ref_count_==int(ref_count_), "integer overflow error"); 00678 #endif 00679 return int(prefix().ref_count); 00680 } 00681 00683 bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const; 00684 00685 //------------------------------------------------------------------------ 00686 // Affinity 00687 //------------------------------------------------------------------------ 00688 00690 00691 typedef internal::affinity_id affinity_id; 00692 00694 void set_affinity( affinity_id id ) {prefix().affinity = id;} 00695 00697 affinity_id affinity() const {return prefix().affinity;} 00698 00700 00704 virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id ); 00705 00706 #if __TBB_TASK_GROUP_CONTEXT 00707 00708 00709 bool cancel_group_execution () { return prefix().context->cancel_group_execution(); } 00710 00712 bool is_cancelled () const { return prefix().context->is_group_execution_cancelled(); } 00713 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00714 00715 private: 00716 friend class interface5::internal::task_base; 00717 friend class task_list; 00718 friend class internal::scheduler; 00719 friend class internal::allocate_root_proxy; 00720 #if __TBB_TASK_GROUP_CONTEXT 00721 friend class internal::allocate_root_with_context_proxy; 00722 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00723 friend class internal::allocate_continuation_proxy; 00724 friend class internal::allocate_child_proxy; 00725 friend class internal::allocate_additional_child_of_proxy; 00726 00728 00729 internal::task_prefix& prefix( internal::version_tag* = NULL ) const { 00730 return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(this))[-1]; 00731 } 00732 }; // class task 00733 00735 00736 class empty_task: public task { 00737 /*override*/ task* execute() { 00738 return NULL; 00739 } 00740 }; 00741 00743 00745 class task_list: internal::no_copy { 00746 private: 00747 task* first; 00748 task** next_ptr; 00749 friend class task; 00750 friend class interface5::internal::task_base; 00751 public: 00753 task_list() : first(NULL), next_ptr(&first) {} 00754 00756 ~task_list() {} 00757 00759 bool empty() const {return !first;} 00760 00762 void push_back( task& task ) { 00763 task.prefix().next = NULL; 00764 *next_ptr = &task; 00765 next_ptr = &task.prefix().next; 00766 } 00767 00769 task& pop_front() { 00770 __TBB_ASSERT( !empty(), "attempt to pop item from empty task_list" ); 00771 task* result = first; 00772 first = result->prefix().next; 00773 if( !first ) next_ptr = &first; 00774 return *result; 00775 } 00776 00778 void clear() { 00779 first=NULL; 00780 next_ptr=&first; 00781 } 00782 }; 00783 00784 inline void interface5::internal::task_base::spawn( task& t ) { 00785 t.prefix().owner->spawn( t, t.prefix().next ); 00786 } 00787 00788 inline void interface5::internal::task_base::spawn( task_list& list ) { 00789 if( task* t = list.first ) { 00790 t->prefix().owner->spawn( *t, *list.next_ptr ); 00791 list.clear(); 00792 } 00793 } 00794 00795 inline void task::spawn_root_and_wait( task_list& root_list ) { 00796 if( task* t = root_list.first ) { 00797 t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr ); 00798 root_list.clear(); 00799 } 00800 } 00801 00802 } // namespace tbb 00803 00804 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_proxy& ) { 00805 return &tbb::internal::allocate_root_proxy::allocate(bytes); 00806 } 00807 00808 inline void operator delete( void* task, const tbb::internal::allocate_root_proxy& ) { 00809 tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task) ); 00810 } 00811 00812 #if __TBB_TASK_GROUP_CONTEXT 00813 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_with_context_proxy& p ) { 00814 return &p.allocate(bytes); 00815 } 00816 00817 inline void operator delete( void* task, const tbb::internal::allocate_root_with_context_proxy& p ) { 00818 p.free( *static_cast<tbb::task*>(task) ); 00819 } 00820 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00821 00822 inline void *operator new( size_t bytes, const tbb::internal::allocate_continuation_proxy& p ) { 00823 return &p.allocate(bytes); 00824 } 00825 00826 inline void operator delete( void* task, const tbb::internal::allocate_continuation_proxy& p ) { 00827 p.free( *static_cast<tbb::task*>(task) ); 00828 } 00829 00830 inline void *operator new( size_t bytes, const tbb::internal::allocate_child_proxy& p ) { 00831 return &p.allocate(bytes); 00832 } 00833 00834 inline void operator delete( void* task, const tbb::internal::allocate_child_proxy& p ) { 00835 p.free( *static_cast<tbb::task*>(task) ); 00836 } 00837 00838 inline void *operator new( size_t bytes, const tbb::internal::allocate_additional_child_of_proxy& p ) { 00839 return &p.allocate(bytes); 00840 } 00841 00842 inline void operator delete( void* task, const tbb::internal::allocate_additional_child_of_proxy& p ) { 00843 p.free( *static_cast<tbb::task*>(task) ); 00844 } 00845 00846 #endif /* __TBB_task_H */
Copyright © 2005-2010 Intel Corporation. All Rights Reserved.
Licensed under the GNU General Public License 2 with the runtime exception.
Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.
* Other names and brands may be claimed as the property of others.
