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   bounded_fifo_queue.hpp
0009  * \author Andrey Semashev
0010  * \date   04.01.2012
0011  *
0012  * The header contains implementation of bounded FIFO queueing strategy for
0013  * the asynchronous sink frontend.
0014  */
0015 
0016 #ifndef BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_
0017 #define BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_
0018 
0019 #include <boost/log/detail/config.hpp>
0020 
0021 #ifdef BOOST_HAS_PRAGMA_ONCE
0022 #pragma once
0023 #endif
0024 
0025 #if defined(BOOST_LOG_NO_THREADS)
0026 #error Boost.Log: This header content is only supported in multithreaded environment
0027 #endif
0028 
0029 #include <cstddef>
0030 #include <queue>
0031 #include <boost/thread/locks.hpp>
0032 #include <boost/thread/mutex.hpp>
0033 #include <boost/thread/condition_variable.hpp>
0034 #include <boost/log/core/record_view.hpp>
0035 #include <boost/log/detail/header.hpp>
0036 
0037 namespace boost {
0038 
0039 BOOST_LOG_OPEN_NAMESPACE
0040 
0041 namespace sinks {
0042 
0043 /*!
0044  * \brief Bounded FIFO log record queueing strategy
0045  *
0046  * The \c bounded_fifo_queue class is intended to be used with
0047  * the \c asynchronous_sink frontend as a log record queueing strategy.
0048  *
0049  * This strategy describes log record queueing logic.
0050  * The queue has a limited capacity, upon reaching which the enqueue operation will
0051  * invoke the overflow handling strategy specified in the \c OverflowStrategyT
0052  * template parameter to handle the situation. The library provides overflow handling
0053  * strategies for most common cases: \c drop_on_overflow will silently discard the log record,
0054  * and \c block_on_overflow will put the enqueueing thread to wait until there is space
0055  * in the queue.
0056  *
0057  * The log record queue imposes no ordering over the queued
0058  * elements aside from the order in which they are enqueued.
0059  */
0060 template< std::size_t MaxQueueSizeV, typename OverflowStrategyT >
0061 class bounded_fifo_queue :
0062     private OverflowStrategyT
0063 {
0064 private:
0065     typedef OverflowStrategyT overflow_strategy;
0066     typedef std::queue< record_view > queue_type;
0067     typedef boost::mutex mutex_type;
0068 
0069 private:
0070     //! Synchronization primitive
0071     mutex_type m_mutex;
0072     //! Condition to block the consuming thread on
0073     condition_variable m_cond;
0074     //! Log record queue
0075     queue_type m_queue;
0076     //! Interruption flag
0077     bool m_interruption_requested;
0078 
0079 protected:
0080     //! Default constructor
0081     bounded_fifo_queue() : m_interruption_requested(false)
0082     {
0083     }
0084     //! Initializing constructor
0085     template< typename ArgsT >
0086     explicit bounded_fifo_queue(ArgsT const&) : m_interruption_requested(false)
0087     {
0088     }
0089 
0090     //! Enqueues log record to the queue
0091     void enqueue(record_view const& rec)
0092     {
0093         unique_lock< mutex_type > lock(m_mutex);
0094         std::size_t size = m_queue.size();
0095         for (; size >= MaxQueueSizeV; size = m_queue.size())
0096         {
0097             if (!overflow_strategy::on_overflow(rec, lock))
0098                 return;
0099         }
0100 
0101         m_queue.push(rec);
0102         if (size == 0)
0103             m_cond.notify_one();
0104     }
0105 
0106     //! Attempts to enqueue log record to the queue
0107     bool try_enqueue(record_view const& rec)
0108     {
0109         unique_lock< mutex_type > lock(m_mutex, try_to_lock);
0110         if (lock.owns_lock())
0111         {
0112             const std::size_t size = m_queue.size();
0113 
0114             // Do not invoke the bounding strategy in case of overflow as it may block
0115             if (size < MaxQueueSizeV)
0116             {
0117                 m_queue.push(rec);
0118                 if (size == 0)
0119                     m_cond.notify_one();
0120                 return true;
0121             }
0122         }
0123 
0124         return false;
0125     }
0126 
0127     //! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty
0128     bool try_dequeue_ready(record_view& rec)
0129     {
0130         return try_dequeue(rec);
0131     }
0132 
0133     //! Attempts to dequeue log record from the queue, does not block if the queue is empty
0134     bool try_dequeue(record_view& rec)
0135     {
0136         lock_guard< mutex_type > lock(m_mutex);
0137         const std::size_t size = m_queue.size();
0138         if (size > 0)
0139         {
0140             rec.swap(m_queue.front());
0141             m_queue.pop();
0142             overflow_strategy::on_queue_space_available();
0143             return true;
0144         }
0145 
0146         return false;
0147     }
0148 
0149     //! Dequeues log record from the queue, blocks if the queue is empty
0150     bool dequeue_ready(record_view& rec)
0151     {
0152         unique_lock< mutex_type > lock(m_mutex);
0153 
0154         while (!m_interruption_requested)
0155         {
0156             const std::size_t size = m_queue.size();
0157             if (size > 0)
0158             {
0159                 rec.swap(m_queue.front());
0160                 m_queue.pop();
0161                 overflow_strategy::on_queue_space_available();
0162                 return true;
0163             }
0164             else
0165             {
0166                 m_cond.wait(lock);
0167             }
0168         }
0169         m_interruption_requested = false;
0170 
0171         return false;
0172     }
0173 
0174     //! Wakes a thread possibly blocked in the \c dequeue method
0175     void interrupt_dequeue()
0176     {
0177         lock_guard< mutex_type > lock(m_mutex);
0178         m_interruption_requested = true;
0179         overflow_strategy::interrupt();
0180         m_cond.notify_one();
0181     }
0182 };
0183 
0184 } // namespace sinks
0185 
0186 BOOST_LOG_CLOSE_NAMESPACE // namespace log
0187 
0188 } // namespace boost
0189 
0190 #include <boost/log/detail/footer.hpp>
0191 
0192 #endif // BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_