task.h

00001 /*
00002     Copyright 2005-2010 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 typedef struct ___itt_caller *__itt_caller;
00028 
00029 namespace tbb {
00030 
00031 class task;
00032 class task_list;
00033 
00034 #if __TBB_TASK_GROUP_CONTEXT
00035 class task_group_context;
00036 #endif /* __TBB_TASK_GROUP_CONTEXT */
00037 
00038 // MSVC does not allow taking the address of a member that was defined 
00039 // privately in task_base and made public in class task via a using declaration.
00040 #if _MSC_VER || (__GNUC__==3 && __GNUC_MINOR__<3)
00041 #define __TBB_TASK_BASE_ACCESS public
00042 #else
00043 #define __TBB_TASK_BASE_ACCESS private
00044 #endif
00045 
00046 namespace internal {
00047 
00048     class allocate_additional_child_of_proxy: no_assign {
00050         task* self;
00051         task& parent;
00052     public:
00053         explicit allocate_additional_child_of_proxy( task& parent_ ) : self(NULL), parent(parent_) {}
00054         task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00055         void __TBB_EXPORTED_METHOD free( task& ) const;
00056     };
00057 
00058 }
00059 
00060 namespace interface5 {
00061     namespace internal {
00063 
00068         class task_base: tbb::internal::no_copy {
00069         __TBB_TASK_BASE_ACCESS:
00070             friend class tbb::task;
00071 
00073             static void spawn( task& t );
00074  
00076             static void spawn( task_list& list );
00077 
00079 
00081             static tbb::internal::allocate_additional_child_of_proxy allocate_additional_child_of( task& t ) {
00082                 return tbb::internal::allocate_additional_child_of_proxy(t);
00083             }
00084 
00086 
00090             static void __TBB_EXPORTED_FUNC destroy( task& victim );
00091         }; 
00092     } // internal
00093 } // interface5
00094 
00096 namespace internal {
00097 
00098     class scheduler: no_copy {
00099     public:
00101         virtual void spawn( task& first, task*& next ) = 0;
00102 
00104         virtual void wait_for_all( task& parent, task* child ) = 0;
00105 
00107         virtual void spawn_root_and_wait( task& first, task*& next ) = 0;
00108 
00110         //  Have to have it just to shut up overzealous compilation warnings
00111         virtual ~scheduler() = 0;
00112 #if __TBB_ARENA_PER_MASTER
00113 
00115         virtual void enqueue( task& t, void* reserved ) = 0;
00116 #endif /* __TBB_ARENA_PER_MASTER */
00117     };
00118 
00120 
00121     typedef intptr_t reference_count;
00122 
00124     typedef unsigned short affinity_id;
00125 
00126 #if __TBB_TASK_GROUP_CONTEXT
00127     struct context_list_node_t {
00128         context_list_node_t *my_prev,
00129                             *my_next;
00130     };
00131 
00132     class allocate_root_with_context_proxy: no_assign {
00133         task_group_context& my_context;
00134     public:
00135         allocate_root_with_context_proxy ( task_group_context& ctx ) : my_context(ctx) {}
00136         task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00137         void __TBB_EXPORTED_METHOD free( task& ) const;
00138     };
00139 #endif /* __TBB_TASK_GROUP_CONTEXT */
00140 
00141     class allocate_root_proxy: no_assign {
00142     public:
00143         static task& __TBB_EXPORTED_FUNC allocate( size_t size );
00144         static void __TBB_EXPORTED_FUNC free( task& );
00145     };
00146 
00147     class allocate_continuation_proxy: no_assign {
00148     public:
00149         task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00150         void __TBB_EXPORTED_METHOD free( task& ) const;
00151     };
00152 
00153     class allocate_child_proxy: no_assign {
00154     public:
00155         task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
00156         void __TBB_EXPORTED_METHOD free( task& ) const;
00157     };
00158 
00160 
00165     class task_prefix {
00166     private:
00167         friend class tbb::task;
00168         friend class tbb::interface5::internal::task_base;
00169         friend class tbb::task_list;
00170         friend class internal::scheduler;
00171         friend class internal::allocate_root_proxy;
00172         friend class internal::allocate_child_proxy;
00173         friend class internal::allocate_continuation_proxy;
00174         friend class internal::allocate_additional_child_of_proxy;
00175 
00176 #if __TBB_TASK_GROUP_CONTEXT
00178 
00181         task_group_context  *context;
00182 #endif /* __TBB_TASK_GROUP_CONTEXT */
00183         
00185 
00190         scheduler* origin;
00191 
00193 
00195         scheduler* owner;
00196 
00198 
00201         tbb::task* parent;
00202 
00204 
00208         reference_count ref_count;
00209 
00211 
00213         int depth;
00214 
00216 
00217         unsigned char state;
00218 
00220 
00225         unsigned char extra_state;
00226 
00227         affinity_id affinity;
00228 
00230         tbb::task* next;
00231 
00233         tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);}
00234     };
00235 
00236 } // namespace internal
00238 
00239 #if __TBB_TASK_GROUP_CONTEXT
00240 
00241 #if TBB_USE_CAPTURED_EXCEPTION
00242     class tbb_exception;
00243 #else
00244     namespace internal {
00245         class tbb_exception_ptr;
00246     }
00247 #endif /* !TBB_USE_CAPTURED_EXCEPTION */
00248 
00250 
00270 class task_group_context : internal::no_copy {
00271 private:
00272 #if TBB_USE_CAPTURED_EXCEPTION
00273     typedef tbb_exception exception_container_type;
00274 #else
00275     typedef internal::tbb_exception_ptr exception_container_type;
00276 #endif
00277 
00278     enum version_traits_word_layout {
00279         traits_offset = 16,
00280         version_mask = 0xFFFF,
00281         traits_mask = 0xFFFFul << traits_offset
00282     };
00283 
00284 public:
00285     enum kind_type {
00286         isolated,
00287         bound
00288     };
00289 
00290     enum traits_type {
00291         exact_exception = 0x0001ul << traits_offset,
00292         concurrent_wait = 0x0004ul << traits_offset,
00293 #if TBB_USE_CAPTURED_EXCEPTION
00294         default_traits = 0
00295 #else
00296         default_traits = exact_exception
00297 #endif /* !TBB_USE_CAPTURED_EXCEPTION */
00298     };
00299 
00300 private:
00301     union {
00303         kind_type my_kind;
00304         uintptr_t _my_kind_aligner;
00305     };
00306 
00308     task_group_context *my_parent;
00309 
00311 
00313     internal::context_list_node_t my_node;
00314 
00316     __itt_caller itt_caller;
00317 
00319 
00322     char _leading_padding[internal::NFS_MaxLineSize - 
00323                     2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal::context_list_node_t)
00324                           - sizeof(__itt_caller)];
00325     
00327     uintptr_t my_cancellation_requested;
00328     
00330 
00333     uintptr_t  my_version_and_traits;
00334 
00336     exception_container_type *my_exception;
00337 
00339 
00342     void *my_owner;
00343 
00345 
00346     char _trailing_padding[internal::NFS_MaxLineSize - sizeof(intptr_t) - 2 * sizeof(void*)];
00347 
00348 public:
00350 
00377     task_group_context ( kind_type relation_with_parent = bound,
00378                          uintptr_t traits = default_traits )
00379         : my_kind(relation_with_parent)
00380         , my_version_and_traits(1 | traits)
00381     {
00382         init();
00383     }
00384 
00385     __TBB_EXPORTED_METHOD ~task_group_context ();
00386 
00388 
00395     void __TBB_EXPORTED_METHOD reset ();
00396 
00398 
00405     bool __TBB_EXPORTED_METHOD cancel_group_execution ();
00406 
00408     bool __TBB_EXPORTED_METHOD is_group_execution_cancelled () const;
00409 
00411 
00417     void __TBB_EXPORTED_METHOD register_pending_exception ();
00418 
00419 protected:
00421 
00422     void __TBB_EXPORTED_METHOD init ();
00423 
00424 private:
00425     friend class task;
00426     friend class internal::allocate_root_with_context_proxy;
00427 
00428     static const kind_type binding_required = bound;
00429     static const kind_type binding_completed = kind_type(bound+1);
00430     static const kind_type detached = kind_type(binding_completed+1);
00431     static const kind_type dying = kind_type(detached+1);
00432 
00435     void propagate_cancellation_from_ancestors ();
00436 
00437 }; // class task_group_context
00438 
00439 #endif /* __TBB_TASK_GROUP_CONTEXT */
00440 
00442 
00443 class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base {
00444 
00446     void __TBB_EXPORTED_METHOD internal_set_ref_count( int count );
00447 
00449     internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_count();
00450 
00451 protected:
00453     task() {prefix().extra_state=1;}
00454 
00455 public:
00457     virtual ~task() {}
00458 
00460     virtual task* execute() = 0;
00461 
00463     enum state_type {
00465         executing,
00467         reexecute,
00469         ready,
00471         allocated,
00473         freed,
00475         recycle 
00476     };
00477 
00478     //------------------------------------------------------------------------
00479     // Allocating tasks
00480     //------------------------------------------------------------------------
00481 
00483     static internal::allocate_root_proxy allocate_root() {
00484         return internal::allocate_root_proxy();
00485     }
00486 
00487 #if __TBB_TASK_GROUP_CONTEXT
00489     static internal::allocate_root_with_context_proxy allocate_root( task_group_context& ctx ) {
00490         return internal::allocate_root_with_context_proxy(ctx);
00491     }
00492 #endif /* __TBB_TASK_GROUP_CONTEXT */
00493 
00495 
00496     internal::allocate_continuation_proxy& allocate_continuation() {
00497         return *reinterpret_cast<internal::allocate_continuation_proxy*>(this);
00498     }
00499 
00501     internal::allocate_child_proxy& allocate_child() {
00502         return *reinterpret_cast<internal::allocate_child_proxy*>(this);
00503     }
00504 
00506     using task_base::allocate_additional_child_of;
00507 
00508 #if __TBB_DEPRECATED_TASK_INTERFACE
00510 
00514     void __TBB_EXPORTED_METHOD destroy( task& t );
00515 #else /* !__TBB_DEPRECATED_TASK_INTERFACE */
00517     using task_base::destroy;
00518 #endif /* !__TBB_DEPRECATED_TASK_INTERFACE */
00519 
00520     //------------------------------------------------------------------------
00521     // Recycling of tasks
00522     //------------------------------------------------------------------------
00523 
00525 
00531     void recycle_as_continuation() {
00532         __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00533         prefix().state = allocated;
00534     }
00535 
00537 
00539     void recycle_as_safe_continuation() {
00540         __TBB_ASSERT( prefix().state==executing, "execute not running?" );
00541         prefix().state = recycle;
00542     }
00543 
00545     void recycle_as_child_of( task& new_parent ) {
00546         internal::task_prefix& p = prefix();
00547         __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" );
00548         __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled as a child" );
00549         __TBB_ASSERT( p.parent==NULL, "parent must be null" );
00550         __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" );
00551         __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already freed" );
00552         p.state = allocated;
00553         p.parent = &new_parent;
00554 #if __TBB_TASK_GROUP_CONTEXT
00555         p.context = new_parent.prefix().context;
00556 #endif /* __TBB_TASK_GROUP_CONTEXT */
00557     }
00558 
00560 
00561     void recycle_to_reexecute() {
00562         __TBB_ASSERT( prefix().state==executing, "execute not running, or already recycled" );
00563         __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled for reexecution" );
00564         prefix().state = reexecute;
00565     }
00566 
00567     // All depth-related methods are obsolete, and are retained for the sake 
00568     // of backward source compatibility only
00569     intptr_t depth() const {return 0;}
00570     void set_depth( intptr_t ) {}
00571     void add_to_depth( int ) {}
00572 
00573 
00574     //------------------------------------------------------------------------
00575     // Spawning and blocking
00576     //------------------------------------------------------------------------
00577 
00579     void set_ref_count( int count ) {
00580 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00581         internal_set_ref_count(count);
00582 #else
00583         prefix().ref_count = count;
00584 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
00585     }
00586 
00588 
00589     void increment_ref_count() {
00590         __TBB_FetchAndIncrementWacquire( &prefix().ref_count );
00591     }
00592 
00594 
00595     int decrement_ref_count() {
00596 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
00597         return int(internal_decrement_ref_count());
00598 #else
00599         return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))-1;
00600 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
00601     }
00602 
00604     using task_base::spawn;
00605 
00607     void spawn_and_wait_for_all( task& child ) {
00608         prefix().owner->wait_for_all( *this, &child );
00609     }
00610 
00612     void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list );
00613 
00615     static void spawn_root_and_wait( task& root ) {
00616         root.prefix().owner->spawn_root_and_wait( root, root.prefix().next );
00617     }
00618 
00620 
00622     static void spawn_root_and_wait( task_list& root_list );
00623 
00625 
00626     void wait_for_all() {
00627         prefix().owner->wait_for_all( *this, NULL );
00628     }
00629 
00630 #if __TBB_ARENA_PER_MASTER
00632     static void enqueue( task& t ) {
00633         t.prefix().owner->enqueue( t, NULL );
00634     }
00635 
00636 #endif /* __TBB_ARENA_PER_MASTER */
00637 
00639     static task& __TBB_EXPORTED_FUNC self();
00640 
00642     task* parent() const {return prefix().parent;}
00643 
00644 #if __TBB_TASK_GROUP_CONTEXT
00646     task_group_context* context() {return prefix().context;}
00647 #endif /* __TBB_TASK_GROUP_CONTEXT */   
00648 
00650     bool is_stolen_task() const {
00651         return (prefix().extra_state & 0x80)!=0;
00652     }
00653 
00654     //------------------------------------------------------------------------
00655     // Debugging
00656     //------------------------------------------------------------------------
00657 
00659     state_type state() const {return state_type(prefix().state);}
00660 
00662     int ref_count() const {
00663 #if TBB_USE_ASSERT
00664         internal::reference_count ref_count_ = prefix().ref_count;
00665         __TBB_ASSERT( ref_count_==int(ref_count_), "integer overflow error");
00666 #endif
00667         return int(prefix().ref_count);
00668     }
00669 
00671     bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const;
00672 
00673     //------------------------------------------------------------------------
00674     // Affinity
00675     //------------------------------------------------------------------------
00676  
00678 
00679     typedef internal::affinity_id affinity_id;
00680 
00682     void set_affinity( affinity_id id ) {prefix().affinity = id;}
00683 
00685     affinity_id affinity() const {return prefix().affinity;}
00686 
00688 
00692     virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id );
00693 
00694 #if __TBB_TASK_GROUP_CONTEXT
00696 
00697     bool cancel_group_execution () { return prefix().context->cancel_group_execution(); }
00698 
00700     bool is_cancelled () const { return prefix().context->is_group_execution_cancelled(); }
00701 #endif /* __TBB_TASK_GROUP_CONTEXT */
00702 
00703 private:
00704     friend class interface5::internal::task_base;
00705     friend class task_list;
00706     friend class internal::scheduler;
00707     friend class internal::allocate_root_proxy;
00708 #if __TBB_TASK_GROUP_CONTEXT
00709     friend class internal::allocate_root_with_context_proxy;
00710 #endif /* __TBB_TASK_GROUP_CONTEXT */
00711     friend class internal::allocate_continuation_proxy;
00712     friend class internal::allocate_child_proxy;
00713     friend class internal::allocate_additional_child_of_proxy;
00714     
00716 
00717     internal::task_prefix& prefix( internal::version_tag* = NULL ) const {
00718         return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(this))[-1];
00719     }
00720 }; // class task
00721 
00723 
00724 class empty_task: public task {
00725     /*override*/ task* execute() {
00726         return NULL;
00727     }
00728 };
00729 
00731 
00733 class task_list: internal::no_copy {
00734 private:
00735     task* first;
00736     task** next_ptr;
00737     friend class task;
00738     friend class interface5::internal::task_base;
00739 public:
00741     task_list() : first(NULL), next_ptr(&first) {}
00742 
00744     ~task_list() {}
00745 
00747     bool empty() const {return !first;}
00748 
00750     void push_back( task& task ) {
00751         task.prefix().next = NULL;
00752         *next_ptr = &task;
00753         next_ptr = &task.prefix().next;
00754     }
00755 
00757     task& pop_front() {
00758         __TBB_ASSERT( !empty(), "attempt to pop item from empty task_list" );
00759         task* result = first;
00760         first = result->prefix().next;
00761         if( !first ) next_ptr = &first;
00762         return *result;
00763     }
00764 
00766     void clear() {
00767         first=NULL;
00768         next_ptr=&first;
00769     }
00770 };
00771 
00772 inline void interface5::internal::task_base::spawn( task& t ) {
00773     t.prefix().owner->spawn( t, t.prefix().next );
00774 }
00775 
00776 inline void interface5::internal::task_base::spawn( task_list& list ) {
00777     if( task* t = list.first ) {
00778         t->prefix().owner->spawn( *t, *list.next_ptr );
00779         list.clear();
00780     }
00781 }
00782 
00783 inline void task::spawn_root_and_wait( task_list& root_list ) {
00784     if( task* t = root_list.first ) {
00785         t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr );
00786         root_list.clear();
00787     }
00788 }
00789 
00790 } // namespace tbb
00791 
00792 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_proxy& ) {
00793     return &tbb::internal::allocate_root_proxy::allocate(bytes);
00794 }
00795 
00796 inline void operator delete( void* task, const tbb::internal::allocate_root_proxy& ) {
00797     tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task) );
00798 }
00799 
00800 #if __TBB_TASK_GROUP_CONTEXT
00801 inline void *operator new( size_t bytes, const tbb::internal::allocate_root_with_context_proxy& p ) {
00802     return &p.allocate(bytes);
00803 }
00804 
00805 inline void operator delete( void* task, const tbb::internal::allocate_root_with_context_proxy& p ) {
00806     p.free( *static_cast<tbb::task*>(task) );
00807 }
00808 #endif /* __TBB_TASK_GROUP_CONTEXT */
00809 
00810 inline void *operator new( size_t bytes, const tbb::internal::allocate_continuation_proxy& p ) {
00811     return &p.allocate(bytes);
00812 }
00813 
00814 inline void operator delete( void* task, const tbb::internal::allocate_continuation_proxy& p ) {
00815     p.free( *static_cast<tbb::task*>(task) );
00816 }
00817 
00818 inline void *operator new( size_t bytes, const tbb::internal::allocate_child_proxy& p ) {
00819     return &p.allocate(bytes);
00820 }
00821 
00822 inline void operator delete( void* task, const tbb::internal::allocate_child_proxy& p ) {
00823     p.free( *static_cast<tbb::task*>(task) );
00824 }
00825 
00826 inline void *operator new( size_t bytes, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00827     return &p.allocate(bytes);
00828 }
00829 
00830 inline void operator delete( void* task, const tbb::internal::allocate_additional_child_of_proxy& p ) {
00831     p.free( *static_cast<tbb::task*>(task) );
00832 }
00833 
00834 #endif /* __TBB_task_H */

Copyright © 2005-2010 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.