1/*
2 Copyright 2005-2013 Intel Corporation. All Rights Reserved.
3
4 This file is part of Threading Building Blocks.
5
6 Threading Building Blocks is free software; you can redistribute it
7 and/or modify it under the terms of the GNU General Public License
8 version 2 as published by the Free Software Foundation.
9
10 Threading Building Blocks is distributed in the hope that it will be
11 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Threading Building Blocks; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 As a special exception, you may use this file as part of a free software
20 library without restriction. Specifically, if other files instantiate
21 templates or use macros or inline functions from this file, or you compile
22 this file and link it with other files to produce an executable, this
23 file does not by itself cause the resulting executable to be covered by
24 the GNU General Public License. This exception does not however
25 invalidate any other reasons why the executable file might be covered by
26 the GNU General Public License.
27*/
28
29#ifndef __TBB_exception_H
30#define __TBB_exception_H
31
32#include "tbb_stddef.h"
33
34#if !TBB_USE_EXCEPTIONS && _MSC_VER
35 // Suppress "C++ exception handler used, but unwind semantics are not enabled" warning in STL headers
36 #pragma warning (push)
37 #pragma warning (disable: 4530)
38#endif
39
40#include <exception>
41#include <new> //required for bad_alloc definition, operators new
42#include <string> // required to construct std exception classes
43
44#if !TBB_USE_EXCEPTIONS && _MSC_VER
45 #pragma warning (pop)
46#endif
47
48namespace tbb {
49
50//! Exception for concurrent containers
51class bad_last_alloc : public std::bad_alloc {
52public:
53 /*override*/ const char* what() const throw();
54#if __TBB_DEFAULT_DTOR_THROW_SPEC_BROKEN
55 /*override*/ ~bad_last_alloc() throw() {}
56#endif
57};
58
59//! Exception for PPL locks
60class improper_lock : public std::exception {
61public:
62 /*override*/ const char* what() const throw();
63};
64
65//! Exception for user-initiated abort
66class user_abort : public std::exception {
67public:
68 /*override*/ const char* what() const throw();
69};
70
71//! Exception for missing wait on structured_task_group
72class missing_wait : public std::exception {
73public:
74 /*override*/ const char* what() const throw();
75};
76
77//! Exception for repeated scheduling of the same task_handle
78class invalid_multiple_scheduling : public std::exception {
79public:
80 /*override*/ const char* what() const throw();
81};
82
83namespace internal {
84//! Obsolete
85void __TBB_EXPORTED_FUNC throw_bad_last_alloc_exception_v4();
86
87enum exception_id {
88 eid_bad_alloc = 1,
89 eid_bad_last_alloc,
90 eid_nonpositive_step,
91 eid_out_of_range,
92 eid_segment_range_error,
93 eid_index_range_error,
94 eid_missing_wait,
95 eid_invalid_multiple_scheduling,
96 eid_improper_lock,
97 eid_possible_deadlock,
98 eid_operation_not_permitted,
99 eid_condvar_wait_failed,
100 eid_invalid_load_factor,
101 eid_reserved, // free slot for backward compatibility, can be reused.
102 eid_invalid_swap,
103 eid_reservation_length_error,
104 eid_invalid_key,
105 eid_user_abort,
106 eid_reserved1,
107#if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE
108 // This id is used only inside library and only for support of CPF functionality.
109 // So, if we drop the functionality, eid_reserved1 can be safely renamed and reused.
110 eid_blocking_sch_init = eid_reserved1,
111#endif
112 //! The last enumerator tracks the number of defined IDs. It must remain the last one.
113 /** When adding new IDs, place them immediately _before_ this comment (that is
114 _after_ all the existing IDs. NEVER insert new IDs between the existing ones. **/
115 eid_max
116};
117
118//! Gathers all throw operators in one place.
119/** Its purpose is to minimize code bloat that can be caused by throw operators
120 scattered in multiple places, especially in templates. **/
121void __TBB_EXPORTED_FUNC throw_exception_v4 ( exception_id );
122
123//! Versionless convenience wrapper for throw_exception_v4()
124inline void throw_exception ( exception_id eid ) { throw_exception_v4(eid); }
125
126} // namespace internal
127} // namespace tbb
128
129#if __TBB_TASK_GROUP_CONTEXT
130#include "tbb_allocator.h"
131#include <typeinfo> //for typeid
132
133namespace tbb {
134
135//! Interface to be implemented by all exceptions TBB recognizes and propagates across the threads.
136/** If an unhandled exception of the type derived from tbb::tbb_exception is intercepted
137 by the TBB scheduler in one of the worker threads, it is delivered to and re-thrown in
138 the root thread. The root thread is the thread that has started the outermost algorithm
139 or root task sharing the same task_group_context with the guilty algorithm/task (the one
140 that threw the exception first).
141
142 Note: when documentation mentions workers with respect to exception handling,
143 masters are implied as well, because they are completely equivalent in this context.
144 Consequently a root thread can be master or worker thread.
145
146 NOTE: In case of nested algorithms or complex task hierarchies when the nested
147 levels share (explicitly or by means of implicit inheritance) the task group
148 context of the outermost level, the exception may be (re-)thrown multiple times
149 (ultimately - in each worker on each nesting level) before reaching the root
150 thread at the outermost level. IMPORTANT: if you intercept an exception derived
151 from this class on a nested level, you must re-throw it in the catch block by means
152 of the "throw;" operator.
153
154 TBB provides two implementations of this interface: tbb::captured_exception and
155 template class tbb::movable_exception. See their declarations for more info. **/
156class tbb_exception : public std::exception
157{
158 /** No operator new is provided because the TBB usage model assumes dynamic
159 creation of the TBB exception objects only by means of applying move()
160 operation on an exception thrown out of TBB scheduler. **/
161 void* operator new ( size_t );
162
163public:
164#if __clang__
165 // At -O3 or even -O2 optimization level, Clang may fully throw away an empty destructor
166 // of tbb_exception from destructors of derived classes. As a result, it does not create
167 // vtable for tbb_exception, which is a required part of TBB binary interface.
168 // Making the destructor non-empty (with just a semicolon) prevents that optimization.
169 ~tbb_exception() throw() { /* keep the semicolon! */ ; }
170#endif
171
172 //! Creates and returns pointer to the deep copy of this exception object.
173 /** Move semantics is allowed. **/
174 virtual tbb_exception* move () throw() = 0;
175
176 //! Destroys objects created by the move() method.
177 /** Frees memory and calls destructor for this exception object.
178 Can and must be used only on objects created by the move method. **/
179 virtual void destroy () throw() = 0;
180
181 //! Throws this exception object.
182 /** Make sure that if you have several levels of derivation from this interface
183 you implement or override this method on the most derived level. The implementation
184 is as simple as "throw *this;". Failure to do this will result in exception
185 of a base class type being thrown. **/
186 virtual void throw_self () = 0;
187
188 //! Returns RTTI name of the originally intercepted exception
189 virtual const char* name() const throw() = 0;
190
191 //! Returns the result of originally intercepted exception's what() method.
192 virtual const char* what() const throw() = 0;
193
194 /** Operator delete is provided only to allow using existing smart pointers
195 with TBB exception objects obtained as the result of applying move()
196 operation on an exception thrown out of TBB scheduler.
197
198 When overriding method move() make sure to override operator delete as well
199 if memory is allocated not by TBB's scalable allocator. **/
200 void operator delete ( void* p ) {
201 internal::deallocate_via_handler_v3(p);
202 }
203};
204
205//! This class is used by TBB to propagate information about unhandled exceptions into the root thread.
206/** Exception of this type is thrown by TBB in the root thread (thread that started a parallel
207 algorithm ) if an unhandled exception was intercepted during the algorithm execution in one
208 of the workers.
209 \sa tbb::tbb_exception **/
210class captured_exception : public tbb_exception
211{
212public:
213 captured_exception ( const captured_exception& src )
214 : tbb_exception(src), my_dynamic(false)
215 {
216 set(src.my_exception_name, src.my_exception_info);
217 }
218
219 captured_exception ( const char* name_, const char* info )
220 : my_dynamic(false)
221 {
222 set(name_, info);
223 }
224
225 __TBB_EXPORTED_METHOD ~captured_exception () throw();
226
227 captured_exception& operator= ( const captured_exception& src ) {
228 if ( this != &src ) {
229 clear();
230 set(src.my_exception_name, src.my_exception_info);
231 }
232 return *this;
233 }
234
235 /*override*/
236 captured_exception* __TBB_EXPORTED_METHOD move () throw();
237
238 /*override*/
239 void __TBB_EXPORTED_METHOD destroy () throw();
240
241 /*override*/
242 void throw_self () { __TBB_THROW(*this); }
243
244 /*override*/
245 const char* __TBB_EXPORTED_METHOD name() const throw();
246
247 /*override*/
248 const char* __TBB_EXPORTED_METHOD what() const throw();
249
250 void __TBB_EXPORTED_METHOD set ( const char* name, const char* info ) throw();
251 void __TBB_EXPORTED_METHOD clear () throw();
252
253private:
254 //! Used only by method clone().
255 captured_exception() {}
256
257 //! Functionally equivalent to {captured_exception e(name,info); return e.clone();}
258 static captured_exception* allocate ( const char* name, const char* info );
259
260 bool my_dynamic;
261 const char* my_exception_name;
262 const char* my_exception_info;
263};
264
265//! Template that can be used to implement exception that transfers arbitrary ExceptionData to the root thread
266/** Code using TBB can instantiate this template with an arbitrary ExceptionData type
267 and throw this exception object. Such exceptions are intercepted by the TBB scheduler
268 and delivered to the root thread ().
269 \sa tbb::tbb_exception **/
270template<typename ExceptionData>
271class movable_exception : public tbb_exception
272{
273 typedef movable_exception<ExceptionData> self_type;
274
275public:
276 movable_exception ( const ExceptionData& data_ )
277 : my_exception_data(data_)
278 , my_dynamic(false)
279 , my_exception_name(
280#if TBB_USE_EXCEPTIONS
281 typeid(self_type).name()
282#else /* !TBB_USE_EXCEPTIONS */
283 "movable_exception"
284#endif /* !TBB_USE_EXCEPTIONS */
285 )
286 {}
287
288 movable_exception ( const movable_exception& src ) throw ()
289 : tbb_exception(src)
290 , my_exception_data(src.my_exception_data)
291 , my_dynamic(false)
292 , my_exception_name(src.my_exception_name)
293 {}
294
295 ~movable_exception () throw() {}
296
297 const movable_exception& operator= ( const movable_exception& src ) {
298 if ( this != &src ) {
299 my_exception_data = src.my_exception_data;
300 my_exception_name = src.my_exception_name;
301 }
302 return *this;
303 }
304
305 ExceptionData& data () throw() { return my_exception_data; }
306
307 const ExceptionData& data () const throw() { return my_exception_data; }
308
309 /*override*/ const char* name () const throw() { return my_exception_name; }
310
311 /*override*/ const char* what () const throw() { return "tbb::movable_exception"; }
312
313 /*override*/
314 movable_exception* move () throw() {
315 void* e = internal::allocate_via_handler_v3(sizeof(movable_exception));
316 if ( e ) {
317 ::new (e) movable_exception(*this);
318 ((movable_exception*)e)->my_dynamic = true;
319 }
320 return (movable_exception*)e;
321 }
322 /*override*/
323 void destroy () throw() {
324 __TBB_ASSERT ( my_dynamic, "Method destroy can be called only on dynamically allocated movable_exceptions" );
325 if ( my_dynamic ) {
326 this->~movable_exception();
327 internal::deallocate_via_handler_v3(this);
328 }
329 }
330 /*override*/
331 void throw_self () { __TBB_THROW( *this ); }
332
333protected:
334 //! User data
335 ExceptionData my_exception_data;
336
337private:
338 //! Flag specifying whether this object has been dynamically allocated (by the move method)
339 bool my_dynamic;
340
341 //! RTTI name of this class
342 /** We rely on the fact that RTTI names are static string constants. **/
343 const char* my_exception_name;
344};
345
346#if !TBB_USE_CAPTURED_EXCEPTION
347namespace internal {
348
349//! Exception container that preserves the exact copy of the original exception
350/** This class can be used only when the appropriate runtime support (mandated
351 by C++0x) is present **/
352class tbb_exception_ptr {
353 std::exception_ptr my_ptr;
354
355public:
356 static tbb_exception_ptr* allocate ();
357 static tbb_exception_ptr* allocate ( const tbb_exception& tag );
358 //! This overload uses move semantics (i.e. it empties src)
359 static tbb_exception_ptr* allocate ( captured_exception& src );
360
361 //! Destroys this objects
362 /** Note that objects of this type can be created only by the allocate() method. **/
363 void destroy () throw();
364
365 //! Throws the contained exception .
366 void throw_self () { std::rethrow_exception(my_ptr); }
367
368private:
369 tbb_exception_ptr ( const std::exception_ptr& src ) : my_ptr(src) {}
370 tbb_exception_ptr ( const captured_exception& src ) :
371 #if __TBB_MAKE_EXCEPTION_PTR_PRESENT
372 my_ptr(std::make_exception_ptr(src)) // the final function name in C++11
373 #else
374 my_ptr(std::copy_exception(src)) // early C++0x drafts name
375 #endif
376 {}
377}; // class tbb::internal::tbb_exception_ptr
378
379} // namespace internal
380#endif /* !TBB_USE_CAPTURED_EXCEPTION */
381
382} // namespace tbb
383
384#endif /* __TBB_TASK_GROUP_CONTEXT */
385
386#endif /* __TBB_exception_H */
387