Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:37:52

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