Chris@16
|
1 /*
|
Chris@101
|
2 * Copyright Andrey Semashev 2007 - 2015.
|
Chris@16
|
3 * Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
4 * (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 * http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6 */
|
Chris@16
|
7 /*!
|
Chris@16
|
8 * \file exception_handler_feature.hpp
|
Chris@16
|
9 * \author Andrey Semashev
|
Chris@16
|
10 * \date 17.07.2009
|
Chris@16
|
11 *
|
Chris@16
|
12 * The header contains implementation of an exception handler support feature.
|
Chris@16
|
13 */
|
Chris@16
|
14
|
Chris@16
|
15 #ifndef BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_
|
Chris@16
|
16 #define BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/mpl/if.hpp>
|
Chris@16
|
19 #include <boost/move/core.hpp>
|
Chris@16
|
20 #include <boost/move/utility.hpp>
|
Chris@16
|
21 #include <boost/type_traits/is_same.hpp>
|
Chris@16
|
22 #include <boost/log/detail/config.hpp>
|
Chris@16
|
23 #include <boost/log/detail/light_function.hpp>
|
Chris@16
|
24 #include <boost/log/detail/locks.hpp>
|
Chris@101
|
25 #include <boost/log/core/record.hpp>
|
Chris@16
|
26 #include <boost/log/sources/threading_models.hpp>
|
Chris@16
|
27 #include <boost/log/utility/strictest_lock.hpp>
|
Chris@16
|
28 #if !defined(BOOST_LOG_NO_THREADS)
|
Chris@16
|
29 #include <boost/thread/exceptions.hpp>
|
Chris@16
|
30 #endif
|
Chris@16
|
31 #include <boost/log/detail/header.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 #ifdef BOOST_HAS_PRAGMA_ONCE
|
Chris@16
|
34 #pragma once
|
Chris@16
|
35 #endif
|
Chris@16
|
36
|
Chris@16
|
37 namespace boost {
|
Chris@16
|
38
|
Chris@16
|
39 BOOST_LOG_OPEN_NAMESPACE
|
Chris@16
|
40
|
Chris@16
|
41 namespace sources {
|
Chris@16
|
42
|
Chris@16
|
43 /*!
|
Chris@16
|
44 * \brief Exception handler feature implementation
|
Chris@16
|
45 */
|
Chris@16
|
46 template< typename BaseT >
|
Chris@16
|
47 class basic_exception_handler_logger :
|
Chris@16
|
48 public BaseT
|
Chris@16
|
49 {
|
Chris@16
|
50 //! Base type
|
Chris@16
|
51 typedef BaseT base_type;
|
Chris@16
|
52 typedef basic_exception_handler_logger this_type;
|
Chris@16
|
53 BOOST_COPYABLE_AND_MOVABLE_ALT(this_type)
|
Chris@16
|
54
|
Chris@16
|
55 public:
|
Chris@16
|
56 //! Threading model being used
|
Chris@16
|
57 typedef typename base_type::threading_model threading_model;
|
Chris@16
|
58 //! Final logger type
|
Chris@16
|
59 typedef typename base_type::final_type final_type;
|
Chris@16
|
60 //! Exception handler function type
|
Chris@16
|
61 typedef boost::log::aux::light_function< void () > exception_handler_type;
|
Chris@16
|
62
|
Chris@16
|
63 #if defined(BOOST_LOG_DOXYGEN_PASS)
|
Chris@16
|
64 //! Lock requirement for the open_record_unlocked method
|
Chris@16
|
65 typedef typename strictest_lock<
|
Chris@16
|
66 typename base_type::open_record_lock,
|
Chris@16
|
67 no_lock< threading_model >
|
Chris@16
|
68 >::type open_record_lock;
|
Chris@16
|
69 //! Lock requirement for the push_record_unlocked method
|
Chris@16
|
70 typedef typename strictest_lock<
|
Chris@16
|
71 typename base_type::push_record_lock,
|
Chris@16
|
72 no_lock< threading_model >
|
Chris@16
|
73 >::type push_record_lock;
|
Chris@16
|
74 #endif // defined(BOOST_LOG_DOXYGEN_PASS)
|
Chris@16
|
75
|
Chris@16
|
76 //! Lock requirement for the swap_unlocked method
|
Chris@16
|
77 typedef typename strictest_lock<
|
Chris@16
|
78 typename base_type::swap_lock,
|
Chris@16
|
79 #ifndef BOOST_LOG_NO_THREADS
|
Chris@16
|
80 boost::log::aux::exclusive_lock_guard< threading_model >
|
Chris@16
|
81 #else
|
Chris@16
|
82 no_lock< threading_model >
|
Chris@16
|
83 #endif // !defined(BOOST_LOG_NO_THREADS)
|
Chris@16
|
84 >::type swap_lock;
|
Chris@16
|
85
|
Chris@16
|
86 private:
|
Chris@16
|
87 //! Exception handler
|
Chris@16
|
88 exception_handler_type m_ExceptionHandler;
|
Chris@16
|
89
|
Chris@16
|
90 public:
|
Chris@16
|
91 /*!
|
Chris@16
|
92 * Default constructor. The constructed logger does not have an exception handler.
|
Chris@16
|
93 */
|
Chris@16
|
94 basic_exception_handler_logger() : base_type()
|
Chris@16
|
95 {
|
Chris@16
|
96 }
|
Chris@16
|
97 /*!
|
Chris@16
|
98 * Copy constructor
|
Chris@16
|
99 */
|
Chris@16
|
100 basic_exception_handler_logger(basic_exception_handler_logger const& that) :
|
Chris@16
|
101 base_type(static_cast< base_type const& >(that)),
|
Chris@16
|
102 m_ExceptionHandler(that.m_ExceptionHandler)
|
Chris@16
|
103 {
|
Chris@16
|
104 }
|
Chris@16
|
105 /*!
|
Chris@16
|
106 * Move constructor
|
Chris@16
|
107 */
|
Chris@16
|
108 basic_exception_handler_logger(BOOST_RV_REF(basic_exception_handler_logger) that) :
|
Chris@16
|
109 base_type(boost::move(static_cast< base_type& >(that))),
|
Chris@16
|
110 m_ExceptionHandler(boost::move(that.m_ExceptionHandler))
|
Chris@16
|
111 {
|
Chris@16
|
112 }
|
Chris@16
|
113 /*!
|
Chris@16
|
114 * Constructor with arguments. Passes arguments to other features.
|
Chris@16
|
115 */
|
Chris@16
|
116 template< typename ArgsT >
|
Chris@16
|
117 explicit basic_exception_handler_logger(ArgsT const& args) :
|
Chris@16
|
118 base_type(args)
|
Chris@16
|
119 {
|
Chris@16
|
120 }
|
Chris@16
|
121
|
Chris@16
|
122 /*!
|
Chris@16
|
123 * The method sets exception handler function. The function will be called with no arguments
|
Chris@16
|
124 * in case if an exception occurs during either \c open_record or \c push_record method
|
Chris@16
|
125 * execution. Since exception handler is called from a \c catch statement, the exception
|
Chris@16
|
126 * can be rethrown in order to determine its type.
|
Chris@16
|
127 *
|
Chris@16
|
128 * By default no handler is installed, thus any exception is propagated as usual.
|
Chris@16
|
129 *
|
Chris@16
|
130 * \sa <tt>utility/exception_handler.hpp</tt>
|
Chris@16
|
131 * \param handler Exception handling function
|
Chris@16
|
132 *
|
Chris@16
|
133 * \note The exception handler can be invoked in several threads concurrently.
|
Chris@16
|
134 *
|
Chris@16
|
135 * \note Thread interruptions are not affected by exception handlers.
|
Chris@16
|
136 */
|
Chris@16
|
137 template< typename HandlerT >
|
Chris@16
|
138 void set_exception_handler(HandlerT const& handler)
|
Chris@16
|
139 {
|
Chris@16
|
140 #ifndef BOOST_LOG_NO_THREADS
|
Chris@16
|
141 boost::log::aux::exclusive_lock_guard< threading_model > lock(this->get_threading_model());
|
Chris@16
|
142 #endif
|
Chris@16
|
143 m_ExceptionHandler = handler;
|
Chris@16
|
144 }
|
Chris@16
|
145
|
Chris@16
|
146 protected:
|
Chris@16
|
147 /*!
|
Chris@16
|
148 * Unlocked \c open_record
|
Chris@16
|
149 */
|
Chris@16
|
150 template< typename ArgsT >
|
Chris@16
|
151 record open_record_unlocked(ArgsT const& args)
|
Chris@16
|
152 {
|
Chris@16
|
153 try
|
Chris@16
|
154 {
|
Chris@16
|
155 return base_type::open_record_unlocked(args);
|
Chris@16
|
156 }
|
Chris@16
|
157 #ifndef BOOST_LOG_NO_THREADS
|
Chris@16
|
158 catch (thread_interrupted&)
|
Chris@16
|
159 {
|
Chris@16
|
160 throw;
|
Chris@16
|
161 }
|
Chris@16
|
162 #endif
|
Chris@16
|
163 catch (...)
|
Chris@16
|
164 {
|
Chris@16
|
165 handle_exception();
|
Chris@16
|
166 return record();
|
Chris@16
|
167 }
|
Chris@16
|
168 }
|
Chris@16
|
169
|
Chris@16
|
170 /*!
|
Chris@16
|
171 * Unlocked \c push_record
|
Chris@16
|
172 */
|
Chris@16
|
173 void push_record_unlocked(BOOST_RV_REF(record) rec)
|
Chris@16
|
174 {
|
Chris@16
|
175 try
|
Chris@16
|
176 {
|
Chris@16
|
177 base_type::push_record_unlocked(boost::move(rec));
|
Chris@16
|
178 }
|
Chris@16
|
179 #ifndef BOOST_LOG_NO_THREADS
|
Chris@16
|
180 catch (thread_interrupted&)
|
Chris@16
|
181 {
|
Chris@16
|
182 throw;
|
Chris@16
|
183 }
|
Chris@16
|
184 #endif
|
Chris@16
|
185 catch (...)
|
Chris@16
|
186 {
|
Chris@16
|
187 handle_exception();
|
Chris@16
|
188 }
|
Chris@16
|
189 }
|
Chris@16
|
190
|
Chris@16
|
191 /*!
|
Chris@16
|
192 * Unlocked swap
|
Chris@16
|
193 */
|
Chris@16
|
194 void swap_unlocked(basic_exception_handler_logger& that)
|
Chris@16
|
195 {
|
Chris@16
|
196 base_type::swap_unlocked(static_cast< base_type& >(that));
|
Chris@16
|
197 m_ExceptionHandler.swap(that.m_ExceptionHandler);
|
Chris@16
|
198 }
|
Chris@16
|
199
|
Chris@16
|
200 private:
|
Chris@16
|
201 #if !defined(BOOST_LOG_DOXYGEN_PASS)
|
Chris@16
|
202 //! The function handles the intercepted exception
|
Chris@16
|
203 void handle_exception()
|
Chris@16
|
204 {
|
Chris@16
|
205 #ifndef BOOST_LOG_NO_THREADS
|
Chris@16
|
206 // Here's the trick with the lock type. Since the lock
|
Chris@16
|
207 // is only needed when an exception is caught, we indicate
|
Chris@16
|
208 // no locking requirements in the push_record_lock type.
|
Chris@16
|
209 // However, if other features don't require locking either,
|
Chris@16
|
210 // we shall acquire a read lock here, when an exception is caught.
|
Chris@16
|
211 // If other features do require locking, the thread model is
|
Chris@16
|
212 // already locked by now, and we don't do locking at all.
|
Chris@16
|
213 typedef typename mpl::if_<
|
Chris@16
|
214 is_same< no_lock< threading_model >, typename final_type::push_record_lock >,
|
Chris@16
|
215 boost::log::aux::shared_lock_guard< threading_model >,
|
Chris@16
|
216 no_lock< threading_model >
|
Chris@16
|
217 >::type lock_type;
|
Chris@16
|
218 lock_type lock(base_type::get_threading_model());
|
Chris@16
|
219 #endif // !defined(BOOST_LOG_NO_THREADS)
|
Chris@16
|
220
|
Chris@16
|
221 if (m_ExceptionHandler.empty())
|
Chris@16
|
222 throw;
|
Chris@16
|
223 m_ExceptionHandler();
|
Chris@16
|
224 }
|
Chris@16
|
225 #endif // !defined(BOOST_LOG_DOXYGEN_PASS)
|
Chris@16
|
226 };
|
Chris@16
|
227
|
Chris@16
|
228 /*!
|
Chris@16
|
229 * \brief Exception handler support feature
|
Chris@16
|
230 *
|
Chris@16
|
231 * The logger with this feature will provide an additional method to
|
Chris@16
|
232 * install an exception handler functional object. This functional
|
Chris@16
|
233 * object will be called if during either opening or pushing a record
|
Chris@16
|
234 * an exception is thrown from the logging core.
|
Chris@16
|
235 */
|
Chris@16
|
236 struct exception_handler
|
Chris@16
|
237 {
|
Chris@16
|
238 template< typename BaseT >
|
Chris@16
|
239 struct apply
|
Chris@16
|
240 {
|
Chris@16
|
241 typedef basic_exception_handler_logger< BaseT > type;
|
Chris@16
|
242 };
|
Chris@16
|
243 };
|
Chris@16
|
244
|
Chris@16
|
245 } // namespace sources
|
Chris@16
|
246
|
Chris@16
|
247 BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
Chris@16
|
248
|
Chris@16
|
249 } // namespace boost
|
Chris@16
|
250
|
Chris@16
|
251 #include <boost/log/detail/footer.hpp>
|
Chris@16
|
252
|
Chris@16
|
253 #endif // BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_
|