summaryrefslogtreecommitdiff
path: root/boost/log/sinks/bounded_fifo_queue.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/log/sinks/bounded_fifo_queue.hpp')
-rw-r--r--boost/log/sinks/bounded_fifo_queue.hpp192
1 files changed, 192 insertions, 0 deletions
diff --git a/boost/log/sinks/bounded_fifo_queue.hpp b/boost/log/sinks/bounded_fifo_queue.hpp
new file mode 100644
index 0000000000..59b157e259
--- /dev/null
+++ b/boost/log/sinks/bounded_fifo_queue.hpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright Andrey Semashev 2007 - 2014.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ */
+/*!
+ * \file bounded_fifo_queue.hpp
+ * \author Andrey Semashev
+ * \date 04.01.2012
+ *
+ * The header contains implementation of bounded FIFO queueing strategy for
+ * the asynchronous sink frontend.
+ */
+
+#ifndef BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_
+#define BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if defined(BOOST_LOG_NO_THREADS)
+#error Boost.Log: This header content is only supported in multithreaded environment
+#endif
+
+#include <cstddef>
+#include <queue>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/log/core/record_view.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+/*!
+ * \brief Bounded FIFO log record queueing strategy
+ *
+ * The \c bounded_fifo_queue class is intended to be used with
+ * the \c asynchronous_sink frontend as a log record queueing strategy.
+ *
+ * This strategy describes log record queueing logic.
+ * The queue has a limited capacity, upon reaching which the enqueue operation will
+ * invoke the overflow handling strategy specified in the \c OverflowStrategyT
+ * template parameter to handle the situation. The library provides overflow handling
+ * strategies for most common cases: \c drop_on_overflow will silently discard the log record,
+ * and \c block_on_overflow will put the enqueueing thread to wait until there is space
+ * in the queue.
+ *
+ * The log record queue imposes no ordering over the queued
+ * elements aside from the order in which they are enqueued.
+ */
+template< std::size_t MaxQueueSizeV, typename OverflowStrategyT >
+class bounded_fifo_queue :
+ private OverflowStrategyT
+{
+private:
+ typedef OverflowStrategyT overflow_strategy;
+ typedef std::queue< record_view > queue_type;
+ typedef boost::mutex mutex_type;
+
+private:
+ //! Synchronization primitive
+ mutex_type m_mutex;
+ //! Condition to block the consuming thread on
+ condition_variable m_cond;
+ //! Log record queue
+ queue_type m_queue;
+ //! Interruption flag
+ bool m_interruption_requested;
+
+protected:
+ //! Default constructor
+ bounded_fifo_queue() : m_interruption_requested(false)
+ {
+ }
+ //! Initializing constructor
+ template< typename ArgsT >
+ explicit bounded_fifo_queue(ArgsT const&) : m_interruption_requested(false)
+ {
+ }
+
+ //! Enqueues log record to the queue
+ void enqueue(record_view const& rec)
+ {
+ unique_lock< mutex_type > lock(m_mutex);
+ std::size_t size = m_queue.size();
+ for (; size >= MaxQueueSizeV; size = m_queue.size())
+ {
+ if (!overflow_strategy::on_overflow(rec, lock))
+ return;
+ }
+
+ m_queue.push(rec);
+ if (size == 0)
+ m_cond.notify_one();
+ }
+
+ //! Attempts to enqueue log record to the queue
+ bool try_enqueue(record_view const& rec)
+ {
+ unique_lock< mutex_type > lock(m_mutex, try_to_lock);
+ if (lock.owns_lock())
+ {
+ const std::size_t size = m_queue.size();
+
+ // Do not invoke the bounding strategy in case of overflow as it may block
+ if (size < MaxQueueSizeV)
+ {
+ m_queue.push(rec);
+ if (size == 0)
+ m_cond.notify_one();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ //! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty
+ bool try_dequeue_ready(record_view& rec)
+ {
+ return try_dequeue(rec);
+ }
+
+ //! Attempts to dequeue log record from the queue, does not block if the queue is empty
+ bool try_dequeue(record_view& rec)
+ {
+ lock_guard< mutex_type > lock(m_mutex);
+ const std::size_t size = m_queue.size();
+ if (size > 0)
+ {
+ rec.swap(m_queue.front());
+ m_queue.pop();
+ overflow_strategy::on_queue_space_available();
+ return true;
+ }
+
+ return false;
+ }
+
+ //! Dequeues log record from the queue, blocks if the queue is empty
+ bool dequeue_ready(record_view& rec)
+ {
+ unique_lock< mutex_type > lock(m_mutex);
+
+ while (!m_interruption_requested)
+ {
+ const std::size_t size = m_queue.size();
+ if (size > 0)
+ {
+ rec.swap(m_queue.front());
+ m_queue.pop();
+ overflow_strategy::on_queue_space_available();
+ return true;
+ }
+ else
+ {
+ m_cond.wait(lock);
+ }
+ }
+ m_interruption_requested = false;
+
+ return false;
+ }
+
+ //! Wakes a thread possibly blocked in the \c dequeue method
+ void interrupt_dequeue()
+ {
+ lock_guard< mutex_type > lock(m_mutex);
+ m_interruption_requested = true;
+ overflow_strategy::interrupt();
+ m_cond.notify_one();
+ }
+};
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_