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