]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/statechart/fifo_worker.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / statechart / fifo_worker.hpp
1 #ifndef BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
2 #define BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
3 //////////////////////////////////////////////////////////////////////////////
4 // Copyright 2002-2008 Andreas Huber Doenni
5 // Distributed under the Boost Software License, Version 1.0. (See accompany-
6 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //////////////////////////////////////////////////////////////////////////////
8
9
10
11 #include <boost/assert.hpp>
12 #include <boost/noncopyable.hpp>
13 #include <boost/function/function0.hpp>
14 #include <boost/bind.hpp>
15 // BOOST_HAS_THREADS, BOOST_MSVC
16 #include <boost/config.hpp>
17
18 #include <boost/detail/allocator_utilities.hpp>
19
20 #ifdef BOOST_HAS_THREADS
21 # ifdef BOOST_MSVC
22 # pragma warning( push )
23 // "conditional expression is constant" in basic_timed_mutex.hpp
24 # pragma warning( disable: 4127 )
25 // "conversion from 'int' to 'unsigned short'" in microsec_time_clock.hpp
26 # pragma warning( disable: 4244 )
27 // "... needs to have dll-interface to be used by clients of class ..."
28 # pragma warning( disable: 4251 )
29 // "... assignment operator could not be generated"
30 # pragma warning( disable: 4512 )
31 // "Function call with parameters that may be unsafe" in
32 // condition_variable.hpp
33 # pragma warning( disable: 4996 )
34 # endif
35
36 # include <boost/thread/mutex.hpp>
37 # include <boost/thread/condition.hpp>
38
39 # ifdef BOOST_MSVC
40 # pragma warning( pop )
41 # endif
42 #endif
43
44 #include <list>
45 #include <memory> // std::allocator
46
47
48 namespace boost
49 {
50 namespace statechart
51 {
52
53
54
55 template< class Allocator = std::allocator< none > >
56 class fifo_worker : noncopyable
57 {
58 public:
59 //////////////////////////////////////////////////////////////////////////
60 #ifdef BOOST_HAS_THREADS
61 fifo_worker( bool waitOnEmptyQueue = false ) :
62 waitOnEmptyQueue_( waitOnEmptyQueue ),
63 #else
64 fifo_worker() :
65 #endif
66 terminated_( false )
67 {
68 }
69
70 typedef function0< void > work_item;
71
72 // We take a non-const reference so that we can move (i.e. swap) the item
73 // into the queue, what avoids copying the (possibly heap-allocated)
74 // implementation object inside work_item.
75 void queue_work_item( work_item & item )
76 {
77 if ( item.empty() )
78 {
79 return;
80 }
81
82 #ifdef BOOST_HAS_THREADS
83 mutex::scoped_lock lock( mutex_ );
84 #endif
85
86 workQueue_.push_back( work_item() );
87 workQueue_.back().swap( item );
88
89 #ifdef BOOST_HAS_THREADS
90 queueNotEmpty_.notify_one();
91 #endif
92 }
93
94 // Convenience overload so that temporary objects can be passed directly
95 // instead of having to create a work_item object first. Under most
96 // circumstances, this will lead to one unnecessary copy of the
97 // function implementation object.
98 void queue_work_item( const work_item & item )
99 {
100 work_item copy = item;
101 queue_work_item( copy );
102 }
103
104 void terminate()
105 {
106 work_item item = boost::bind( &fifo_worker::terminate_impl, this );
107 queue_work_item( item );
108 }
109
110 // Is not mutex-protected! Must only be called from the thread that also
111 // calls operator().
112 bool terminated() const
113 {
114 return terminated_;
115 }
116
117 unsigned long operator()( unsigned long maxItemCount = 0 )
118 {
119 unsigned long itemCount = 0;
120
121 while ( !terminated() &&
122 ( ( maxItemCount == 0 ) || ( itemCount < maxItemCount ) ) )
123 {
124 work_item item = dequeue_item();
125
126 if ( item.empty() )
127 {
128 // item can only be empty when the queue is empty, which only
129 // happens in ST builds or when users pass false to the fifo_worker
130 // constructor
131 return itemCount;
132 }
133
134 item();
135 ++itemCount;
136 }
137
138 return itemCount;
139 }
140
141 private:
142 //////////////////////////////////////////////////////////////////////////
143 work_item dequeue_item()
144 {
145 #ifdef BOOST_HAS_THREADS
146 mutex::scoped_lock lock( mutex_ );
147
148 if ( !waitOnEmptyQueue_ && workQueue_.empty() )
149 {
150 return work_item();
151 }
152
153 while ( workQueue_.empty() )
154 {
155 queueNotEmpty_.wait( lock );
156 }
157 #else
158 // If the queue happens to run empty in a single-threaded system,
159 // waiting for new work items (which means to loop indefinitely!) is
160 // pointless as there is no way that new work items could find their way
161 // into the queue. The only sensible thing is to exit the loop and
162 // return to the caller in this case.
163 // Users can then queue new work items before calling operator() again.
164 if ( workQueue_.empty() )
165 {
166 return work_item();
167 }
168 #endif
169
170 // Optimization: Swap rather than assign to avoid the copy of the
171 // implementation object inside function
172 work_item result;
173 result.swap( workQueue_.front() );
174 workQueue_.pop_front();
175 return result;
176 }
177
178 void terminate_impl()
179 {
180 terminated_ = true;
181 }
182
183
184 typedef std::list<
185 work_item,
186 typename boost::detail::allocator::rebind_to<
187 Allocator, work_item >::type
188 > work_queue_type;
189
190 work_queue_type workQueue_;
191
192 #ifdef BOOST_HAS_THREADS
193 mutex mutex_;
194 condition queueNotEmpty_;
195 const bool waitOnEmptyQueue_;
196 #endif
197
198 bool terminated_;
199 };
200
201
202
203 } // namespace statechart
204 } // namespace boost
205
206
207
208 #endif