Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/log/sinks/bounded_fifo_queue.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/log/sinks/bounded_fifo_queue.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,194 @@ +/* + * Copyright Andrey Semashev 2007 - 2013. + * 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(); + if (size == MaxQueueSizeV) + 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(); + if (size == MaxQueueSizeV) + 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_