task.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# 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.