]> git.sesse.net Git - casparcg/blob - tbb30_20100406oss/include/tbb/tbb_exception.h
3e1eecd851f748be23cf631ba4c70e66e4414495
[casparcg] / tbb30_20100406oss / include / tbb / tbb_exception.h
1 /*
2     Copyright 2005-2010 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 <stdexcept>
41
42 #if !TBB_USE_EXCEPTIONS && _MSC_VER
43     #pragma warning (pop)
44 #endif
45
46 #if __SUNPRO_CC
47 #include <string> // required to construct std exception classes
48 #endif
49
50 namespace tbb {
51
52 //! Exception for concurrent containers
53 class bad_last_alloc : public std::bad_alloc {
54 public:
55     /*override*/ const char* what() const throw();
56 #if __TBB_DEFAULT_DTOR_THROW_SPEC_BROKEN
57     /*override*/ ~bad_last_alloc() throw() {}
58 #endif
59 };
60
61 //! Exception for PPL locks
62 class improper_lock : public std::exception {
63 public:
64     /*override*/ const char* what() const throw();
65 };
66
67 //! Exception for missing wait on structured_task_group
68 class missing_wait : public std::exception {
69 public:
70     /*override*/ const char* what() const throw();
71 };
72
73 //! Exception for repeated scheduling of the same task_handle 
74 class invalid_multiple_scheduling : public std::exception {
75 public:
76     /*override*/ const char* what() const throw();
77 };
78
79 namespace internal {
80 //! Obsolete
81 void __TBB_EXPORTED_FUNC throw_bad_last_alloc_exception_v4();
82
83 enum exception_id {
84     eid_bad_alloc = 1,
85     eid_bad_last_alloc,
86     eid_nonpositive_step,
87     eid_out_of_range,
88     eid_segment_range_error,
89     eid_index_range_error,
90     eid_missing_wait,
91     eid_invalid_multiple_scheduling,
92     eid_improper_lock,
93     eid_possible_deadlock,
94     eid_operation_not_permitted,
95     eid_condvar_wait_failed,
96     eid_invalid_load_factor,
97     eid_invalid_buckets_number,
98     eid_invalid_swap,
99     eid_reservation_length_error,
100     eid_invalid_key,
101     //! The last enumerator tracks the number of defined IDs. It must remain the last one.
102     /** When adding new IDs, place them immediately _before_ this comment (that is
103         _after_ all the existing IDs. NEVER insert new IDs between the existing ones. **/
104     eid_max
105 };
106
107 //! Gathers all throw operators in one place.
108 /** Its purpose is to minimize code bloat that can be caused by throw operators 
109     scattered in multiple places, especially in templates. **/
110 void __TBB_EXPORTED_FUNC throw_exception_v4 ( exception_id );
111
112 //! Versionless convenience wrapper for throw_exception_v4()
113 inline void throw_exception ( exception_id eid ) { throw_exception_v4(eid); }
114
115 } // namespace internal
116 } // namespace tbb
117
118 #if __TBB_TASK_GROUP_CONTEXT
119 #include "tbb_allocator.h"
120 #include <exception>
121 #include <typeinfo>
122 #include <new>
123
124 namespace tbb {
125
126 //! Interface to be implemented by all exceptions TBB recognizes and propagates across the threads.
127 /** If an unhandled exception of the type derived from tbb::tbb_exception is intercepted
128     by the TBB scheduler in one of the worker threads, it is delivered to and re-thrown in
129     the root thread. The root thread is the thread that has started the outermost algorithm 
130     or root task sharing the same task_group_context with the guilty algorithm/task (the one
131     that threw the exception first).
132     
133     Note: when documentation mentions workers with respect to exception handling, 
134     masters are implied as well, because they are completely equivalent in this context.
135     Consequently a root thread can be master or worker thread. 
136
137     NOTE: In case of nested algorithms or complex task hierarchies when the nested 
138     levels share (explicitly or by means of implicit inheritance) the task group 
139     context of the outermost level, the exception may be (re-)thrown multiple times 
140     (ultimately - in each worker on each nesting level) before reaching the root 
141     thread at the outermost level. IMPORTANT: if you intercept an exception derived 
142     from this class on a nested level, you must re-throw it in the catch block by means
143     of the "throw;" operator. 
144     
145     TBB provides two implementations of this interface: tbb::captured_exception and 
146     template class tbb::movable_exception. See their declarations for more info. **/
147 class tbb_exception : public std::exception
148 {
149     /** No operator new is provided because the TBB usage model assumes dynamic 
150         creation of the TBB exception objects only by means of applying move()
151         operation on an exception thrown out of TBB scheduler. **/
152     void* operator new ( size_t );
153
154 public:
155     //! Creates and returns pointer to the deep copy of this exception object. 
156     /** Move semantics is allowed. **/
157     virtual tbb_exception* move () throw() = 0;
158     
159     //! Destroys objects created by the move() method.
160     /** Frees memory and calls destructor for this exception object. 
161         Can and must be used only on objects created by the move method. **/
162     virtual void destroy () throw() = 0;
163
164     //! Throws this exception object.
165     /** Make sure that if you have several levels of derivation from this interface
166         you implement or override this method on the most derived level. The implementation 
167         is as simple as "throw *this;". Failure to do this will result in exception 
168         of a base class type being thrown. **/
169     virtual void throw_self () = 0;
170
171     //! Returns RTTI name of the originally intercepted exception
172     virtual const char* name() const throw() = 0;
173
174     //! Returns the result of originally intercepted exception's what() method.
175     virtual const char* what() const throw() = 0;
176
177     /** Operator delete is provided only to allow using existing smart pointers
178         with TBB exception objects obtained as the result of applying move()
179         operation on an exception thrown out of TBB scheduler. 
180         
181         When overriding method move() make sure to override operator delete as well
182         if memory is allocated not by TBB's scalable allocator. **/
183     void operator delete ( void* p ) {
184         internal::deallocate_via_handler_v3(p);
185     }
186 };
187
188 //! This class is used by TBB to propagate information about unhandled exceptions into the root thread.
189 /** Exception of this type is thrown by TBB in the root thread (thread that started a parallel 
190     algorithm ) if an unhandled exception was intercepted during the algorithm execution in one 
191     of the workers.
192     \sa tbb::tbb_exception **/
193 class captured_exception : public tbb_exception
194 {
195 public:
196     captured_exception ( const captured_exception& src )
197         : tbb_exception(src), my_dynamic(false)
198     {
199         set(src.my_exception_name, src.my_exception_info);
200     }
201
202     captured_exception ( const char* name_, const char* info )
203         : my_dynamic(false)
204     {
205         set(name_, info);
206     }
207
208     __TBB_EXPORTED_METHOD ~captured_exception () throw() {
209         clear();
210     }
211
212     captured_exception& operator= ( const captured_exception& src ) {
213         if ( this != &src ) {
214             clear();
215             set(src.my_exception_name, src.my_exception_info);
216         }
217         return *this;
218     }
219
220     /*override*/ 
221     captured_exception* __TBB_EXPORTED_METHOD move () throw();
222
223     /*override*/ 
224     void __TBB_EXPORTED_METHOD destroy () throw();
225
226     /*override*/ 
227     void throw_self () { __TBB_THROW(*this); }
228
229     /*override*/ 
230     const char* __TBB_EXPORTED_METHOD name() const throw();
231
232     /*override*/ 
233     const char* __TBB_EXPORTED_METHOD what() const throw();
234
235     void __TBB_EXPORTED_METHOD set ( const char* name, const char* info ) throw();
236     void __TBB_EXPORTED_METHOD clear () throw();
237
238 private:
239     //! Used only by method clone().  
240     captured_exception() {}
241
242     //! Functionally equivalent to {captured_exception e(name,info); return e.clone();}
243     static captured_exception* allocate ( const char* name, const char* info );
244
245     bool my_dynamic;
246     const char* my_exception_name;
247     const char* my_exception_info;
248 };
249
250 //! Template that can be used to implement exception that transfers arbitrary ExceptionData to the root thread
251 /** Code using TBB can instantiate this template with an arbitrary ExceptionData type 
252     and throw this exception object. Such exceptions are intercepted by the TBB scheduler
253     and delivered to the root thread (). 
254     \sa tbb::tbb_exception **/
255 template<typename ExceptionData>
256 class movable_exception : public tbb_exception
257 {
258     typedef movable_exception<ExceptionData> self_type;
259
260 public:
261     movable_exception ( const ExceptionData& data_ ) 
262         : my_exception_data(data_)
263         , my_dynamic(false)
264         , my_exception_name(
265 #if TBB_USE_EXCEPTIONS
266         typeid(self_type).name()
267 #else /* !TBB_USE_EXCEPTIONS */
268         "movable_exception"
269 #endif /* !TBB_USE_EXCEPTIONS */
270         )
271     {}
272
273     movable_exception ( const movable_exception& src ) throw () 
274         : tbb_exception(src)
275         , my_exception_data(src.my_exception_data)
276         , my_dynamic(false)
277         , my_exception_name(src.my_exception_name)
278     {}
279
280     ~movable_exception () throw() {}
281
282     const movable_exception& operator= ( const movable_exception& src ) {
283         if ( this != &src ) {
284             my_exception_data = src.my_exception_data;
285             my_exception_name = src.my_exception_name;
286         }
287         return *this;
288     }
289
290     ExceptionData& data () throw() { return my_exception_data; }
291
292     const ExceptionData& data () const throw() { return my_exception_data; }
293
294     /*override*/ const char* name () const throw() { return my_exception_name; }
295
296     /*override*/ const char* what () const throw() { return "tbb::movable_exception"; }
297
298     /*override*/ 
299     movable_exception* move () throw() {
300         void* e = internal::allocate_via_handler_v3(sizeof(movable_exception));
301         if ( e ) {
302             ::new (e) movable_exception(*this);
303             ((movable_exception*)e)->my_dynamic = true;
304         }
305         return (movable_exception*)e;
306     }
307     /*override*/ 
308     void destroy () throw() {
309         __TBB_ASSERT ( my_dynamic, "Method destroy can be called only on dynamically allocated movable_exceptions" );
310         if ( my_dynamic ) {
311             this->~movable_exception();
312             internal::deallocate_via_handler_v3(this);
313         }
314     }
315     /*override*/ 
316     void throw_self () { __TBB_THROW( *this ); }
317
318 protected:
319     //! User data
320     ExceptionData  my_exception_data;
321
322 private:
323     //! Flag specifying whether this object has been dynamically allocated (by the move method)
324     bool my_dynamic;
325
326     //! RTTI name of this class
327     /** We rely on the fact that RTTI names are static string constants. **/
328     const char* my_exception_name;
329 };
330
331 #if !TBB_USE_CAPTURED_EXCEPTION
332 namespace internal {
333
334 //! Exception container that preserves the exact copy of the original exception
335 /** This class can be used only when the appropriate runtime support (mandated 
336     by C++0x) is present **/
337 class tbb_exception_ptr {
338     std::exception_ptr  my_ptr;
339
340 public:
341     static tbb_exception_ptr* allocate ();
342     static tbb_exception_ptr* allocate ( const tbb_exception& tag );
343     //! This overload uses move semantics (i.e. it empties src)
344     static tbb_exception_ptr* allocate ( captured_exception& src );
345     
346     //! Destroys this objects
347     /** Note that objects of this type can be created only by the allocate() method. **/
348     void destroy () throw();
349
350     //! Throws the contained exception .
351     void throw_self () { std::rethrow_exception(my_ptr); }
352
353 private:
354     tbb_exception_ptr ( const std::exception_ptr& src ) : my_ptr(src) {}
355     tbb_exception_ptr ( const captured_exception& src ) : my_ptr(std::copy_exception(src)) {}
356 }; // class tbb::internal::tbb_exception_ptr
357
358 } // namespace internal
359 #endif /* !TBB_USE_CAPTURED_EXCEPTION */
360
361 } // namespace tbb
362
363 #endif /* __TBB_TASK_GROUP_CONTEXT */
364
365 #endif /* __TBB_exception_H */