Chris@16: /* Chris@101: * Copyright Andrey Semashev 2007 - 2015. Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: */ Chris@16: /*! Chris@16: * \file exception_handler_feature.hpp Chris@16: * \author Andrey Semashev Chris@16: * \date 17.07.2009 Chris@16: * Chris@16: * The header contains implementation of an exception handler support feature. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_ Chris@16: #define BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #if !defined(BOOST_LOG_NO_THREADS) Chris@16: #include Chris@16: #endif Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_HAS_PRAGMA_ONCE Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: BOOST_LOG_OPEN_NAMESPACE Chris@16: Chris@16: namespace sources { Chris@16: Chris@16: /*! Chris@16: * \brief Exception handler feature implementation Chris@16: */ Chris@16: template< typename BaseT > Chris@16: class basic_exception_handler_logger : Chris@16: public BaseT Chris@16: { Chris@16: //! Base type Chris@16: typedef BaseT base_type; Chris@16: typedef basic_exception_handler_logger this_type; Chris@16: BOOST_COPYABLE_AND_MOVABLE_ALT(this_type) Chris@16: Chris@16: public: Chris@16: //! Threading model being used Chris@16: typedef typename base_type::threading_model threading_model; Chris@16: //! Final logger type Chris@16: typedef typename base_type::final_type final_type; Chris@16: //! Exception handler function type Chris@16: typedef boost::log::aux::light_function< void () > exception_handler_type; Chris@16: Chris@16: #if defined(BOOST_LOG_DOXYGEN_PASS) Chris@16: //! Lock requirement for the open_record_unlocked method Chris@16: typedef typename strictest_lock< Chris@16: typename base_type::open_record_lock, Chris@16: no_lock< threading_model > Chris@16: >::type open_record_lock; Chris@16: //! Lock requirement for the push_record_unlocked method Chris@16: typedef typename strictest_lock< Chris@16: typename base_type::push_record_lock, Chris@16: no_lock< threading_model > Chris@16: >::type push_record_lock; Chris@16: #endif // defined(BOOST_LOG_DOXYGEN_PASS) Chris@16: Chris@16: //! Lock requirement for the swap_unlocked method Chris@16: typedef typename strictest_lock< Chris@16: typename base_type::swap_lock, Chris@16: #ifndef BOOST_LOG_NO_THREADS Chris@16: boost::log::aux::exclusive_lock_guard< threading_model > Chris@16: #else Chris@16: no_lock< threading_model > Chris@16: #endif // !defined(BOOST_LOG_NO_THREADS) Chris@16: >::type swap_lock; Chris@16: Chris@16: private: Chris@16: //! Exception handler Chris@16: exception_handler_type m_ExceptionHandler; Chris@16: Chris@16: public: Chris@16: /*! Chris@16: * Default constructor. The constructed logger does not have an exception handler. Chris@16: */ Chris@16: basic_exception_handler_logger() : base_type() Chris@16: { Chris@16: } Chris@16: /*! Chris@16: * Copy constructor Chris@16: */ Chris@16: basic_exception_handler_logger(basic_exception_handler_logger const& that) : Chris@16: base_type(static_cast< base_type const& >(that)), Chris@16: m_ExceptionHandler(that.m_ExceptionHandler) Chris@16: { Chris@16: } Chris@16: /*! Chris@16: * Move constructor Chris@16: */ Chris@16: basic_exception_handler_logger(BOOST_RV_REF(basic_exception_handler_logger) that) : Chris@16: base_type(boost::move(static_cast< base_type& >(that))), Chris@16: m_ExceptionHandler(boost::move(that.m_ExceptionHandler)) Chris@16: { Chris@16: } Chris@16: /*! Chris@16: * Constructor with arguments. Passes arguments to other features. Chris@16: */ Chris@16: template< typename ArgsT > Chris@16: explicit basic_exception_handler_logger(ArgsT const& args) : Chris@16: base_type(args) Chris@16: { Chris@16: } Chris@16: Chris@16: /*! Chris@16: * The method sets exception handler function. The function will be called with no arguments Chris@16: * in case if an exception occurs during either \c open_record or \c push_record method Chris@16: * execution. Since exception handler is called from a \c catch statement, the exception Chris@16: * can be rethrown in order to determine its type. Chris@16: * Chris@16: * By default no handler is installed, thus any exception is propagated as usual. Chris@16: * Chris@16: * \sa utility/exception_handler.hpp Chris@16: * \param handler Exception handling function Chris@16: * Chris@16: * \note The exception handler can be invoked in several threads concurrently. Chris@16: * Chris@16: * \note Thread interruptions are not affected by exception handlers. Chris@16: */ Chris@16: template< typename HandlerT > Chris@16: void set_exception_handler(HandlerT const& handler) Chris@16: { Chris@16: #ifndef BOOST_LOG_NO_THREADS Chris@16: boost::log::aux::exclusive_lock_guard< threading_model > lock(this->get_threading_model()); Chris@16: #endif Chris@16: m_ExceptionHandler = handler; Chris@16: } Chris@16: Chris@16: protected: Chris@16: /*! Chris@16: * Unlocked \c open_record Chris@16: */ Chris@16: template< typename ArgsT > Chris@16: record open_record_unlocked(ArgsT const& args) Chris@16: { Chris@16: try Chris@16: { Chris@16: return base_type::open_record_unlocked(args); Chris@16: } Chris@16: #ifndef BOOST_LOG_NO_THREADS Chris@16: catch (thread_interrupted&) Chris@16: { Chris@16: throw; Chris@16: } Chris@16: #endif Chris@16: catch (...) Chris@16: { Chris@16: handle_exception(); Chris@16: return record(); Chris@16: } Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Unlocked \c push_record Chris@16: */ Chris@16: void push_record_unlocked(BOOST_RV_REF(record) rec) Chris@16: { Chris@16: try Chris@16: { Chris@16: base_type::push_record_unlocked(boost::move(rec)); Chris@16: } Chris@16: #ifndef BOOST_LOG_NO_THREADS Chris@16: catch (thread_interrupted&) Chris@16: { Chris@16: throw; Chris@16: } Chris@16: #endif Chris@16: catch (...) Chris@16: { Chris@16: handle_exception(); Chris@16: } Chris@16: } Chris@16: Chris@16: /*! Chris@16: * Unlocked swap Chris@16: */ Chris@16: void swap_unlocked(basic_exception_handler_logger& that) Chris@16: { Chris@16: base_type::swap_unlocked(static_cast< base_type& >(that)); Chris@16: m_ExceptionHandler.swap(that.m_ExceptionHandler); Chris@16: } Chris@16: Chris@16: private: Chris@16: #if !defined(BOOST_LOG_DOXYGEN_PASS) Chris@16: //! The function handles the intercepted exception Chris@16: void handle_exception() Chris@16: { Chris@16: #ifndef BOOST_LOG_NO_THREADS Chris@16: // Here's the trick with the lock type. Since the lock Chris@16: // is only needed when an exception is caught, we indicate Chris@16: // no locking requirements in the push_record_lock type. Chris@16: // However, if other features don't require locking either, Chris@16: // we shall acquire a read lock here, when an exception is caught. Chris@16: // If other features do require locking, the thread model is Chris@16: // already locked by now, and we don't do locking at all. Chris@16: typedef typename mpl::if_< Chris@16: is_same< no_lock< threading_model >, typename final_type::push_record_lock >, Chris@16: boost::log::aux::shared_lock_guard< threading_model >, Chris@16: no_lock< threading_model > Chris@16: >::type lock_type; Chris@16: lock_type lock(base_type::get_threading_model()); Chris@16: #endif // !defined(BOOST_LOG_NO_THREADS) Chris@16: Chris@16: if (m_ExceptionHandler.empty()) Chris@16: throw; Chris@16: m_ExceptionHandler(); Chris@16: } Chris@16: #endif // !defined(BOOST_LOG_DOXYGEN_PASS) Chris@16: }; Chris@16: Chris@16: /*! Chris@16: * \brief Exception handler support feature Chris@16: * Chris@16: * The logger with this feature will provide an additional method to Chris@16: * install an exception handler functional object. This functional Chris@16: * object will be called if during either opening or pushing a record Chris@16: * an exception is thrown from the logging core. Chris@16: */ Chris@16: struct exception_handler Chris@16: { Chris@16: template< typename BaseT > Chris@16: struct apply Chris@16: { Chris@16: typedef basic_exception_handler_logger< BaseT > type; Chris@16: }; Chris@16: }; Chris@16: Chris@16: } // namespace sources Chris@16: Chris@16: BOOST_LOG_CLOSE_NAMESPACE // namespace log Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_