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 */
 |