Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:25

0001 /*
0002  *          Copyright Andrey Semashev 2007 - 2015.
0003  * Distributed under the Boost Software License, Version 1.0.
0004  *    (See accompanying file LICENSE_1_0.txt or copy at
0005  *          http://www.boost.org/LICENSE_1_0.txt)
0006  */
0007 /*!
0008  * \file   basic_sink_frontend.hpp
0009  * \author Andrey Semashev
0010  * \date   14.07.2009
0011  *
0012  * The header contains implementation of a base class for sink frontends.
0013  */
0014 
0015 #ifndef BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
0016 #define BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
0017 
0018 #include <boost/type_traits/integral_constant.hpp>
0019 #include <boost/log/detail/config.hpp>
0020 #include <boost/log/detail/code_conversion.hpp>
0021 #include <boost/log/detail/attachable_sstream_buf.hpp>
0022 #include <boost/log/detail/fake_mutex.hpp>
0023 #include <boost/log/core/record_view.hpp>
0024 #include <boost/log/sinks/sink.hpp>
0025 #include <boost/log/sinks/frontend_requirements.hpp>
0026 #include <boost/log/expressions/filter.hpp>
0027 #include <boost/log/expressions/formatter.hpp>
0028 #if !defined(BOOST_LOG_NO_THREADS)
0029 #include <boost/memory_order.hpp>
0030 #include <boost/atomic/atomic.hpp>
0031 #include <boost/thread/exceptions.hpp>
0032 #include <boost/thread/tss.hpp>
0033 #include <boost/log/detail/locks.hpp>
0034 #include <boost/log/detail/light_rw_mutex.hpp>
0035 #endif // !defined(BOOST_LOG_NO_THREADS)
0036 #include <boost/log/detail/header.hpp>
0037 
0038 #ifdef BOOST_HAS_PRAGMA_ONCE
0039 #pragma once
0040 #endif
0041 
0042 namespace boost {
0043 
0044 BOOST_LOG_OPEN_NAMESPACE
0045 
0046 namespace sinks {
0047 
0048 //! A base class for a logging sink frontend
0049 class BOOST_LOG_NO_VTABLE basic_sink_frontend :
0050     public sink
0051 {
0052     //! Base type
0053     typedef sink base_type;
0054 
0055 public:
0056     //! An exception handler type
0057     typedef base_type::exception_handler_type exception_handler_type;
0058 
0059 #if !defined(BOOST_LOG_NO_THREADS)
0060 protected:
0061     //! Mutex type
0062     typedef boost::log::aux::light_rw_mutex mutex_type;
0063 
0064 private:
0065     //! Synchronization mutex
0066     mutable mutex_type m_Mutex;
0067 #endif
0068 
0069 private:
0070     //! Filter
0071     filter m_Filter;
0072     //! Exception handler
0073     exception_handler_type m_ExceptionHandler;
0074 
0075 public:
0076     /*!
0077      * \brief Initializing constructor
0078      *
0079      * \param cross_thread The flag indicates whether the sink passes log records between different threads
0080      */
0081     explicit basic_sink_frontend(bool cross_thread) : sink(cross_thread)
0082     {
0083     }
0084 
0085     /*!
0086      * The method sets sink-specific filter functional object
0087      */
0088     template< typename FunT >
0089     void set_filter(FunT const& filter)
0090     {
0091         BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
0092         m_Filter = filter;
0093     }
0094     /*!
0095      * The method resets the filter
0096      */
0097     void reset_filter()
0098     {
0099         BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
0100         m_Filter.reset();
0101     }
0102 
0103     /*!
0104      * The method sets an exception handler function
0105      */
0106     template< typename FunT >
0107     void set_exception_handler(FunT const& handler)
0108     {
0109         BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
0110         m_ExceptionHandler = handler;
0111     }
0112 
0113     /*!
0114      * The method resets the exception handler function
0115      */
0116     void reset_exception_handler()
0117     {
0118         BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
0119         m_ExceptionHandler.clear();
0120     }
0121 
0122     /*!
0123      * The method returns \c true if no filter is set or the attribute values pass the filter
0124      *
0125      * \param attrs A set of attribute values of a logging record
0126      */
0127     bool will_consume(attribute_value_set const& attrs) BOOST_OVERRIDE
0128     {
0129         BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
0130         try
0131         {
0132             return m_Filter(attrs);
0133         }
0134 #if !defined(BOOST_LOG_NO_THREADS)
0135         catch (thread_interrupted&)
0136         {
0137             throw;
0138         }
0139 #endif
0140         catch (...)
0141         {
0142             if (m_ExceptionHandler.empty())
0143                 throw;
0144             m_ExceptionHandler();
0145             return false;
0146         }
0147     }
0148 
0149 protected:
0150 #if !defined(BOOST_LOG_NO_THREADS)
0151     //! Returns reference to the frontend mutex
0152     mutex_type& frontend_mutex() const { return m_Mutex; }
0153 #endif
0154 
0155     //! Returns reference to the exception handler
0156     exception_handler_type& exception_handler() { return m_ExceptionHandler; }
0157     //! Returns reference to the exception handler
0158     exception_handler_type const& exception_handler() const { return m_ExceptionHandler; }
0159 
0160     //! Feeds log record to the backend
0161     template< typename BackendMutexT, typename BackendT >
0162     void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
0163     {
0164         try
0165         {
0166             BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
0167             backend.consume(rec);
0168         }
0169 #if !defined(BOOST_LOG_NO_THREADS)
0170         catch (thread_interrupted&)
0171         {
0172             throw;
0173         }
0174 #endif
0175         catch (...)
0176         {
0177             BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
0178             if (m_ExceptionHandler.empty())
0179                 throw;
0180             m_ExceptionHandler();
0181         }
0182     }
0183 
0184     //! Attempts to feeds log record to the backend, does not block if \a backend_mutex is locked
0185     template< typename BackendMutexT, typename BackendT >
0186     bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
0187     {
0188 #if !defined(BOOST_LOG_NO_THREADS)
0189         try
0190         {
0191             if (!backend_mutex.try_lock())
0192                 return false;
0193         }
0194         catch (thread_interrupted&)
0195         {
0196             throw;
0197         }
0198         catch (...)
0199         {
0200             boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex());
0201             if (this->exception_handler().empty())
0202                 throw;
0203             this->exception_handler()();
0204             return false;
0205         }
0206 
0207         boost::log::aux::exclusive_auto_unlocker< BackendMutexT > unlocker(backend_mutex);
0208 #endif
0209         // No need to lock anything in the feed_record method
0210         boost::log::aux::fake_mutex m;
0211         feed_record(rec, m, backend);
0212         return true;
0213     }
0214 
0215     //! Flushes record buffers in the backend, if one supports it
0216     template< typename BackendMutexT, typename BackendT >
0217     void flush_backend(BackendMutexT& backend_mutex, BackendT& backend)
0218     {
0219         typedef typename BackendT::frontend_requirements frontend_requirements;
0220         flush_backend_impl(backend_mutex, backend,
0221             typename has_requirement< frontend_requirements, flushing >::type());
0222     }
0223 
0224 private:
0225     //! Flushes record buffers in the backend (the actual implementation)
0226     template< typename BackendMutexT, typename BackendT >
0227     void flush_backend_impl(BackendMutexT& backend_mutex, BackendT& backend, boost::true_type)
0228     {
0229         try
0230         {
0231             BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
0232             backend.flush();
0233         }
0234 #if !defined(BOOST_LOG_NO_THREADS)
0235         catch (thread_interrupted&)
0236         {
0237             throw;
0238         }
0239 #endif
0240         catch (...)
0241         {
0242             BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
0243             if (m_ExceptionHandler.empty())
0244                 throw;
0245             m_ExceptionHandler();
0246         }
0247     }
0248     //! Flushes record buffers in the backend (stub for backends that don't support flushing)
0249     template< typename BackendMutexT, typename BackendT >
0250     void flush_backend_impl(BackendMutexT&, BackendT&, boost::false_type)
0251     {
0252     }
0253 };
0254 
0255 //! A base class for a logging sink frontend with formatting support
0256 template< typename CharT >
0257 class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend :
0258     public basic_sink_frontend
0259 {
0260     typedef basic_sink_frontend base_type;
0261 
0262 public:
0263     //! Character type
0264     typedef CharT char_type;
0265     //! Formatted string type
0266     typedef std::basic_string< char_type > string_type;
0267 
0268     //! Formatter function object type
0269     typedef basic_formatter< char_type > formatter_type;
0270     //! Output stream type
0271     typedef typename formatter_type::stream_type stream_type;
0272 
0273 #if !defined(BOOST_LOG_NO_THREADS)
0274 protected:
0275     //! Mutex type
0276     typedef typename base_type::mutex_type mutex_type;
0277 #endif
0278 
0279 private:
0280     struct formatting_context
0281     {
0282         class cleanup_guard
0283         {
0284         private:
0285             formatting_context& m_context;
0286 
0287         public:
0288             explicit cleanup_guard(formatting_context& ctx) BOOST_NOEXCEPT : m_context(ctx)
0289             {
0290             }
0291 
0292             ~cleanup_guard()
0293             {
0294                 m_context.m_FormattedRecord.clear();
0295                 m_context.m_FormattingStream.rdbuf()->max_size(m_context.m_FormattedRecord.max_size());
0296                 m_context.m_FormattingStream.rdbuf()->storage_overflow(false);
0297                 m_context.m_FormattingStream.clear();
0298             }
0299 
0300             BOOST_DELETED_FUNCTION(cleanup_guard(cleanup_guard const&))
0301             BOOST_DELETED_FUNCTION(cleanup_guard& operator=(cleanup_guard const&))
0302         };
0303 
0304 #if !defined(BOOST_LOG_NO_THREADS)
0305         //! Object version
0306         const unsigned int m_Version;
0307 #endif
0308         //! Formatted log record storage
0309         string_type m_FormattedRecord;
0310         //! Formatting stream
0311         stream_type m_FormattingStream;
0312         //! Formatter functor
0313         formatter_type m_Formatter;
0314 
0315         formatting_context() :
0316 #if !defined(BOOST_LOG_NO_THREADS)
0317             m_Version(0u),
0318 #endif
0319             m_FormattingStream(m_FormattedRecord)
0320         {
0321             m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
0322         }
0323 #if !defined(BOOST_LOG_NO_THREADS)
0324         formatting_context(unsigned int version, std::locale const& loc, formatter_type const& formatter) :
0325             m_Version(version),
0326             m_FormattingStream(m_FormattedRecord),
0327             m_Formatter(formatter)
0328         {
0329             m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
0330             m_FormattingStream.imbue(loc);
0331         }
0332 #endif
0333     };
0334 
0335 private:
0336 #if !defined(BOOST_LOG_NO_THREADS)
0337 
0338     //! State version
0339     boost::atomic< unsigned int > m_Version;
0340 
0341     //! Formatter functor
0342     formatter_type m_Formatter;
0343     //! Locale to perform formatting
0344     std::locale m_Locale;
0345 
0346     //! Formatting state
0347     thread_specific_ptr< formatting_context > m_pContext;
0348 
0349 #else
0350 
0351     //! Formatting state
0352     formatting_context m_Context;
0353 
0354 #endif // !defined(BOOST_LOG_NO_THREADS)
0355 
0356 public:
0357     /*!
0358      * \brief Initializing constructor
0359      *
0360      * \param cross_thread The flag indicates whether the sink passes log records between different threads
0361      */
0362     explicit basic_formatting_sink_frontend(bool cross_thread) :
0363         basic_sink_frontend(cross_thread)
0364 #if !defined(BOOST_LOG_NO_THREADS)
0365         , m_Version(0u)
0366 #endif
0367     {
0368     }
0369 
0370     /*!
0371      * The method sets sink-specific formatter function object
0372      */
0373     template< typename FunT >
0374     void set_formatter(FunT const& formatter)
0375     {
0376 #if !defined(BOOST_LOG_NO_THREADS)
0377         boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
0378         m_Formatter = formatter;
0379         m_Version.opaque_add(1u, boost::memory_order_relaxed);
0380 #else
0381         m_Context.m_Formatter = formatter;
0382 #endif
0383     }
0384     /*!
0385      * The method resets the formatter
0386      */
0387     void reset_formatter()
0388     {
0389 #if !defined(BOOST_LOG_NO_THREADS)
0390         boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
0391         m_Formatter.reset();
0392         m_Version.opaque_add(1u, boost::memory_order_relaxed);
0393 #else
0394         m_Context.m_Formatter.reset();
0395 #endif
0396     }
0397 
0398     /*!
0399      * The method returns the current locale used for formatting
0400      */
0401     std::locale getloc() const
0402     {
0403 #if !defined(BOOST_LOG_NO_THREADS)
0404         boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
0405         return m_Locale;
0406 #else
0407         return m_Context.m_FormattingStream.getloc();
0408 #endif
0409     }
0410     /*!
0411      * The method sets the locale used for formatting
0412      */
0413     void imbue(std::locale const& loc)
0414     {
0415 #if !defined(BOOST_LOG_NO_THREADS)
0416         boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
0417         m_Locale = loc;
0418         m_Version.opaque_add(1u, boost::memory_order_relaxed);
0419 #else
0420         m_Context.m_FormattingStream.imbue(loc);
0421 #endif
0422     }
0423 
0424 protected:
0425     //! Returns reference to the formatter
0426     formatter_type& formatter()
0427     {
0428 #if !defined(BOOST_LOG_NO_THREADS)
0429         return m_Formatter;
0430 #else
0431         return m_Context.m_Formatter;
0432 #endif
0433     }
0434 
0435     //! Feeds log record to the backend
0436     template< typename BackendMutexT, typename BackendT >
0437     void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
0438     {
0439         formatting_context* context;
0440 
0441 #if !defined(BOOST_LOG_NO_THREADS)
0442         context = m_pContext.get();
0443         if (!context || context->m_Version != m_Version.load(boost::memory_order_relaxed))
0444         {
0445             {
0446                 boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());
0447                 context = new formatting_context(m_Version.load(boost::memory_order_relaxed), m_Locale, m_Formatter);
0448             }
0449             m_pContext.reset(context);
0450         }
0451 #else
0452         context = &m_Context;
0453 #endif
0454 
0455         typename formatting_context::cleanup_guard cleanup(*context);
0456 
0457         try
0458         {
0459             // Perform the formatting
0460             context->m_Formatter(rec, context->m_FormattingStream);
0461             context->m_FormattingStream.flush();
0462 
0463             // Feed the record
0464             BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
0465             backend.consume(rec, context->m_FormattedRecord);
0466         }
0467 #if !defined(BOOST_LOG_NO_THREADS)
0468         catch (thread_interrupted&)
0469         {
0470             throw;
0471         }
0472 #endif
0473         catch (...)
0474         {
0475             BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());)
0476             if (this->exception_handler().empty())
0477                 throw;
0478             this->exception_handler()();
0479         }
0480     }
0481 
0482     //! Attempts to feeds log record to the backend, does not block if \a backend_mutex is locked
0483     template< typename BackendMutexT, typename BackendT >
0484     bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
0485     {
0486 #if !defined(BOOST_LOG_NO_THREADS)
0487         try
0488         {
0489             if (!backend_mutex.try_lock())
0490                 return false;
0491         }
0492         catch (thread_interrupted&)
0493         {
0494             throw;
0495         }
0496         catch (...)
0497         {
0498             boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex());
0499             if (this->exception_handler().empty())
0500                 throw;
0501             this->exception_handler()();
0502             return false;
0503         }
0504 
0505         boost::log::aux::exclusive_auto_unlocker< BackendMutexT > unlocker(backend_mutex);
0506 #endif
0507         // No need to lock anything in the feed_record method
0508         boost::log::aux::fake_mutex m;
0509         feed_record(rec, m, backend);
0510         return true;
0511     }
0512 };
0513 
0514 namespace aux {
0515 
0516     template<
0517         typename BackendT,
0518         bool RequiresFormattingV = has_requirement<
0519             typename BackendT::frontend_requirements,
0520             formatted_records
0521         >::value
0522     >
0523     struct make_sink_frontend_base
0524     {
0525         typedef basic_sink_frontend type;
0526     };
0527     template< typename BackendT >
0528     struct make_sink_frontend_base< BackendT, true >
0529     {
0530         typedef basic_formatting_sink_frontend< typename BackendT::char_type > type;
0531     };
0532 
0533 } // namespace aux
0534 
0535 } // namespace sinks
0536 
0537 BOOST_LOG_CLOSE_NAMESPACE // namespace log
0538 
0539 } // namespace boost
0540 
0541 #include <boost/log/detail/footer.hpp>
0542 
0543 #endif // BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_