| /* |
| Copyright 2005-2010 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_scheduler_common_H |
| #define _TBB_scheduler_common_H |
| |
| #include "tbb/tbb_stddef.h" |
| |
| #if __SUNPRO_CC |
| #include <string.h> // for memset, memcpy, memmove |
| #endif |
| |
| /* Temporarily change "private" to "public" while including "tbb/task.h". |
| This hack allows us to avoid publishing internal types and methods |
| in the public header files just for sake of friend declarations. */ |
| #define private public |
| #include "tbb/task.h" |
| #include "tbb/tbb_exception.h" |
| #undef private |
| |
| // This macro is an attempt to get rid of ugly ifdefs in the shared parts of the code. |
| // It drops the second argument depending on whether the controlling macro is defined. |
| // The first argument is just a convenience allowing to keep comma before the macro usage. |
| #if __TBB_TASK_GROUP_CONTEXT |
| #define __TBB_CONTEXT_ARG(arg1, context) arg1, context |
| #else /* !__TBB_TASK_GROUP_CONTEXT */ |
| #define __TBB_CONTEXT_ARG(arg1, context) arg1 |
| #endif /* !__TBB_TASK_GROUP_CONTEXT */ |
| |
| #if DO_TBB_TRACE |
| #include <cstdio> |
| #define TBB_TRACE(x) ((void)std::printf x) |
| #else |
| #define TBB_TRACE(x) ((void)(0)) |
| #endif /* DO_TBB_TRACE */ |
| |
| #if _MSC_VER && !defined(__INTEL_COMPILER) |
| // Workaround for overzealous compiler warnings |
| // These particular warnings are so ubiquitous that no attempt is made to narrow |
| // the scope of the warnings. |
| #pragma warning (disable: 4100 4127 4312 4244 4267 4706) |
| #endif |
| |
| namespace tbb { |
| namespace internal { |
| |
| /** Defined in scheduler.cpp **/ |
| extern uintptr_t global_cancel_count; |
| |
| //! Alignment for a task object |
| const size_t task_alignment = 16; |
| |
| //! Number of bytes reserved for a task prefix |
| /** If not exactly sizeof(task_prefix), the extra bytes *precede* the task_prefix. */ |
| const size_t task_prefix_reservation_size = ((sizeof(internal::task_prefix)-1)/task_alignment+1)*task_alignment; |
| |
| //! Definitions for bits in task_prefix::extra_state |
| enum task_extra_state { |
| //! Tag for v1 tasks (i.e. tasks in TBB 1.0 and 2.0) |
| es_version_1_task = 0, |
| //! Tag for v3 tasks (i.e. tasks in TBB 2.1-2.2) |
| es_version_3_task = 1, |
| //! Tag for v3 task_proxy. |
| es_task_proxy = 0x20, |
| //! Set if ref_count might be changed by another thread. Used for debugging. |
| es_ref_count_active = 0x40, |
| //! Set if the task has been stolen |
| es_task_is_stolen = 0x80 |
| }; |
| |
| //! Optimization hint to free_task that enables it omit unnecessary tests and code. |
| enum free_task_hint { |
| //! No hint |
| no_hint=0, |
| //! Task is known to have been allocated by this scheduler |
| local_task=1, |
| //! Task is known to be a small task. |
| /** Task should be returned to the free list of *some* scheduler, possibly not this scheduler. */ |
| small_task=2, |
| //! Bitwise-OR of local_task and small_task. |
| /** Task should be returned to free list of this scheduler. */ |
| small_local_task=3 |
| }; |
| |
| //------------------------------------------------------------------------ |
| // Helpers |
| //------------------------------------------------------------------------ |
| |
| #if TBB_USE_ASSERT |
| /** Logically, this method should be a member of class task. |
| But we do not want to publish it, so it is here instead. */ |
| inline bool AssertOkay( const task& task ) { |
| __TBB_ASSERT( &task!=NULL, NULL ); |
| __TBB_ASSERT( (uintptr_t)&task % task_alignment == 0, "misaligned task" ); |
| __TBB_ASSERT( (unsigned)task.state()<=(unsigned)task::recycle, "corrupt task (invalid state)" ); |
| return true; |
| } |
| #endif /* TBB_USE_ASSERT */ |
| |
| inline bool ConcurrentWaitsEnabled ( task& t ) { |
| return (t.prefix().context->my_version_and_traits & task_group_context::concurrent_wait) != 0; |
| } |
| |
| inline bool CancellationInfoPresent ( task& t ) { |
| return t.prefix().context->my_cancellation_requested != 0; |
| } |
| |
| #if __TBB_TASK_GROUP_CONTEXT |
| #if TBB_USE_CAPTURED_EXCEPTION |
| inline tbb_exception* TbbCurrentException( task_group_context*, tbb_exception* src) { return src->move(); } |
| inline tbb_exception* TbbCurrentException( task_group_context*, captured_exception* src) { return src; } |
| #else |
| // Using macro instead of an inline function here allows to avoid evaluation of the |
| // TbbCapturedException expression when exact propagation is enabled for the context. |
| #define TbbCurrentException(context, TbbCapturedException) \ |
| context->my_version_and_traits & task_group_context::exact_exception \ |
| ? tbb_exception_ptr::allocate() \ |
| : tbb_exception_ptr::allocate( *(TbbCapturedException) ); |
| #endif /* !TBB_USE_CAPTURED_EXCEPTION */ |
| |
| #define TbbRegisterCurrentException(context, TbbCapturedException) \ |
| if ( context->cancel_group_execution() ) { \ |
| /* We are the first to signal cancellation, so store the exception that caused it. */ \ |
| context->my_exception = TbbCurrentException( context, TbbCapturedException ); \ |
| } |
| |
| #define TbbCatchAll(context) \ |
| catch ( tbb_exception& exc ) { \ |
| TbbRegisterCurrentException( context, &exc ); \ |
| } catch ( std::exception& exc ) { \ |
| TbbRegisterCurrentException( context, captured_exception::allocate(typeid(exc).name(), exc.what()) ); \ |
| } catch ( ... ) { \ |
| TbbRegisterCurrentException( context, captured_exception::allocate("...", "Unidentified exception") );\ |
| } |
| #endif /* __TBB_TASK_GROUP_CONTEXT */ |
| |
| } // namespace internal |
| } // namespace tbb |
| |
| #endif /* _TBB_scheduler_common_H */ |