123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964 |
- /*
- Copyright 2005-2013 Intel Corporation. All Rights Reserved.
- This file is part of Threading Building Blocks.
- Threading Building Blocks is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public License
- version 2 as published by the Free Software Foundation.
- Threading Building Blocks is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Threading Building Blocks; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- As a special exception, you may use this file as part of a free software
- library without restriction. Specifically, if other files instantiate
- templates or use macros or inline functions from this file, or you compile
- this file and link it with other files to produce an executable, this
- file does not by itself cause the resulting executable to be covered by
- the GNU General Public License. This exception does not however
- invalidate any other reasons why the executable file might be covered by
- the GNU General Public License.
- */
- #ifndef __TBB_task_H
- #define __TBB_task_H
- #include "tbb_stddef.h"
- #include "tbb_machine.h"
- #include <climits>
- typedef struct ___itt_caller *__itt_caller;
- namespace tbb {
- class task;
- class task_list;
- #if __TBB_TASK_GROUP_CONTEXT
- class task_group_context;
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- // MSVC does not allow taking the address of a member that was defined
- // privately in task_base and made public in class task via a using declaration.
- #if _MSC_VER || (__GNUC__==3 && __GNUC_MINOR__<3)
- #define __TBB_TASK_BASE_ACCESS public
- #else
- #define __TBB_TASK_BASE_ACCESS private
- #endif
- namespace internal {
- class allocate_additional_child_of_proxy: no_assign {
- //! No longer used, but retained for binary layout compatibility. Always NULL.
- task* self;
- task& parent;
- public:
- explicit allocate_additional_child_of_proxy( task& parent_ ) : self(NULL), parent(parent_) {}
- task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
- void __TBB_EXPORTED_METHOD free( task& ) const;
- };
- }
- namespace interface5 {
- namespace internal {
- //! Base class for methods that became static in TBB 3.0.
- /** TBB's evolution caused the "this" argument for several methods to become obsolete.
- However, for backwards binary compatibility, the new methods need distinct names,
- otherwise the One Definition Rule would be broken. Hence the new methods are
- defined in this private base class, and then exposed in class task via
- using declarations. */
- class task_base: tbb::internal::no_copy {
- __TBB_TASK_BASE_ACCESS:
- friend class tbb::task;
- //! Schedule task for execution when a worker becomes available.
- static void spawn( task& t );
- //! Spawn multiple tasks and clear list.
- static void spawn( task_list& list );
- //! Like allocate_child, except that task's parent becomes "t", not this.
- /** Typically used in conjunction with schedule_to_reexecute to implement while loops.
- Atomically increments the reference count of t.parent() */
- static tbb::internal::allocate_additional_child_of_proxy allocate_additional_child_of( task& t ) {
- return tbb::internal::allocate_additional_child_of_proxy(t);
- }
- //! Destroy a task.
- /** Usually, calling this method is unnecessary, because a task is
- implicitly deleted after its execute() method runs. However,
- sometimes a task needs to be explicitly deallocated, such as
- when a root task is used as the parent in spawn_and_wait_for_all. */
- static void __TBB_EXPORTED_FUNC destroy( task& victim );
- };
- } // internal
- } // interface5
- //! @cond INTERNAL
- namespace internal {
- class scheduler: no_copy {
- public:
- //! For internal use only
- virtual void spawn( task& first, task*& next ) = 0;
- //! For internal use only
- virtual void wait_for_all( task& parent, task* child ) = 0;
- //! For internal use only
- virtual void spawn_root_and_wait( task& first, task*& next ) = 0;
- //! Pure virtual destructor;
- // Have to have it just to shut up overzealous compilation warnings
- virtual ~scheduler() = 0;
- //! For internal use only
- virtual void enqueue( task& t, void* reserved ) = 0;
- };
- //! A reference count
- /** Should always be non-negative. A signed type is used so that underflow can be detected. */
- typedef intptr_t reference_count;
- //! An id as used for specifying affinity.
- typedef unsigned short affinity_id;
- #if __TBB_TASK_GROUP_CONTEXT
- class generic_scheduler;
- struct context_list_node_t {
- context_list_node_t *my_prev,
- *my_next;
- };
- class allocate_root_with_context_proxy: no_assign {
- task_group_context& my_context;
- public:
- allocate_root_with_context_proxy ( task_group_context& ctx ) : my_context(ctx) {}
- task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
- void __TBB_EXPORTED_METHOD free( task& ) const;
- };
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- class allocate_root_proxy: no_assign {
- public:
- static task& __TBB_EXPORTED_FUNC allocate( size_t size );
- static void __TBB_EXPORTED_FUNC free( task& );
- };
- class allocate_continuation_proxy: no_assign {
- public:
- task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
- void __TBB_EXPORTED_METHOD free( task& ) const;
- };
- class allocate_child_proxy: no_assign {
- public:
- task& __TBB_EXPORTED_METHOD allocate( size_t size ) const;
- void __TBB_EXPORTED_METHOD free( task& ) const;
- };
- //! Memory prefix to a task object.
- /** This class is internal to the library.
- Do not reference it directly, except within the library itself.
- Fields are ordered in way that preserves backwards compatibility and yields
- good packing on typical 32-bit and 64-bit platforms.
- In case task prefix size exceeds 32 or 64 bytes on IA32 and Intel64
- architectures correspondingly, consider dynamic setting of task_alignment
- and task_prefix_reservation_size based on the maximal operand size supported
- by the current CPU.
- @ingroup task_scheduling */
- class task_prefix {
- private:
- friend class tbb::task;
- friend class tbb::interface5::internal::task_base;
- friend class tbb::task_list;
- friend class internal::scheduler;
- friend class internal::allocate_root_proxy;
- friend class internal::allocate_child_proxy;
- friend class internal::allocate_continuation_proxy;
- friend class internal::allocate_additional_child_of_proxy;
- #if __TBB_TASK_GROUP_CONTEXT
- //! Shared context that is used to communicate asynchronous state changes
- /** Currently it is used to broadcast cancellation requests generated both
- by users and as the result of unhandled exceptions in the task::execute()
- methods. */
- task_group_context *context;
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- //! The scheduler that allocated the task, or NULL if the task is big.
- /** Small tasks are pooled by the scheduler that allocated the task.
- If a scheduler needs to free a small task allocated by another scheduler,
- it returns the task to that other scheduler. This policy avoids
- memory space blowup issues for memory allocators that allocate from
- thread-specific pools. */
- scheduler* origin;
- #if __TBB_TASK_PRIORITY
- union {
- #endif /* __TBB_TASK_PRIORITY */
- //! Obsolete. The scheduler that owns the task.
- /** Retained only for the sake of backward binary compatibility.
- Still used by inline methods in the task.h header. **/
- scheduler* owner;
- #if __TBB_TASK_PRIORITY
- //! Pointer to the next offloaded lower priority task.
- /** Used to maintain a list of offloaded tasks inside the scheduler. **/
- task* next_offloaded;
- };
- #endif /* __TBB_TASK_PRIORITY */
- //! The task whose reference count includes me.
- /** In the "blocking style" of programming, this field points to the parent task.
- In the "continuation-passing style" of programming, this field points to the
- continuation of the parent. */
- tbb::task* parent;
- //! Reference count used for synchronization.
- /** In the "continuation-passing style" of programming, this field is
- the difference of the number of allocated children minus the
- number of children that have completed.
- In the "blocking style" of programming, this field is one more than the difference. */
- __TBB_atomic reference_count ref_count;
- //! Obsolete. Used to be scheduling depth before TBB 2.2
- /** Retained only for the sake of backward binary compatibility.
- Not used by TBB anymore. **/
- int depth;
- //! A task::state_type, stored as a byte for compactness.
- /** This state is exposed to users via method task::state(). */
- unsigned char state;
- //! Miscellaneous state that is not directly visible to users, stored as a byte for compactness.
- /** 0x0 -> version 1.0 task
- 0x1 -> version >=2.1 task
- 0x10 -> task was enqueued
- 0x20 -> task_proxy
- 0x40 -> task has live ref_count
- 0x80 -> a stolen task */
- unsigned char extra_state;
- affinity_id affinity;
- //! "next" field for list of task
- tbb::task* next;
- //! The task corresponding to this task_prefix.
- tbb::task& task() {return *reinterpret_cast<tbb::task*>(this+1);}
- };
- } // namespace internal
- //! @endcond
- #if __TBB_TASK_GROUP_CONTEXT
- #if __TBB_TASK_PRIORITY
- namespace internal {
- static const int priority_stride_v4 = INT_MAX / 4;
- }
- enum priority_t {
- priority_normal = internal::priority_stride_v4 * 2,
- priority_low = priority_normal - internal::priority_stride_v4,
- priority_high = priority_normal + internal::priority_stride_v4
- };
- #endif /* __TBB_TASK_PRIORITY */
- #if TBB_USE_CAPTURED_EXCEPTION
- class tbb_exception;
- #else
- namespace internal {
- class tbb_exception_ptr;
- }
- #endif /* !TBB_USE_CAPTURED_EXCEPTION */
- class task_scheduler_init;
- //! Used to form groups of tasks
- /** @ingroup task_scheduling
- The context services explicit cancellation requests from user code, and unhandled
- exceptions intercepted during tasks execution. Intercepting an exception results
- in generating internal cancellation requests (which is processed in exactly the
- same way as external ones).
- The context is associated with one or more root tasks and defines the cancellation
- group that includes all the descendants of the corresponding root task(s). Association
- is established when a context object is passed as an argument to the task::allocate_root()
- method. See task_group_context::task_group_context for more details.
- The context can be bound to another one, and other contexts can be bound to it,
- forming a tree-like structure: parent -> this -> children. Arrows here designate
- cancellation propagation direction. If a task in a cancellation group is cancelled
- all the other tasks in this group and groups bound to it (as children) get cancelled too.
- IMPLEMENTATION NOTE:
- When adding new members to task_group_context or changing types of existing ones,
- update the size of both padding buffers (_leading_padding and _trailing_padding)
- appropriately. See also VERSIONING NOTE at the constructor definition below. **/
- class task_group_context : internal::no_copy {
- private:
- friend class internal::generic_scheduler;
- friend class task_scheduler_init;
- #if TBB_USE_CAPTURED_EXCEPTION
- typedef tbb_exception exception_container_type;
- #else
- typedef internal::tbb_exception_ptr exception_container_type;
- #endif
- enum version_traits_word_layout {
- traits_offset = 16,
- version_mask = 0xFFFF,
- traits_mask = 0xFFFFul << traits_offset
- };
- public:
- enum kind_type {
- isolated,
- bound
- };
- enum traits_type {
- exact_exception = 0x0001ul << traits_offset,
- concurrent_wait = 0x0004ul << traits_offset,
- #if TBB_USE_CAPTURED_EXCEPTION
- default_traits = 0
- #else
- default_traits = exact_exception
- #endif /* !TBB_USE_CAPTURED_EXCEPTION */
- };
- private:
- enum state {
- may_have_children = 1
- };
- union {
- //! Flavor of this context: bound or isolated.
- kind_type my_kind;
- uintptr_t _my_kind_aligner;
- };
- //! Pointer to the context of the parent cancellation group. NULL for isolated contexts.
- task_group_context *my_parent;
- //! Used to form the thread specific list of contexts without additional memory allocation.
- /** A context is included into the list of the current thread when its binding to
- its parent happens. Any context can be present in the list of one thread only. **/
- internal::context_list_node_t my_node;
- //! Used to set and maintain stack stitching point for Intel Performance Tools.
- __itt_caller itt_caller;
- //! Leading padding protecting accesses to frequently used members from false sharing.
- /** Read accesses to the field my_cancellation_requested are on the hot path inside
- the scheduler. This padding ensures that this field never shares the same cache
- line with a local variable that is frequently written to. **/
- char _leading_padding[internal::NFS_MaxLineSize
- - 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(internal::context_list_node_t)
- - sizeof(__itt_caller)];
- //! Specifies whether cancellation was request for this task group.
- uintptr_t my_cancellation_requested;
- //! Version for run-time checks and behavioral traits of the context.
- /** Version occupies low 16 bits, and traits (zero or more ORed enumerators
- from the traits_type enumerations) take the next 16 bits.
- Original (zeroth) version of the context did not support any traits. **/
- uintptr_t my_version_and_traits;
- //! Pointer to the container storing exception being propagated across this task group.
- exception_container_type *my_exception;
- //! Scheduler instance that registered this context in its thread specific list.
- internal::generic_scheduler *my_owner;
- //! Internal state (combination of state flags).
- uintptr_t my_state;
- #if __TBB_TASK_PRIORITY
- //! Priority level of the task group (in normalized representation)
- intptr_t my_priority;
- #endif /* __TBB_TASK_PRIORITY */
- //! Trailing padding protecting accesses to frequently used members from false sharing
- /** \sa _leading_padding **/
- char _trailing_padding[internal::NFS_MaxLineSize - 2 * sizeof(uintptr_t) - 2 * sizeof(void*)
- #if __TBB_TASK_PRIORITY
- - sizeof(intptr_t)
- #endif /* __TBB_TASK_PRIORITY */
- ];
- public:
- //! Default & binding constructor.
- /** By default a bound context is created. That is this context will be bound
- (as child) to the context of the task calling task::allocate_root(this_context)
- method. Cancellation requests passed to the parent context are propagated
- to all the contexts bound to it. Similarly priority change is propagated
- from the parent context to its children.
- If task_group_context::isolated is used as the argument, then the tasks associated
- with this context will never be affected by events in any other context.
- Creating isolated contexts involve much less overhead, but they have limited
- utility. Normally when an exception occurs in an algorithm that has nested
- ones running, it is desirably to have all the nested algorithms cancelled
- as well. Such a behavior requires nested algorithms to use bound contexts.
- There is one good place where using isolated algorithms is beneficial. It is
- a master thread. That is if a particular algorithm is invoked directly from
- the master thread (not from a TBB task), supplying it with explicitly
- created isolated context will result in a faster algorithm startup.
- VERSIONING NOTE:
- Implementation(s) of task_group_context constructor(s) cannot be made
- entirely out-of-line because the run-time version must be set by the user
- code. This will become critically important for binary compatibility, if
- we ever have to change the size of the context object.
- Boosting the runtime version will also be necessary if new data fields are
- introduced in the currently unused padding areas and these fields are updated
- by inline methods. **/
- task_group_context ( kind_type relation_with_parent = bound,
- uintptr_t traits = default_traits )
- : my_kind(relation_with_parent)
- , my_version_and_traits(1 | traits)
- {
- init();
- }
- __TBB_EXPORTED_METHOD ~task_group_context ();
- //! Forcefully reinitializes the context after the task tree it was associated with is completed.
- /** Because the method assumes that all the tasks that used to be associated with
- this context have already finished, calling it while the context is still
- in use somewhere in the task hierarchy leads to undefined behavior.
- IMPORTANT: This method is not thread safe!
- The method does not change the context's parent if it is set. **/
- void __TBB_EXPORTED_METHOD reset ();
- //! Initiates cancellation of all tasks in this cancellation group and its subordinate groups.
- /** \return false if cancellation has already been requested, true otherwise.
- Note that canceling never fails. When false is returned, it just means that
- another thread (or this one) has already sent cancellation request to this
- context or to one of its ancestors (if this context is bound). It is guaranteed
- that when this method is concurrently called on the same not yet cancelled
- context, true will be returned by one and only one invocation. **/
- bool __TBB_EXPORTED_METHOD cancel_group_execution ();
- //! Returns true if the context received cancellation request.
- bool __TBB_EXPORTED_METHOD is_group_execution_cancelled () const;
- //! Records the pending exception, and cancels the task group.
- /** May be called only from inside a catch-block. If the context is already
- cancelled, does nothing.
- The method brings the task group associated with this context exactly into
- the state it would be in, if one of its tasks threw the currently pending
- exception during its execution. In other words, it emulates the actions
- of the scheduler's dispatch loop exception handler. **/
- void __TBB_EXPORTED_METHOD register_pending_exception ();
- #if __TBB_TASK_PRIORITY
- //! Changes priority of the task group
- void set_priority ( priority_t );
- //! Retrieves current priority of the current task group
- priority_t priority () const;
- #endif /* __TBB_TASK_PRIORITY */
- protected:
- //! Out-of-line part of the constructor.
- /** Singled out to ensure backward binary compatibility of the future versions. **/
- void __TBB_EXPORTED_METHOD init ();
- private:
- friend class task;
- friend class internal::allocate_root_with_context_proxy;
- static const kind_type binding_required = bound;
- static const kind_type binding_completed = kind_type(bound+1);
- static const kind_type detached = kind_type(binding_completed+1);
- static const kind_type dying = kind_type(detached+1);
- //! Propagates state change (if any) from an ancestor
- /** Checks if one of this object's ancestors is in a new state, and propagates
- the new state to all its descendants in this object's heritage line. **/
- template <typename T>
- void propagate_state_from_ancestors ( T task_group_context::*mptr_state, T new_state );
- //! Makes sure that the context is registered with a scheduler instance.
- inline void finish_initialization ( internal::generic_scheduler *local_sched );
- //! Registers this context with the local scheduler and binds it to its parent context
- void bind_to ( internal::generic_scheduler *local_sched );
- //! Registers this context with the local scheduler
- void register_with ( internal::generic_scheduler *local_sched );
- }; // class task_group_context
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- //! Base class for user-defined tasks.
- /** @ingroup task_scheduling */
- class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base {
- //! Set reference count
- void __TBB_EXPORTED_METHOD internal_set_ref_count( int count );
- //! Decrement reference count and return its new value.
- internal::reference_count __TBB_EXPORTED_METHOD internal_decrement_ref_count();
- protected:
- //! Default constructor.
- task() {prefix().extra_state=1;}
- public:
- //! Destructor.
- virtual ~task() {}
- //! Should be overridden by derived classes.
- virtual task* execute() = 0;
- //! Enumeration of task states that the scheduler considers.
- enum state_type {
- //! task is running, and will be destroyed after method execute() completes.
- executing,
- //! task to be rescheduled.
- reexecute,
- //! task is in ready pool, or is going to be put there, or was just taken off.
- ready,
- //! task object is freshly allocated or recycled.
- allocated,
- //! task object is on free list, or is going to be put there, or was just taken off.
- freed,
- //! task to be recycled as continuation
- recycle
- };
- //------------------------------------------------------------------------
- // Allocating tasks
- //------------------------------------------------------------------------
- //! Returns proxy for overloaded new that allocates a root task.
- static internal::allocate_root_proxy allocate_root() {
- return internal::allocate_root_proxy();
- }
- #if __TBB_TASK_GROUP_CONTEXT
- //! Returns proxy for overloaded new that allocates a root task associated with user supplied context.
- static internal::allocate_root_with_context_proxy allocate_root( task_group_context& ctx ) {
- return internal::allocate_root_with_context_proxy(ctx);
- }
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- //! Returns proxy for overloaded new that allocates a continuation task of *this.
- /** The continuation's parent becomes the parent of *this. */
- internal::allocate_continuation_proxy& allocate_continuation() {
- return *reinterpret_cast<internal::allocate_continuation_proxy*>(this);
- }
- //! Returns proxy for overloaded new that allocates a child task of *this.
- internal::allocate_child_proxy& allocate_child() {
- return *reinterpret_cast<internal::allocate_child_proxy*>(this);
- }
- //! Define recommended static form via import from base class.
- using task_base::allocate_additional_child_of;
- #if __TBB_DEPRECATED_TASK_INTERFACE
- //! Destroy a task.
- /** Usually, calling this method is unnecessary, because a task is
- implicitly deleted after its execute() method runs. However,
- sometimes a task needs to be explicitly deallocated, such as
- when a root task is used as the parent in spawn_and_wait_for_all. */
- void __TBB_EXPORTED_METHOD destroy( task& t );
- #else /* !__TBB_DEPRECATED_TASK_INTERFACE */
- //! Define recommended static form via import from base class.
- using task_base::destroy;
- #endif /* !__TBB_DEPRECATED_TASK_INTERFACE */
- //------------------------------------------------------------------------
- // Recycling of tasks
- //------------------------------------------------------------------------
- //! Change this to be a continuation of its former self.
- /** The caller must guarantee that the task's refcount does not become zero until
- after the method execute() returns. Typically, this is done by having
- method execute() return a pointer to a child of the task. If the guarantee
- cannot be made, use method recycle_as_safe_continuation instead.
- Because of the hazard, this method may be deprecated in the future. */
- void recycle_as_continuation() {
- __TBB_ASSERT( prefix().state==executing, "execute not running?" );
- prefix().state = allocated;
- }
- //! Recommended to use, safe variant of recycle_as_continuation
- /** For safety, it requires additional increment of ref_count.
- With no descendants and ref_count of 1, it has the semantics of recycle_to_reexecute. */
- void recycle_as_safe_continuation() {
- __TBB_ASSERT( prefix().state==executing, "execute not running?" );
- prefix().state = recycle;
- }
- //! Change this to be a child of new_parent.
- void recycle_as_child_of( task& new_parent ) {
- internal::task_prefix& p = prefix();
- __TBB_ASSERT( prefix().state==executing||prefix().state==allocated, "execute not running, or already recycled" );
- __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled as a child" );
- __TBB_ASSERT( p.parent==NULL, "parent must be null" );
- __TBB_ASSERT( new_parent.prefix().state<=recycle, "corrupt parent's state" );
- __TBB_ASSERT( new_parent.prefix().state!=freed, "parent already freed" );
- p.state = allocated;
- p.parent = &new_parent;
- #if __TBB_TASK_GROUP_CONTEXT
- p.context = new_parent.prefix().context;
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- }
- //! Schedule this for reexecution after current execute() returns.
- /** Made obsolete by recycle_as_safe_continuation; may become deprecated. */
- void recycle_to_reexecute() {
- __TBB_ASSERT( prefix().state==executing, "execute not running, or already recycled" );
- __TBB_ASSERT( prefix().ref_count==0, "no child tasks allowed when recycled for reexecution" );
- prefix().state = reexecute;
- }
- // All depth-related methods are obsolete, and are retained for the sake
- // of backward source compatibility only
- intptr_t depth() const {return 0;}
- void set_depth( intptr_t ) {}
- void add_to_depth( int ) {}
- //------------------------------------------------------------------------
- // Spawning and blocking
- //------------------------------------------------------------------------
- //! Set reference count
- void set_ref_count( int count ) {
- #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
- internal_set_ref_count(count);
- #else
- prefix().ref_count = count;
- #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
- }
- //! Atomically increment reference count and returns its old value.
- /** Has acquire semantics */
- void increment_ref_count() {
- __TBB_FetchAndIncrementWacquire( &prefix().ref_count );
- }
- //! Atomically decrement reference count and returns its new value.
- /** Has release semantics. */
- int decrement_ref_count() {
- #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
- return int(internal_decrement_ref_count());
- #else
- return int(__TBB_FetchAndDecrementWrelease( &prefix().ref_count ))-1;
- #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
- }
- //! Define recommended static forms via import from base class.
- using task_base::spawn;
- //! Similar to spawn followed by wait_for_all, but more efficient.
- void spawn_and_wait_for_all( task& child ) {
- prefix().owner->wait_for_all( *this, &child );
- }
- //! Similar to spawn followed by wait_for_all, but more efficient.
- void __TBB_EXPORTED_METHOD spawn_and_wait_for_all( task_list& list );
- //! Spawn task allocated by allocate_root, wait for it to complete, and deallocate it.
- static void spawn_root_and_wait( task& root ) {
- root.prefix().owner->spawn_root_and_wait( root, root.prefix().next );
- }
- //! Spawn root tasks on list and wait for all of them to finish.
- /** If there are more tasks than worker threads, the tasks are spawned in
- order of front to back. */
- static void spawn_root_and_wait( task_list& root_list );
- //! Wait for reference count to become one, and set reference count to zero.
- /** Works on tasks while waiting. */
- void wait_for_all() {
- prefix().owner->wait_for_all( *this, NULL );
- }
- //! Enqueue task for starvation-resistant execution.
- #if __TBB_TASK_PRIORITY
- /** The task will be enqueued on the normal priority level disregarding the
- priority of its task group.
- The rationale of such semantics is that priority of an enqueued task is
- statically fixed at the moment of its enqueuing, while task group priority
- is dynamic. Thus automatic priority inheritance would be generally a subject
- to the race, which may result in unexpected behavior.
- Use enqueue() overload with explicit priority value and task::group_priority()
- method to implement such priority inheritance when it is really necessary. **/
- #endif /* __TBB_TASK_PRIORITY */
- static void enqueue( task& t ) {
- t.prefix().owner->enqueue( t, NULL );
- }
- #if __TBB_TASK_PRIORITY
- //! Enqueue task for starvation-resistant execution on the specified priority level.
- static void enqueue( task& t, priority_t p ) {
- __TBB_ASSERT( p == priority_low || p == priority_normal || p == priority_high, "Invalid priority level value" );
- t.prefix().owner->enqueue( t, (void*)p );
- }
- #endif /* __TBB_TASK_PRIORITY */
- //! The innermost task being executed or destroyed by the current thread at the moment.
- static task& __TBB_EXPORTED_FUNC self();
- //! task on whose behalf this task is working, or NULL if this is a root.
- task* parent() const {return prefix().parent;}
- //! sets parent task pointer to specified value
- void set_parent(task* p) {
- #if __TBB_TASK_GROUP_CONTEXT
- __TBB_ASSERT(prefix().context == p->prefix().context, "The tasks must be in the same context");
- #endif
- prefix().parent = p;
- }
- #if __TBB_TASK_GROUP_CONTEXT
- //! This method is deprecated and will be removed in the future.
- /** Use method group() instead. **/
- task_group_context* context() {return prefix().context;}
- //! Pointer to the task group descriptor.
- task_group_context* group () { return prefix().context; }
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- //! True if task was stolen from the task pool of another thread.
- bool is_stolen_task() const {
- return (prefix().extra_state & 0x80)!=0;
- }
- //------------------------------------------------------------------------
- // Debugging
- //------------------------------------------------------------------------
- //! Current execution state
- state_type state() const {return state_type(prefix().state);}
- //! The internal reference count.
- int ref_count() const {
- #if TBB_USE_ASSERT
- internal::reference_count ref_count_ = prefix().ref_count;
- __TBB_ASSERT( ref_count_==int(ref_count_), "integer overflow error");
- #endif
- return int(prefix().ref_count);
- }
- //! Obsolete, and only retained for the sake of backward compatibility. Always returns true.
- bool __TBB_EXPORTED_METHOD is_owned_by_current_thread() const;
- //------------------------------------------------------------------------
- // Affinity
- //------------------------------------------------------------------------
- //! An id as used for specifying affinity.
- /** Guaranteed to be integral type. Value of 0 means no affinity. */
- typedef internal::affinity_id affinity_id;
- //! Set affinity for this task.
- void set_affinity( affinity_id id ) {prefix().affinity = id;}
- //! Current affinity of this task
- affinity_id affinity() const {return prefix().affinity;}
- //! Invoked by scheduler to notify task that it ran on unexpected thread.
- /** Invoked before method execute() runs, if task is stolen, or task has
- affinity but will be executed on another thread.
- The default action does nothing. */
- virtual void __TBB_EXPORTED_METHOD note_affinity( affinity_id id );
- #if __TBB_TASK_GROUP_CONTEXT
- //! Moves this task from its current group into another one.
- /** Argument ctx specifies the new group.
- The primary purpose of this method is to associate unique task group context
- with a task allocated for subsequent enqueuing. In contrast to spawned tasks
- enqueued ones normally outlive the scope where they were created. This makes
- traditional usage model where task group context are allocated locally on
- the stack inapplicable. Dynamic allocation of context objects is performance
- inefficient. Method change_group() allows to make task group context object
- a member of the task class, and then associate it with its containing task
- object in the latter's constructor. **/
- void __TBB_EXPORTED_METHOD change_group ( task_group_context& ctx );
- //! Initiates cancellation of all tasks in this cancellation group and its subordinate groups.
- /** \return false if cancellation has already been requested, true otherwise. **/
- bool cancel_group_execution () { return prefix().context->cancel_group_execution(); }
- //! Returns true if the context has received cancellation request.
- bool is_cancelled () const { return prefix().context->is_group_execution_cancelled(); }
- #else
- bool is_cancelled () const { return false; }
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- #if __TBB_TASK_PRIORITY
- //! Changes priority of the task group this task belongs to.
- void set_group_priority ( priority_t p ) { prefix().context->set_priority(p); }
- //! Retrieves current priority of the task group this task belongs to.
- priority_t group_priority () const { return prefix().context->priority(); }
- #endif /* __TBB_TASK_PRIORITY */
- private:
- friend class interface5::internal::task_base;
- friend class task_list;
- friend class internal::scheduler;
- friend class internal::allocate_root_proxy;
- #if __TBB_TASK_GROUP_CONTEXT
- friend class internal::allocate_root_with_context_proxy;
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- friend class internal::allocate_continuation_proxy;
- friend class internal::allocate_child_proxy;
- friend class internal::allocate_additional_child_of_proxy;
- //! Get reference to corresponding task_prefix.
- /** Version tag prevents loader on Linux from using the wrong symbol in debug builds. **/
- internal::task_prefix& prefix( internal::version_tag* = NULL ) const {
- return reinterpret_cast<internal::task_prefix*>(const_cast<task*>(this))[-1];
- }
- }; // class task
- //! task that does nothing. Useful for synchronization.
- /** @ingroup task_scheduling */
- class empty_task: public task {
- /*override*/ task* execute() {
- return NULL;
- }
- };
- //! A list of children.
- /** Used for method task::spawn_children
- @ingroup task_scheduling */
- class task_list: internal::no_copy {
- private:
- task* first;
- task** next_ptr;
- friend class task;
- friend class interface5::internal::task_base;
- public:
- //! Construct empty list
- task_list() : first(NULL), next_ptr(&first) {}
- //! Destroys the list, but does not destroy the task objects.
- ~task_list() {}
- //! True if list if empty; false otherwise.
- bool empty() const {return !first;}
- //! Push task onto back of list.
- void push_back( task& task ) {
- task.prefix().next = NULL;
- *next_ptr = &task;
- next_ptr = &task.prefix().next;
- }
- //! Pop the front task from the list.
- task& pop_front() {
- __TBB_ASSERT( !empty(), "attempt to pop item from empty task_list" );
- task* result = first;
- first = result->prefix().next;
- if( !first ) next_ptr = &first;
- return *result;
- }
- //! Clear the list
- void clear() {
- first=NULL;
- next_ptr=&first;
- }
- };
- inline void interface5::internal::task_base::spawn( task& t ) {
- t.prefix().owner->spawn( t, t.prefix().next );
- }
- inline void interface5::internal::task_base::spawn( task_list& list ) {
- if( task* t = list.first ) {
- t->prefix().owner->spawn( *t, *list.next_ptr );
- list.clear();
- }
- }
- inline void task::spawn_root_and_wait( task_list& root_list ) {
- if( task* t = root_list.first ) {
- t->prefix().owner->spawn_root_and_wait( *t, *root_list.next_ptr );
- root_list.clear();
- }
- }
- } // namespace tbb
- inline void *operator new( size_t bytes, const tbb::internal::allocate_root_proxy& ) {
- return &tbb::internal::allocate_root_proxy::allocate(bytes);
- }
- inline void operator delete( void* task, const tbb::internal::allocate_root_proxy& ) {
- tbb::internal::allocate_root_proxy::free( *static_cast<tbb::task*>(task) );
- }
- #if __TBB_TASK_GROUP_CONTEXT
- inline void *operator new( size_t bytes, const tbb::internal::allocate_root_with_context_proxy& p ) {
- return &p.allocate(bytes);
- }
- inline void operator delete( void* task, const tbb::internal::allocate_root_with_context_proxy& p ) {
- p.free( *static_cast<tbb::task*>(task) );
- }
- #endif /* __TBB_TASK_GROUP_CONTEXT */
- inline void *operator new( size_t bytes, const tbb::internal::allocate_continuation_proxy& p ) {
- return &p.allocate(bytes);
- }
- inline void operator delete( void* task, const tbb::internal::allocate_continuation_proxy& p ) {
- p.free( *static_cast<tbb::task*>(task) );
- }
- inline void *operator new( size_t bytes, const tbb::internal::allocate_child_proxy& p ) {
- return &p.allocate(bytes);
- }
- inline void operator delete( void* task, const tbb::internal::allocate_child_proxy& p ) {
- p.free( *static_cast<tbb::task*>(task) );
- }
- inline void *operator new( size_t bytes, const tbb::internal::allocate_additional_child_of_proxy& p ) {
- return &p.allocate(bytes);
- }
- inline void operator delete( void* task, const tbb::internal::allocate_additional_child_of_proxy& p ) {
- p.free( *static_cast<tbb::task*>(task) );
- }
- #endif /* __TBB_task_H */
|