task.h

00001 /*
00002     Copyright 2005-2009 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
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 /* __TBB_EXCEPTIONS */
00030 
00031 namespace tbb {
00032 
00033 class task;
00034 class task_list;
00035 
00036 #if __TBB_EXCEPTIONS
00037 class task_group_context;
00038 #endif /* __TBB_EXCEPTIONS */
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         //  Have to have it just to shut up overzealous compilation warnings
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 /* __TBB_EXCEPTIONS */
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 /* __TBB_EXCEPTIONS */
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 } // namespace internal
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 /* !TBB_USE_CAPTURED_EXCEPTION */
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 /* !TBB_USE_CAPTURED_EXCEPTION */
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 /* TBB_USE_DEBUG */
00387     }
00388 }; // class task_group_context
00389 
00390 #endif /* __TBB_EXCEPTIONS */
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     // Allocating tasks
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 /* __TBB_EXCEPTIONS */
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     // Recycling of tasks
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 /* __TBB_EXCEPTIONS */
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     // All depth-related methods are obsolete, and are retained for the sake 
00516     // of backward source compatibility only
00517     intptr_t depth() const {return 0;}
00518     void set_depth( intptr_t ) {}
00519     void add_to_depth( int ) {}
00520 
00521 
00522     //------------------------------------------------------------------------
00523     // Spawning and blocking
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 /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
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 /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
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 /* __TBB_EXCEPTIONS */   
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     // Debugging
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     // Affinity
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 /* __TBB_EXCEPTIONS */
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 /* __TBB_EXCEPTIONS */
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 }; // class task
00675 
00677 
00678 class empty_task: public task {
00679     /*override*/ 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 } // namespace tbb
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 /* __TBB_EXCEPTIONS */
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 /* __TBB_task_H */

Copyright © 2005-2009 Intel Corporation. All Rights Reserved.

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.