Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-14 08:36:14

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