You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							386 lines
						
					
					
						
							14 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							386 lines
						
					
					
						
							14 KiB
						
					
					
				
								/*
							 | 
						|
								    Copyright 2005-2014 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_exception_H
							 | 
						|
								#define __TBB_exception_H
							 | 
						|
								
							 | 
						|
								#include "tbb_stddef.h"
							 | 
						|
								
							 | 
						|
								#if !TBB_USE_EXCEPTIONS && _MSC_VER
							 | 
						|
								    // Suppress "C++ exception handler used, but unwind semantics are not enabled" warning in STL headers
							 | 
						|
								    #pragma warning (push)
							 | 
						|
								    #pragma warning (disable: 4530)
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								#include <exception>
							 | 
						|
								#include <new>    //required for bad_alloc definition, operators new
							 | 
						|
								#include <string> // required to construct std exception classes
							 | 
						|
								
							 | 
						|
								#if !TBB_USE_EXCEPTIONS && _MSC_VER
							 | 
						|
								    #pragma warning (pop)
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								namespace tbb {
							 | 
						|
								
							 | 
						|
								//! Exception for concurrent containers
							 | 
						|
								class bad_last_alloc : public std::bad_alloc {
							 | 
						|
								public:
							 | 
						|
								    /*override*/ const char* what() const throw();
							 | 
						|
								#if __TBB_DEFAULT_DTOR_THROW_SPEC_BROKEN
							 | 
						|
								    /*override*/ ~bad_last_alloc() throw() {}
							 | 
						|
								#endif
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//! Exception for PPL locks
							 | 
						|
								class improper_lock : public std::exception {
							 | 
						|
								public:
							 | 
						|
								    /*override*/ const char* what() const throw();
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//! Exception for user-initiated abort
							 | 
						|
								class user_abort : public std::exception {
							 | 
						|
								public:
							 | 
						|
								    /*override*/ const char* what() const throw();
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//! Exception for missing wait on structured_task_group
							 | 
						|
								class missing_wait : public std::exception {
							 | 
						|
								public:
							 | 
						|
								    /*override*/ const char* what() const throw();
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//! Exception for repeated scheduling of the same task_handle
							 | 
						|
								class invalid_multiple_scheduling : public std::exception {
							 | 
						|
								public:
							 | 
						|
								    /*override*/ const char* what() const throw();
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								namespace internal {
							 | 
						|
								//! Obsolete
							 | 
						|
								void __TBB_EXPORTED_FUNC throw_bad_last_alloc_exception_v4();
							 | 
						|
								
							 | 
						|
								enum exception_id {
							 | 
						|
								    eid_bad_alloc = 1,
							 | 
						|
								    eid_bad_last_alloc,
							 | 
						|
								    eid_nonpositive_step,
							 | 
						|
								    eid_out_of_range,
							 | 
						|
								    eid_segment_range_error,
							 | 
						|
								    eid_index_range_error,
							 | 
						|
								    eid_missing_wait,
							 | 
						|
								    eid_invalid_multiple_scheduling,
							 | 
						|
								    eid_improper_lock,
							 | 
						|
								    eid_possible_deadlock,
							 | 
						|
								    eid_operation_not_permitted,
							 | 
						|
								    eid_condvar_wait_failed,
							 | 
						|
								    eid_invalid_load_factor,
							 | 
						|
								    eid_reserved, // free slot for backward compatibility, can be reused.
							 | 
						|
								    eid_invalid_swap,
							 | 
						|
								    eid_reservation_length_error,
							 | 
						|
								    eid_invalid_key,
							 | 
						|
								    eid_user_abort,
							 | 
						|
								    eid_reserved1,
							 | 
						|
								#if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE
							 | 
						|
								    // This id is used only inside library and only for support of CPF functionality.
							 | 
						|
								    // So, if we drop the functionality, eid_reserved1 can be safely renamed and reused.
							 | 
						|
								    eid_blocking_sch_init = eid_reserved1,
							 | 
						|
								#endif
							 | 
						|
								    //! The last enumerator tracks the number of defined IDs. It must remain the last one.
							 | 
						|
								    /** When adding new IDs, place them immediately _before_ this comment (that is
							 | 
						|
								        _after_ all the existing IDs. NEVER insert new IDs between the existing ones. **/
							 | 
						|
								    eid_max
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//! Gathers all throw operators in one place.
							 | 
						|
								/** Its purpose is to minimize code bloat that can be caused by throw operators
							 | 
						|
								    scattered in multiple places, especially in templates. **/
							 | 
						|
								void __TBB_EXPORTED_FUNC throw_exception_v4 ( exception_id );
							 | 
						|
								
							 | 
						|
								//! Versionless convenience wrapper for throw_exception_v4()
							 | 
						|
								inline void throw_exception ( exception_id eid ) { throw_exception_v4(eid); }
							 | 
						|
								
							 | 
						|
								} // namespace internal
							 | 
						|
								} // namespace tbb
							 | 
						|
								
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								#include "tbb_allocator.h"
							 | 
						|
								#include <typeinfo> //for typeid
							 | 
						|
								
							 | 
						|
								namespace tbb {
							 | 
						|
								
							 | 
						|
								//! Interface to be implemented by all exceptions TBB recognizes and propagates across the threads.
							 | 
						|
								/** If an unhandled exception of the type derived from tbb::tbb_exception is intercepted
							 | 
						|
								    by the TBB scheduler in one of the worker threads, it is delivered to and re-thrown in
							 | 
						|
								    the root thread. The root thread is the thread that has started the outermost algorithm
							 | 
						|
								    or root task sharing the same task_group_context with the guilty algorithm/task (the one
							 | 
						|
								    that threw the exception first).
							 | 
						|
								
							 | 
						|
								    Note: when documentation mentions workers with respect to exception handling,
							 | 
						|
								    masters are implied as well, because they are completely equivalent in this context.
							 | 
						|
								    Consequently a root thread can be master or worker thread.
							 | 
						|
								
							 | 
						|
								    NOTE: In case of nested algorithms or complex task hierarchies when the nested
							 | 
						|
								    levels share (explicitly or by means of implicit inheritance) the task group
							 | 
						|
								    context of the outermost level, the exception may be (re-)thrown multiple times
							 | 
						|
								    (ultimately - in each worker on each nesting level) before reaching the root
							 | 
						|
								    thread at the outermost level. IMPORTANT: if you intercept an exception derived
							 | 
						|
								    from this class on a nested level, you must re-throw it in the catch block by means
							 | 
						|
								    of the "throw;" operator.
							 | 
						|
								
							 | 
						|
								    TBB provides two implementations of this interface: tbb::captured_exception and
							 | 
						|
								    template class tbb::movable_exception. See their declarations for more info. **/
							 | 
						|
								class tbb_exception : public std::exception
							 | 
						|
								{
							 | 
						|
								    /** No operator new is provided because the TBB usage model assumes dynamic
							 | 
						|
								        creation of the TBB exception objects only by means of applying move()
							 | 
						|
								        operation on an exception thrown out of TBB scheduler. **/
							 | 
						|
								    void* operator new ( size_t );
							 | 
						|
								
							 | 
						|
								public:
							 | 
						|
								#if __clang__
							 | 
						|
								    // At -O3 or even -O2 optimization level, Clang may fully throw away an empty destructor
							 | 
						|
								    // of tbb_exception from destructors of derived classes. As a result, it does not create
							 | 
						|
								    // vtable for tbb_exception, which is a required part of TBB binary interface.
							 | 
						|
								    // Making the destructor non-empty (with just a semicolon) prevents that optimization.
							 | 
						|
								    ~tbb_exception() throw() { /* keep the semicolon! */ ; }
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    //! Creates and returns pointer to the deep copy of this exception object.
							 | 
						|
								    /** Move semantics is allowed. **/
							 | 
						|
								    virtual tbb_exception* move () throw() = 0;
							 | 
						|
								
							 | 
						|
								    //! Destroys objects created by the move() method.
							 | 
						|
								    /** Frees memory and calls destructor for this exception object.
							 | 
						|
								        Can and must be used only on objects created by the move method. **/
							 | 
						|
								    virtual void destroy () throw() = 0;
							 | 
						|
								
							 | 
						|
								    //! Throws this exception object.
							 | 
						|
								    /** Make sure that if you have several levels of derivation from this interface
							 | 
						|
								        you implement or override this method on the most derived level. The implementation
							 | 
						|
								        is as simple as "throw *this;". Failure to do this will result in exception
							 | 
						|
								        of a base class type being thrown. **/
							 | 
						|
								    virtual void throw_self () = 0;
							 | 
						|
								
							 | 
						|
								    //! Returns RTTI name of the originally intercepted exception
							 | 
						|
								    virtual const char* name() const throw() = 0;
							 | 
						|
								
							 | 
						|
								    //! Returns the result of originally intercepted exception's what() method.
							 | 
						|
								    virtual const char* what() const throw() = 0;
							 | 
						|
								
							 | 
						|
								    /** Operator delete is provided only to allow using existing smart pointers
							 | 
						|
								        with TBB exception objects obtained as the result of applying move()
							 | 
						|
								        operation on an exception thrown out of TBB scheduler.
							 | 
						|
								
							 | 
						|
								        When overriding method move() make sure to override operator delete as well
							 | 
						|
								        if memory is allocated not by TBB's scalable allocator. **/
							 | 
						|
								    void operator delete ( void* p ) {
							 | 
						|
								        internal::deallocate_via_handler_v3(p);
							 | 
						|
								    }
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//! This class is used by TBB to propagate information about unhandled exceptions into the root thread.
							 | 
						|
								/** Exception of this type is thrown by TBB in the root thread (thread that started a parallel
							 | 
						|
								    algorithm ) if an unhandled exception was intercepted during the algorithm execution in one
							 | 
						|
								    of the workers.
							 | 
						|
								    \sa tbb::tbb_exception **/
							 | 
						|
								class captured_exception : public tbb_exception
							 | 
						|
								{
							 | 
						|
								public:
							 | 
						|
								    captured_exception ( const captured_exception& src )
							 | 
						|
								        : tbb_exception(src), my_dynamic(false)
							 | 
						|
								    {
							 | 
						|
								        set(src.my_exception_name, src.my_exception_info);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    captured_exception ( const char* name_, const char* info )
							 | 
						|
								        : my_dynamic(false)
							 | 
						|
								    {
							 | 
						|
								        set(name_, info);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    __TBB_EXPORTED_METHOD ~captured_exception () throw();
							 | 
						|
								
							 | 
						|
								    captured_exception& operator= ( const captured_exception& src ) {
							 | 
						|
								        if ( this != &src ) {
							 | 
						|
								            clear();
							 | 
						|
								            set(src.my_exception_name, src.my_exception_info);
							 | 
						|
								        }
							 | 
						|
								        return *this;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /*override*/
							 | 
						|
								    captured_exception* __TBB_EXPORTED_METHOD move () throw();
							 | 
						|
								
							 | 
						|
								    /*override*/
							 | 
						|
								    void __TBB_EXPORTED_METHOD destroy () throw();
							 | 
						|
								
							 | 
						|
								    /*override*/
							 | 
						|
								    void throw_self () { __TBB_THROW(*this); }
							 | 
						|
								
							 | 
						|
								    /*override*/
							 | 
						|
								    const char* __TBB_EXPORTED_METHOD name() const throw();
							 | 
						|
								
							 | 
						|
								    /*override*/
							 | 
						|
								    const char* __TBB_EXPORTED_METHOD what() const throw();
							 | 
						|
								
							 | 
						|
								    void __TBB_EXPORTED_METHOD set ( const char* name, const char* info ) throw();
							 | 
						|
								    void __TBB_EXPORTED_METHOD clear () throw();
							 | 
						|
								
							 | 
						|
								private:
							 | 
						|
								    //! Used only by method clone().
							 | 
						|
								    captured_exception() {}
							 | 
						|
								
							 | 
						|
								    //! Functionally equivalent to {captured_exception e(name,info); return e.clone();}
							 | 
						|
								    static captured_exception* allocate ( const char* name, const char* info );
							 | 
						|
								
							 | 
						|
								    bool my_dynamic;
							 | 
						|
								    const char* my_exception_name;
							 | 
						|
								    const char* my_exception_info;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//! Template that can be used to implement exception that transfers arbitrary ExceptionData to the root thread
							 | 
						|
								/** Code using TBB can instantiate this template with an arbitrary ExceptionData type
							 | 
						|
								    and throw this exception object. Such exceptions are intercepted by the TBB scheduler
							 | 
						|
								    and delivered to the root thread ().
							 | 
						|
								    \sa tbb::tbb_exception **/
							 | 
						|
								template<typename ExceptionData>
							 | 
						|
								class movable_exception : public tbb_exception
							 | 
						|
								{
							 | 
						|
								    typedef movable_exception<ExceptionData> self_type;
							 | 
						|
								
							 | 
						|
								public:
							 | 
						|
								    movable_exception ( const ExceptionData& data_ )
							 | 
						|
								        : my_exception_data(data_)
							 | 
						|
								        , my_dynamic(false)
							 | 
						|
								        , my_exception_name(
							 | 
						|
								#if TBB_USE_EXCEPTIONS
							 | 
						|
								        typeid(self_type).name()
							 | 
						|
								#else /* !TBB_USE_EXCEPTIONS */
							 | 
						|
								        "movable_exception"
							 | 
						|
								#endif /* !TBB_USE_EXCEPTIONS */
							 | 
						|
								        )
							 | 
						|
								    {}
							 | 
						|
								
							 | 
						|
								    movable_exception ( const movable_exception& src ) throw ()
							 | 
						|
								        : tbb_exception(src)
							 | 
						|
								        , my_exception_data(src.my_exception_data)
							 | 
						|
								        , my_dynamic(false)
							 | 
						|
								        , my_exception_name(src.my_exception_name)
							 | 
						|
								    {}
							 | 
						|
								
							 | 
						|
								    ~movable_exception () throw() {}
							 | 
						|
								
							 | 
						|
								    const movable_exception& operator= ( const movable_exception& src ) {
							 | 
						|
								        if ( this != &src ) {
							 | 
						|
								            my_exception_data = src.my_exception_data;
							 | 
						|
								            my_exception_name = src.my_exception_name;
							 | 
						|
								        }
							 | 
						|
								        return *this;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    ExceptionData& data () throw() { return my_exception_data; }
							 | 
						|
								
							 | 
						|
								    const ExceptionData& data () const throw() { return my_exception_data; }
							 | 
						|
								
							 | 
						|
								    /*override*/ const char* name () const throw() { return my_exception_name; }
							 | 
						|
								
							 | 
						|
								    /*override*/ const char* what () const throw() { return "tbb::movable_exception"; }
							 | 
						|
								
							 | 
						|
								    /*override*/
							 | 
						|
								    movable_exception* move () throw() {
							 | 
						|
								        void* e = internal::allocate_via_handler_v3(sizeof(movable_exception));
							 | 
						|
								        if ( e ) {
							 | 
						|
								            ::new (e) movable_exception(*this);
							 | 
						|
								            ((movable_exception*)e)->my_dynamic = true;
							 | 
						|
								        }
							 | 
						|
								        return (movable_exception*)e;
							 | 
						|
								    }
							 | 
						|
								    /*override*/
							 | 
						|
								    void destroy () throw() {
							 | 
						|
								        __TBB_ASSERT ( my_dynamic, "Method destroy can be called only on dynamically allocated movable_exceptions" );
							 | 
						|
								        if ( my_dynamic ) {
							 | 
						|
								            this->~movable_exception();
							 | 
						|
								            internal::deallocate_via_handler_v3(this);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    /*override*/
							 | 
						|
								    void throw_self () { __TBB_THROW( *this ); }
							 | 
						|
								
							 | 
						|
								protected:
							 | 
						|
								    //! User data
							 | 
						|
								    ExceptionData  my_exception_data;
							 | 
						|
								
							 | 
						|
								private:
							 | 
						|
								    //! Flag specifying whether this object has been dynamically allocated (by the move method)
							 | 
						|
								    bool my_dynamic;
							 | 
						|
								
							 | 
						|
								    //! RTTI name of this class
							 | 
						|
								    /** We rely on the fact that RTTI names are static string constants. **/
							 | 
						|
								    const char* my_exception_name;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								#if !TBB_USE_CAPTURED_EXCEPTION
							 | 
						|
								namespace internal {
							 | 
						|
								
							 | 
						|
								//! Exception container that preserves the exact copy of the original exception
							 | 
						|
								/** This class can be used only when the appropriate runtime support (mandated
							 | 
						|
								    by C++0x) is present **/
							 | 
						|
								class tbb_exception_ptr {
							 | 
						|
								    std::exception_ptr  my_ptr;
							 | 
						|
								
							 | 
						|
								public:
							 | 
						|
								    static tbb_exception_ptr* allocate ();
							 | 
						|
								    static tbb_exception_ptr* allocate ( const tbb_exception& tag );
							 | 
						|
								    //! This overload uses move semantics (i.e. it empties src)
							 | 
						|
								    static tbb_exception_ptr* allocate ( captured_exception& src );
							 | 
						|
								
							 | 
						|
								    //! Destroys this objects
							 | 
						|
								    /** Note that objects of this type can be created only by the allocate() method. **/
							 | 
						|
								    void destroy () throw();
							 | 
						|
								
							 | 
						|
								    //! Throws the contained exception .
							 | 
						|
								    void throw_self () { std::rethrow_exception(my_ptr); }
							 | 
						|
								
							 | 
						|
								private:
							 | 
						|
								    tbb_exception_ptr ( const std::exception_ptr& src ) : my_ptr(src) {}
							 | 
						|
								    tbb_exception_ptr ( const captured_exception& src ) :
							 | 
						|
								        #if __TBB_MAKE_EXCEPTION_PTR_PRESENT
							 | 
						|
								            my_ptr(std::make_exception_ptr(src))  // the final function name in C++11
							 | 
						|
								        #else
							 | 
						|
								            my_ptr(std::copy_exception(src))      // early C++0x drafts name
							 | 
						|
								        #endif
							 | 
						|
								    {}
							 | 
						|
								}; // class tbb::internal::tbb_exception_ptr
							 | 
						|
								
							 | 
						|
								} // namespace internal
							 | 
						|
								#endif /* !TBB_USE_CAPTURED_EXCEPTION */
							 | 
						|
								
							 | 
						|
								} // namespace tbb
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_TASK_GROUP_CONTEXT */
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_exception_H */
							 |