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 block_on_overflow.hpp 9 * \author Andrey Semashev 10 * \date 04.01.2012 11 * 12 * The header contains implementation of \c block_on_overflow strategy for handling 13 * queue overflows in bounded queues for the asynchronous sink frontend. 14 */ 15 16 #ifndef BOOST_LOG_SINKS_BLOCK_ON_OVERFLOW_HPP_INCLUDED_ 17 #define BOOST_LOG_SINKS_BLOCK_ON_OVERFLOW_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/intrusive/options.hpp> 30 #include <boost/intrusive/list.hpp> 31 #include <boost/intrusive/list_hook.hpp> 32 #include <boost/thread/condition_variable.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 Blocking strategy for handling log record queue overflows 44 * 45 * This strategy will cause enqueueing threads to block when the 46 * log record queue overflows. The blocked threads will be woken as 47 * soon as there appears free space in the queue, in the same order 48 * they attempted to enqueue records. 49 */ 50 class block_on_overflow 51 { 52 #ifndef BOOST_LOG_DOXYGEN_PASS 53 private: 54 typedef intrusive::list_base_hook< 55 intrusive::link_mode< intrusive::auto_unlink > 56 > thread_context_hook_t; 57 58 struct thread_context : 59 public thread_context_hook_t 60 { 61 condition_variable cond; 62 bool result; 63 thread_contextboost::sinks::block_on_overflow::thread_context64 thread_context() : result(true) {} 65 }; 66 67 typedef intrusive::list< 68 thread_context, 69 intrusive::base_hook< thread_context_hook_t >, 70 intrusive::constant_time_size< false > 71 > thread_contexts; 72 73 private: 74 //! Blocked threads 75 thread_contexts m_thread_contexts; 76 77 public: 78 /*! 79 * Default constructor. 80 */ block_on_overflow()81 BOOST_DEFAULTED_FUNCTION(block_on_overflow(), {}) 82 83 /*! 84 * This method is called by the queue when overflow is detected. 85 * 86 * \param lock An internal lock that protects the queue 87 * 88 * \retval true Attempt to enqueue the record again. 89 * \retval false Discard the record. 90 */ 91 template< typename LockT > 92 bool on_overflow(record_view const&, LockT& lock) 93 { 94 thread_context context; 95 m_thread_contexts.push_back(context); 96 do 97 { 98 context.cond.wait(lock); 99 } 100 while (context.is_linked()); 101 102 return context.result; 103 } 104 105 /*! 106 * This method is called by the queue when there appears a free space. 107 * The internal lock protecting the queue is locked when calling this method. 108 */ on_queue_space_available()109 void on_queue_space_available() 110 { 111 if (!m_thread_contexts.empty()) 112 { 113 m_thread_contexts.front().cond.notify_one(); 114 m_thread_contexts.pop_front(); 115 } 116 } 117 118 /*! 119 * This method is called by the queue to interrupt any possible waits in \c on_overflow. 120 * The internal lock protecting the queue is locked when calling this method. 121 */ interrupt()122 void interrupt() 123 { 124 while (!m_thread_contexts.empty()) 125 { 126 thread_context& context = m_thread_contexts.front(); 127 context.result = false; 128 context.cond.notify_one(); 129 m_thread_contexts.pop_front(); 130 } 131 } 132 133 // Copying prohibited 134 BOOST_DELETED_FUNCTION(block_on_overflow(block_on_overflow const&)) 135 BOOST_DELETED_FUNCTION(block_on_overflow& operator= (block_on_overflow const&)) 136 #endif // BOOST_LOG_DOXYGEN_PASS 137 }; 138 139 } // namespace sinks 140 141 BOOST_LOG_CLOSE_NAMESPACE // namespace log 142 143 } // namespace boost 144 145 #include <boost/log/detail/footer.hpp> 146 147 #endif // BOOST_LOG_SINKS_BLOCK_ON_OVERFLOW_HPP_INCLUDED_ 148