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