]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/test/include/boost/test/execution_monitor.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / test / include / boost / test / execution_monitor.hpp
1 // (C) Copyright Gennadiy Rozental 2001.
2 // (C) Copyright Beman Dawes 2001.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 // See http://www.boost.org/libs/test for the library home page.
8 //
9 //!@file
10 //!@brief Defines public interface of the Execution Monitor and related classes
11 // ***************************************************************************
12
13 #ifndef BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER
14 #define BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER
15
16 // Boost.Test
17 #include <boost/test/detail/global_typedef.hpp>
18 #include <boost/test/detail/fwd_decl.hpp>
19 #include <boost/test/detail/throw_exception.hpp>
20
21 #include <boost/test/utils/class_properties.hpp>
22
23 // Boost
24 #include <boost/shared_ptr.hpp>
25 #include <boost/scoped_array.hpp>
26 #include <boost/type.hpp>
27 #include <boost/cstdlib.hpp>
28 #include <boost/function/function0.hpp>
29
30 #include <boost/test/detail/suppress_warnings.hpp>
31
32 #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING
33
34 // for the FP constants and control routines
35 #include <float.h>
36
37 #ifndef EM_INVALID
38 #define EM_INVALID _EM_INVALID
39 #endif
40
41 #ifndef EM_DENORMAL
42 #define EM_DENORMAL _EM_DENORMAL
43 #endif
44
45 #ifndef EM_ZERODIVIDE
46 #define EM_ZERODIVIDE _EM_ZERODIVIDE
47 #endif
48
49 #ifndef EM_OVERFLOW
50 #define EM_OVERFLOW _EM_OVERFLOW
51 #endif
52
53 #ifndef EM_UNDERFLOW
54 #define EM_UNDERFLOW _EM_UNDERFLOW
55 #endif
56
57 #ifndef MCW_EM
58 #define MCW_EM _MCW_EM
59 #endif
60
61 #else // based on ISO C standard
62
63 #if !defined(BOOST_NO_FENV_H)
64 #include <boost/detail/fenv.hpp>
65 #endif
66
67 #endif
68
69
70 // Additional macro documentations not being generated without this hack
71 #ifdef BOOST_TEST_DOXYGEN_DOC__
72
73 //! Disables the support of the alternative stack
74 //! during the compilation of the Boost.test framework. This is especially useful
75 //! in case it is not possible to detect the lack of alternative stack support for
76 //! your compiler (for instance, ESXi).
77 #define BOOST_TEST_DISABLE_ALT_STACK
78
79 #endif
80
81 //____________________________________________________________________________//
82
83 namespace boost {
84
85 /// @defgroup ExecutionMonitor Function Execution Monitor
86 /// @{
87 /// @section Intro Introduction
88 /// Sometimes we need to call a function and make sure that no user or system originated exceptions are being thrown by it. Uniform exception reporting
89 /// is also may be convenient. That's the purpose of the Boost.Test's Execution Monitor.
90 ///
91 /// The Execution Monitor is a lower-level component of the Boost Test Library. It is the base for implementing all other Boost.Test components, but also
92 /// can be used standalone to get controlled execution of error-prone functions with a uniform error notification. The Execution Monitor calls a user-supplied
93 /// function in a controlled environment, relieving users from messy error detection.
94 ///
95 /// The Execution Monitor usage is demonstrated in the example exec_mon_example.
96 ///
97 /// @section DesignRationale Design Rationale
98 ///
99 /// The Execution Monitor design assumes that it can be used when no (or almost no) memory available. Also the Execution Monitor is intended to be portable to as many platforms as possible.
100 ///
101 /// @section UserGuide User's guide
102 /// The Execution Monitor is designed to solve the problem of executing potentially dangerous function that may result in any number of error conditions,
103 /// in monitored environment that should prevent any undesirable exceptions to propagate out of function call and produce consistent result report for all outcomes.
104 /// The Execution Monitor is able to produce informative report for all standard C++ exceptions and intrinsic types. All other exceptions are reported as unknown.
105 /// If you prefer different message for your exception type or need to perform any action, the Execution Monitor supports custom exception translators.
106 /// There are several other parameters of the monitored environment can be configured by setting appropriate properties of the Execution Monitor.
107 ///
108 /// All symbols in the Execution Monitor implementation are located in the namespace boost. To use the Execution Monitor you need to:
109 /// -# include @c boost/test/execution_monitor.hpp
110 /// -# Make an instance of execution_monitor.
111 /// -# Optionally register custom exception translators for exception classes which require special processing.
112 ///
113 /// @subsection FuncExec Monitored function execution
114 ///
115 /// The class execution_monitor can monitor functions with the following signatures:
116 /// - int ()
117 /// - void ()
118 ///
119 /// This function is expected to be self sufficient part of your application. You can't pass any arguments to this function directly. Instead you
120 /// should bind them into executable nullary function using bind function (either standard or boost variant). Neither you can return any other value,
121 /// but an integer result code. If necessary you can bind output parameters by reference or use some other more complicated nullary functor, which
122 /// maintains state. This includes class methods, static class methods etc.
123 ///
124 /// To start the monitored function, invoke the method execution_monitor::execute and pass the monitored function as an argument. If the call succeeds,
125 /// the method returns the result code produced by the monitored function. If any of the following conditions occur:
126 /// - Uncaught C++ exception
127 /// - Hardware or software signal, trap, or other exception
128 /// - Timeout reached
129 /// - Debug assert event occurred (under Microsoft Visual C++ or compatible compiler)
130 ///
131 /// then the method throws the execution_exception. The exception contains unique error_code value identifying the error condition and the detailed message
132 /// that can be used to report the error.
133 ///
134 /// @subsection Reporting Errors reporting and translation
135 ///
136 /// If you need to report an error inside monitored function execution you have to throw an exception. Do not use the execution_exception - it's not intended
137 /// to be used for this purpose. The simplest choice is to use one of the following C++ types as an exception:
138 /// - C string
139 /// - std:string
140 /// - any exception class in std::exception hierarchy
141 /// - boost::exception
142 ///
143 /// execution_monitor will catch and report these types of exceptions. If exception is thrown which is unknown to execution_monitor, it can only
144 /// report the fact of the exception. So in case if you prefer to use your own exception types or can't govern what exceptions are generated by monitored
145 /// function and would like to see proper error message in a report, execution_monitor can be configured with custom "translator" routine, which will have
146 /// a chance to either record the fact of the exception itself or translate it into one of standard exceptions and rethrow (or both). The translator routine
147 /// is registered per exception type and is invoked when exception of this class (or one inherited from it) is thrown inside monitored routine. You can
148 /// register as many independent translators as you like. See execution_monitor::register_exception_translator specification for requirements on translator
149 /// function.
150 ///
151 /// Finally, if you need to abort the monitored function execution without reporting any errors, you can throw an exception execution_aborted. As a result
152 /// the execution is aborted and zero result code is produced by the method execution_monitor::execute.
153 ///
154 /// @subsection Parameters Supported parameters
155 ///
156 /// The Execution Monitor behavior is configurable through the set of parameters (properties) associated with the instance of the monitor. See execution_monitor
157 /// specification for a list of supported parameters and their semantic.
158
159 // ************************************************************************** //
160 // ************** detail::translator_holder_base ************** //
161 // ************************************************************************** //
162
163 namespace detail {
164
165 class translator_holder_base;
166 typedef boost::shared_ptr<translator_holder_base> translator_holder_base_ptr;
167
168 class BOOST_TEST_DECL translator_holder_base {
169 protected:
170 typedef boost::unit_test::const_string const_string;
171 public:
172 // Constructor
173 translator_holder_base( translator_holder_base_ptr next, const_string tag )
174 : m_next( next )
175 , m_tag( std::string() + tag )
176 {
177 }
178
179 // Destructor
180 virtual ~translator_holder_base() {}
181
182 // translator holder interface
183 // invokes the function F inside the try/catch guarding against specific exception
184 virtual int operator()( boost::function<int ()> const& F ) = 0;
185
186 // erases specific translator holder from the chain
187 translator_holder_base_ptr erase( translator_holder_base_ptr this_, const_string tag )
188 {
189 if( m_next )
190 m_next = m_next->erase( m_next, tag );
191
192 return m_tag == tag ? m_next : this_;
193 }
194 #ifndef BOOST_NO_RTTI
195 virtual translator_holder_base_ptr erase( translator_holder_base_ptr this_, std::type_info const& ) = 0;
196 template<typename ExceptionType>
197 translator_holder_base_ptr erase( translator_holder_base_ptr this_, boost::type<ExceptionType>* = 0 )
198 {
199 if( m_next )
200 m_next = m_next->erase<ExceptionType>( m_next );
201
202 return erase( this_, typeid(ExceptionType) );
203 }
204 #endif
205
206 protected:
207 // Data members
208 translator_holder_base_ptr m_next;
209 std::string m_tag;
210 };
211
212 } // namespace detail
213
214 // ************************************************************************** //
215 /// @class execution_exception
216 /// @brief This class is used to report any kind of an failure during execution of a monitored function inside of execution_monitor
217 ///
218 /// The instance of this class is thrown out of execution_monitor::execute invocation when failure is detected. Regardless of a kind of failure occurred
219 /// the instance will provide a uniform way to catch and report it.
220 ///
221 /// One important design rationale for this class is that we should be ready to work after fatal memory corruptions or out of memory conditions. To facilitate
222 /// this class never allocates any memory and assumes that strings it refers to are either some constants or live in a some kind of persistent (preallocated) memory.
223 // ************************************************************************** //
224
225 class BOOST_TEST_DECL execution_exception {
226 typedef boost::unit_test::const_string const_string;
227 public:
228 /// These values are sometimes used as program return codes.
229 /// The particular values have been chosen to avoid conflicts with
230 /// commonly used program return codes: values < 100 are often user
231 /// assigned, values > 255 are sometimes used to report system errors.
232 /// Gaps in values allow for orderly expansion.
233 ///
234 /// @note(1) Only uncaught C++ exceptions are treated as errors.
235 /// If a function catches a C++ exception, it never reaches
236 /// the execution_monitor.
237 ///
238 /// The implementation decides what is a system_fatal_error and what is
239 /// just a system_exception. Fatal errors are so likely to have corrupted
240 /// machine state (like a stack overflow or addressing exception) that it
241 /// is unreasonable to continue execution.
242 ///
243 /// @note(2) These errors include Unix signals and Windows structured
244 /// exceptions. They are often initiated by hardware traps.
245 enum error_code {
246 no_error = 0, ///< for completeness only; never returned
247 user_error = 200, ///< user reported non-fatal error
248 cpp_exception_error = 205, ///< see note (1) above
249 system_error = 210, ///< see note (2) above
250 timeout_error = 215, ///< only detectable on certain platforms
251 user_fatal_error = 220, ///< user reported fatal error
252 system_fatal_error = 225 ///< see note (2) above
253 };
254
255 /// Simple model for the location of failure in a source code
256 struct BOOST_TEST_DECL location {
257 explicit location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 );
258
259 const_string m_file_name; ///< File name
260 size_t m_line_num; ///< Line number
261 const_string m_function; ///< Function name
262 };
263
264 /// @name Constructors
265
266 /// Constructs instance based on message, location and error code
267
268 /// @param[in] ec error code
269 /// @param[in] what_msg error message
270 /// @param[in] location error location
271 execution_exception( error_code ec, const_string what_msg, location const& location );
272
273 /// @name Access methods
274
275 /// Exception error code
276 error_code code() const { return m_error_code; }
277 /// Exception message
278 const_string what() const { return m_what; }
279 /// Exception location
280 location const& where() const { return m_location; }
281 ///@}
282
283 private:
284 // Data members
285 error_code m_error_code;
286 const_string m_what;
287 location m_location;
288 }; // execution_exception
289
290 // ************************************************************************** //
291 /// @brief Function execution monitor
292
293 /// This class is used to uniformly detect and report an occurrence of several types of signals and exceptions, reducing various
294 /// errors to a uniform execution_exception that is returned to a caller.
295 ///
296 /// The executiom_monitor behavior can be customized through a set of public parameters (properties) associated with the execution_monitor instance.
297 /// All parameters are implemented as public unit_test::readwrite_property data members of the class execution_monitor.
298 // ************************************************************************** //
299
300 class BOOST_TEST_DECL execution_monitor {
301 typedef boost::unit_test::const_string const_string;
302 public:
303
304 /// Default constructor initializes all execution monitor properties
305 execution_monitor();
306
307 /// Should monitor catch system errors.
308 ///
309 /// The @em p_catch_system_errors property is a boolean flag (default value is true) specifying whether or not execution_monitor should trap system
310 /// errors/system level exceptions/signals, which would cause program to crash in a regular case (without execution_monitor).
311 /// Set this property to false, for example, if you wish to force coredump file creation. The Unit Test Framework provides a
312 /// runtime parameter @c \-\-catch_system_errors=yes to alter the behavior in monitored test cases.
313 unit_test::readwrite_property<bool> p_catch_system_errors;
314
315 /// Should monitor try to attach debugger in case of caught system error.
316 ///
317 /// The @em p_auto_start_dbg property is a boolean flag (default value is false) specifying whether or not execution_monitor should try to attach debugger
318 /// in case system error is caught.
319 unit_test::readwrite_property<bool> p_auto_start_dbg;
320
321
322 /// Specifies the seconds that elapse before a timer_error occurs.
323 ///
324 /// The @em p_timeout property is an integer timeout (in seconds) for monitored function execution. Use this parameter to monitor code with possible deadlocks
325 /// or indefinite loops. This feature is only available for some operating systems (not yet Microsoft Windows).
326 unit_test::readwrite_property<unsigned> p_timeout;
327
328 /// Should monitor use alternative stack for the signal catching.
329 ///
330 /// The @em p_use_alt_stack property is a boolean flag (default value is false) specifying whether or not execution_monitor should use an alternative stack
331 /// for the sigaction based signal catching. When enabled the signals are delivered to the execution_monitor on a stack different from current execution
332 /// stack, which is safer in case if it is corrupted by monitored function. For more details on alternative stack handling see appropriate manuals.
333 unit_test::readwrite_property<bool> p_use_alt_stack;
334
335 /// Should monitor try to detect hardware floating point exceptions (!= 0), and which specific exception to catch.
336 ///
337 /// The @em p_detect_fp_exceptions property is a boolean flag (default value is false) specifying whether or not execution_monitor should install hardware
338 /// traps for the floating point exception on platforms where it's supported.
339 unit_test::readwrite_property<unsigned> p_detect_fp_exceptions;
340
341
342 // @name Monitoring entry points
343
344 /// @brief Execution monitor entry point for functions returning integer value
345 ///
346 /// This method executes supplied function F inside a try/catch block and also may include other unspecified platform dependent error detection code.
347 ///
348 /// This method throws an execution_exception on an uncaught C++ exception, a hardware or software signal, trap, or other user exception.
349 ///
350 /// @note execute() doesn't consider it an error for F to return a non-zero value.
351 /// @param[in] F Function to monitor
352 /// @returns value returned by function call F().
353 /// @see vexecute
354 int execute( boost::function<int ()> const& F );
355
356 /// @brief Execution monitor entry point for functions returning void
357 ///
358 /// This method is semantically identical to execution_monitor::execute, but des't produce any result code.
359 /// @param[in] F Function to monitor
360 /// @see execute
361 void vexecute( boost::function<void ()> const& F );
362 // @}
363
364 // @name Exception translator registration
365
366 /// @brief Registers custom (user supplied) exception translator
367
368 /// This method template registers a translator for an exception type specified as a first template argument. For example
369 /// @code
370 /// void myExceptTr( MyException const& ex ) { /*do something with the exception here*/}
371 /// em.register_exception_translator<MyException>( myExceptTr );
372 /// @endcode
373 /// The translator should be any unary function/functor object which accepts MyException const&. This can be free standing function
374 /// or bound class method. The second argument is an optional string tag you can associate with this translator routine. The only reason
375 /// to specify the tag is if you plan to erase the translator eventually. This can be useful in scenario when you reuse the same
376 /// execution_monitor instance to monitor different routines and need to register a translator specific to the routine being monitored.
377 /// While it is possible to erase the translator based on an exception type it was registered for, tag string provides simpler way of doing this.
378 /// @tparam ExceptionType type of the exception we register a translator for
379 /// @tparam ExceptionTranslator type of the translator we register for this exception
380 /// @param[in] tr translator function object with the signature <em> void (ExceptionType const&)</em>
381 /// @param[in] tag tag associated with this translator
382 template<typename ExceptionType, typename ExceptionTranslator>
383 void register_exception_translator( ExceptionTranslator const& tr, const_string tag = const_string(), boost::type<ExceptionType>* = 0 );
384
385 /// @brief Erases custom exception translator based on a tag
386
387 /// Use the same tag as the one used during translator registration
388 /// @param[in] tag tag associated with translator you wants to erase
389 void erase_exception_translator( const_string tag )
390 {
391 m_custom_translators = m_custom_translators->erase( m_custom_translators, tag );
392 }
393 #ifndef BOOST_NO_RTTI
394 /// @brief Erases custom exception translator based on an exception type
395 ///
396 /// tparam ExceptionType Exception type for which you want to erase the translator
397 template<typename ExceptionType>
398 void erase_exception_translator( boost::type<ExceptionType>* = 0 )
399 {
400 m_custom_translators = m_custom_translators->erase<ExceptionType>( m_custom_translators );
401 }
402 //@}
403 #endif
404
405 private:
406 // implementation helpers
407 int catch_signals( boost::function<int ()> const& F );
408
409 // Data members
410 detail::translator_holder_base_ptr m_custom_translators;
411 boost::scoped_array<char> m_alt_stack;
412 }; // execution_monitor
413
414 // ************************************************************************** //
415 // ************** detail::translator_holder ************** //
416 // ************************************************************************** //
417
418 namespace detail {
419
420 template<typename ExceptionType, typename ExceptionTranslator>
421 class translator_holder : public translator_holder_base
422 {
423 public:
424 explicit translator_holder( ExceptionTranslator const& tr, translator_holder_base_ptr& next, const_string tag = const_string() )
425 : translator_holder_base( next, tag ), m_translator( tr ) {}
426
427 // translator holder interface
428 virtual int operator()( boost::function<int ()> const& F )
429 {
430 BOOST_TEST_I_TRY {
431 return m_next ? (*m_next)( F ) : F();
432 }
433 BOOST_TEST_I_CATCH( ExceptionType, e ) {
434 m_translator( e );
435 return boost::exit_exception_failure;
436 }
437 }
438 #ifndef BOOST_NO_RTTI
439 virtual translator_holder_base_ptr erase( translator_holder_base_ptr this_, std::type_info const& ti )
440 {
441 return ti == typeid(ExceptionType) ? m_next : this_;
442 }
443 #endif
444
445 private:
446 // Data members
447 ExceptionTranslator m_translator;
448 };
449
450 } // namespace detail
451
452 template<typename ExceptionType, typename ExceptionTranslator>
453 void
454 execution_monitor::register_exception_translator( ExceptionTranslator const& tr, const_string tag, boost::type<ExceptionType>* )
455 {
456 m_custom_translators.reset(
457 new detail::translator_holder<ExceptionType,ExceptionTranslator>( tr, m_custom_translators, tag ) );
458 }
459
460 // ************************************************************************** //
461 /// @class execution_aborted
462 /// @brief This is a trivial default constructible class. Use it to report graceful abortion of a monitored function execution.
463 // ************************************************************************** //
464
465 struct execution_aborted {};
466
467 // ************************************************************************** //
468 // ************** system_error ************** //
469 // ************************************************************************** //
470
471 class system_error {
472 public:
473 // Constructor
474 explicit system_error( char const* exp );
475
476 long const p_errno;
477 char const* const p_failed_exp;
478 };
479
480 //!@internal
481 #define BOOST_TEST_SYS_ASSERT( cond ) BOOST_TEST_I_ASSRT( cond, ::boost::system_error( BOOST_STRINGIZE( exp ) ) )
482
483 // ************************************************************************** //
484 // **************Floating point exception management interface ************** //
485 // ************************************************************************** //
486
487 namespace fpe {
488
489 enum masks {
490 BOOST_FPE_OFF = 0,
491
492 #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING
493 BOOST_FPE_DIVBYZERO = EM_ZERODIVIDE,
494 BOOST_FPE_INEXACT = EM_INEXACT,
495 BOOST_FPE_INVALID = EM_INVALID,
496 BOOST_FPE_OVERFLOW = EM_OVERFLOW,
497 BOOST_FPE_UNDERFLOW = EM_UNDERFLOW|EM_DENORMAL,
498
499 BOOST_FPE_ALL = MCW_EM,
500 #elif defined(BOOST_NO_FENV_H) || defined(BOOST_CLANG)
501 BOOST_FPE_ALL = 1,
502 #else
503 BOOST_FPE_DIVBYZERO = FE_DIVBYZERO,
504 BOOST_FPE_INEXACT = FE_INEXACT,
505 BOOST_FPE_INVALID = FE_INVALID,
506 BOOST_FPE_OVERFLOW = FE_OVERFLOW,
507 BOOST_FPE_UNDERFLOW = FE_UNDERFLOW,
508
509 BOOST_FPE_ALL = FE_ALL_EXCEPT,
510 #endif
511 BOOST_FPE_INV = BOOST_FPE_ALL+1
512 };
513
514 //____________________________________________________________________________//
515
516 // return the previous set of enabled exceptions when successful, and BOOST_FPE_INV otherwise
517 unsigned BOOST_TEST_DECL enable( unsigned mask );
518 unsigned BOOST_TEST_DECL disable( unsigned mask );
519
520 //____________________________________________________________________________//
521
522 } // namespace fpe
523
524 ///@}
525
526 } // namespace boost
527
528
529 #include <boost/test/detail/enable_warnings.hpp>
530
531 #endif