• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   unbounded_fifo_queue.hpp
9  * \author Andrey Semashev
10  * \date   24.07.2011
11  *
12  * The header contains implementation of unbounded FIFO queueing strategy for
13  * the asynchronous sink frontend.
14  */
15 
16 #ifndef BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_
17 #define BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_
18 
19 #include <boost/log/detail/config.hpp>
20 
21 #ifdef BOOST_HAS_PRAGMA_ONCE
22 #pragma once
23 #endif
24 
25 #if defined(BOOST_LOG_NO_THREADS)
26 #error Boost.Log: This header content is only supported in multithreaded environment
27 #endif
28 
29 #include <boost/memory_order.hpp>
30 #include <boost/atomic/atomic.hpp>
31 #include <boost/log/detail/event.hpp>
32 #include <boost/log/detail/threadsafe_queue.hpp>
33 #include <boost/log/core/record_view.hpp>
34 #include <boost/log/detail/header.hpp>
35 
36 namespace boost {
37 
38 BOOST_LOG_OPEN_NAMESPACE
39 
40 namespace sinks {
41 
42 /*!
43  * \brief Unbounded FIFO log record queueing strategy
44  *
45  * The \c unbounded_fifo_queue class is intended to be used with
46  * the \c asynchronous_sink frontend as a log record queueing strategy.
47  *
48  * This strategy implements the simplest logic of log record buffering between
49  * threads: the queue has no limits and imposes no ordering over the queued
50  * elements aside from the order in which they are enqueued.
51  * Because of this the queue provides decent performance and scalability,
52  * however if sink backends can't consume log records fast enough the queue
53  * may grow uncontrollably. When this is an issue, it is recommended to
54  * use one of the bounded strategies.
55  */
56 class unbounded_fifo_queue
57 {
58 private:
59     typedef boost::log::aux::threadsafe_queue< record_view > queue_type;
60 
61 private:
62     //! Thread-safe queue
63     queue_type m_queue;
64     //! Event object to block on
65     boost::log::aux::event m_event;
66     //! Interruption flag
67     boost::atomic< bool > m_interruption_requested;
68 
69 protected:
70     //! Default constructor
unbounded_fifo_queue()71     unbounded_fifo_queue() : m_interruption_requested(false)
72     {
73     }
74     //! Initializing constructor
75     template< typename ArgsT >
unbounded_fifo_queue(ArgsT const &)76     explicit unbounded_fifo_queue(ArgsT const&) : m_interruption_requested(false)
77     {
78     }
79 
80     //! Enqueues log record to the queue
enqueue(record_view const & rec)81     void enqueue(record_view const& rec)
82     {
83         m_queue.push(rec);
84         m_event.set_signalled();
85     }
86 
87     //! Attempts to enqueue log record to the queue
try_enqueue(record_view const & rec)88     bool try_enqueue(record_view const& rec)
89     {
90         // Assume the call never blocks
91         enqueue(rec);
92         return true;
93     }
94 
95     //! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty
try_dequeue_ready(record_view & rec)96     bool try_dequeue_ready(record_view& rec)
97     {
98         return m_queue.try_pop(rec);
99     }
100 
101     //! Attempts to dequeue log record from the queue, does not block if the queue is empty
try_dequeue(record_view & rec)102     bool try_dequeue(record_view& rec)
103     {
104         return m_queue.try_pop(rec);
105     }
106 
107     //! Dequeues log record from the queue, blocks if the queue is empty
dequeue_ready(record_view & rec)108     bool dequeue_ready(record_view& rec)
109     {
110         // Try the fast way first
111         if (m_queue.try_pop(rec))
112             return true;
113 
114         // Ok, we probably have to wait for new records
115         while (true)
116         {
117             m_event.wait();
118             if (m_interruption_requested.exchange(false, boost::memory_order_acquire))
119                 return false;
120             if (m_queue.try_pop(rec))
121                 return true;
122         }
123     }
124 
125     //! Wakes a thread possibly blocked in the \c dequeue method
interrupt_dequeue()126     void interrupt_dequeue()
127     {
128         m_interruption_requested.store(true, boost::memory_order_release);
129         m_event.set_signalled();
130     }
131 };
132 
133 } // namespace sinks
134 
135 BOOST_LOG_CLOSE_NAMESPACE // namespace log
136 
137 } // namespace boost
138 
139 #include <boost/log/detail/footer.hpp>
140 
141 #endif // BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_
142