]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/interprocess/include/boost/interprocess/sync/detail/condition_algorithm_8a.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / interprocess / include / boost / interprocess / sync / detail / condition_algorithm_8a.hpp
CommitLineData
7c673cae
FG
1//////////////////////////////////////////////////////////////////////////////
2//
3// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
4// Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// See http://www.boost.org/libs/interprocess for documentation.
8//
9//////////////////////////////////////////////////////////////////////////////
10
11#ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP
12#define BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP
13
14#ifndef BOOST_CONFIG_HPP
15# include <boost/config.hpp>
16#endif
17#
18#if defined(BOOST_HAS_PRAGMA_ONCE)
19# pragma once
20#endif
21
22#include <boost/interprocess/detail/config_begin.hpp>
23#include <boost/interprocess/detail/workaround.hpp>
24#include <boost/interprocess/sync/scoped_lock.hpp>
25#include <boost/interprocess/sync/detail/locks.hpp>
26#include <limits>
27
28namespace boost {
29namespace interprocess {
30namespace ipcdetail {
31
32////////////////////////////////////////////////////////////////////////
33////////////////////////////////////////////////////////////////////////
34////////////////////////////////////////////////////////////////////////
35//
36// Condition variable algorithm taken from pthreads-win32 discussion.
37//
38// The algorithm was developed by Alexander Terekhov in colaboration with
39// Louis Thomas.
40//
41// Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
42//
43// semBlockLock - bin.semaphore
44// semBlockQueue - semaphore
45// mtxExternal - mutex or CS
46// mtxUnblockLock - mutex or CS
47// nWaitersGone - int
48// nWaitersBlocked - int
49// nWaitersToUnblock - int
50//
51// wait( timeout ) {
52//
53// [auto: register int result ] // error checking omitted
54// [auto: register int nSignalsWasLeft ]
55// [auto: register int nWaitersWasGone ]
56//
57// sem_wait( semBlockLock );
58// nWaitersBlocked++;
59// sem_post( semBlockLock );
60//
61// unlock( mtxExternal );
62// bTimedOut = sem_wait( semBlockQueue,timeout );
63//
64// lock( mtxUnblockLock );
65// if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
66// if ( bTimedOut ) { // timeout (or canceled)
67// if ( 0 != nWaitersBlocked ) {
68// nWaitersBlocked--;
69// }
70// else {
71// nWaitersGone++; // count spurious wakeups.
72// }
73// }
74// if ( 0 == --nWaitersToUnblock ) {
75// if ( 0 != nWaitersBlocked ) {
76// sem_post( semBlockLock ); // open the gate.
77// nSignalsWasLeft = 0; // do not open the gate
78// // below again.
79// }
80// else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
81// nWaitersGone = 0;
82// }
83// }
84// }
85// else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
86// // spurious semaphore :-)
87// sem_wait( semBlockLock );
88// nWaitersBlocked -= nWaitersGone; // something is going on here
89// // - test of timeouts? :-)
90// sem_post( semBlockLock );
91// nWaitersGone = 0;
92// }
93// unlock( mtxUnblockLock );
94//
95// if ( 1 == nSignalsWasLeft ) {
96// if ( 0 != nWaitersWasGone ) {
97// // sem_adjust( semBlockQueue,-nWaitersWasGone );
98// while ( nWaitersWasGone-- ) {
99// sem_wait( semBlockQueue ); // better now than spurious later
100// }
101// } sem_post( semBlockLock ); // open the gate
102// }
103//
104// lock( mtxExternal );
105//
106// return ( bTimedOut ) ? ETIMEOUT : 0;
107// }
108//
109// signal(bAll) {
110//
111// [auto: register int result ]
112// [auto: register int nSignalsToIssue]
113//
114// lock( mtxUnblockLock );
115//
116// if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
117// if ( 0 == nWaitersBlocked ) { // NO-OP
118// return unlock( mtxUnblockLock );
119// }
120// if (bAll) {
121// nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
122// nWaitersBlocked = 0;
123// }
124// else {
125// nSignalsToIssue = 1;
126// nWaitersToUnblock++;
127// nWaitersBlocked--;
128// }
129// }
130// else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
131// sem_wait( semBlockLock ); // close the gate
132// if ( 0 != nWaitersGone ) {
133// nWaitersBlocked -= nWaitersGone;
134// nWaitersGone = 0;
135// }
136// if (bAll) {
137// nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
138// nWaitersBlocked = 0;
139// }
140// else {
141// nSignalsToIssue = nWaitersToUnblock = 1;
142// nWaitersBlocked--;
143// }
144// }
145// else { // NO-OP
146// return unlock( mtxUnblockLock );
147// }
148//
149// unlock( mtxUnblockLock );
150// sem_post( semBlockQueue,nSignalsToIssue );
151// return result;
152// }
153////////////////////////////////////////////////////////////////////////
154////////////////////////////////////////////////////////////////////////
155////////////////////////////////////////////////////////////////////////
156
157
158// Required interface for ConditionMembers
159// class ConditionMembers
160// {
161// typedef implementation_defined semaphore_type;
162// typedef implementation_defined mutex_type;
163// typedef implementation_defined integer_type;
164//
165// integer_type &get_nwaiters_blocked()
166// integer_type &get_nwaiters_gone()
167// integer_type &get_nwaiters_to_unblock()
168// semaphore_type &get_sem_block_queue()
169// semaphore_type &get_sem_block_lock()
170// mutex_type &get_mtx_unblock_lock()
171// };
172//
173// Must be initialized as following
174//
175// get_nwaiters_blocked() == 0
176// get_nwaiters_gone() == 0
177// get_nwaiters_to_unblock() == 0
178// get_sem_block_queue() == initial count 0
179// get_sem_block_lock() == initial count 1
180// get_mtx_unblock_lock() (unlocked)
181//
182template<class ConditionMembers>
183class condition_algorithm_8a
184{
185 private:
186 condition_algorithm_8a();
187 ~condition_algorithm_8a();
188 condition_algorithm_8a(const condition_algorithm_8a &);
189 condition_algorithm_8a &operator=(const condition_algorithm_8a &);
190
191 typedef typename ConditionMembers::semaphore_type semaphore_type;
192 typedef typename ConditionMembers::mutex_type mutex_type;
193 typedef typename ConditionMembers::integer_type integer_type;
194
195 public:
196 template<class Lock>
197 static bool wait ( ConditionMembers &data, Lock &lock
198 , bool timeout_enabled, const boost::posix_time::ptime &abs_time);
199 static void signal(ConditionMembers &data, bool broadcast);
200};
201
202template<class ConditionMembers>
203inline void condition_algorithm_8a<ConditionMembers>::signal(ConditionMembers &data, bool broadcast)
204{
205 integer_type nsignals_to_issue;
206
207 {
208 scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock());
209
210 if ( 0 != data.get_nwaiters_to_unblock() ) { // the gate is closed!!!
211 if ( 0 == data.get_nwaiters_blocked() ) { // NO-OP
212 //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
213 return;
214 }
215 if (broadcast) {
216 data.get_nwaiters_to_unblock() += nsignals_to_issue = data.get_nwaiters_blocked();
217 data.get_nwaiters_blocked() = 0;
218 }
219 else {
220 nsignals_to_issue = 1;
221 data.get_nwaiters_to_unblock()++;
222 data.get_nwaiters_blocked()--;
223 }
224 }
225 else if ( data.get_nwaiters_blocked() > data.get_nwaiters_gone() ) { // HARMLESS RACE CONDITION!
226 data.get_sem_block_lock().wait(); // close the gate
227 if ( 0 != data.get_nwaiters_gone() ) {
228 data.get_nwaiters_blocked() -= data.get_nwaiters_gone();
229 data.get_nwaiters_gone() = 0;
230 }
231 if (broadcast) {
232 nsignals_to_issue = data.get_nwaiters_to_unblock() = data.get_nwaiters_blocked();
233 data.get_nwaiters_blocked() = 0;
234 }
235 else {
236 nsignals_to_issue = data.get_nwaiters_to_unblock() = 1;
237 data.get_nwaiters_blocked()--;
238 }
239 }
240 else { // NO-OP
241 //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
242 return;
243 }
244 //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
245 }
246 data.get_sem_block_queue().post(nsignals_to_issue);
247}
248
249template<class ConditionMembers>
250template<class Lock>
251inline bool condition_algorithm_8a<ConditionMembers>::wait
252 ( ConditionMembers &data
253 , Lock &lock
254 , bool tout_enabled
255 , const boost::posix_time::ptime &abs_time
256 )
257{
258 //Initialize to avoid warnings
259 integer_type nsignals_was_left = 0;
260 integer_type nwaiters_was_gone = 0;
261
262 data.get_sem_block_lock().wait();
263 ++data.get_nwaiters_blocked();
264 data.get_sem_block_lock().post();
265
266 //Unlock external lock and program for relock
267 lock_inverter<Lock> inverted_lock(lock);
268 scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock);
269
270 bool bTimedOut = tout_enabled
271 ? !data.get_sem_block_queue().timed_wait(abs_time)
272 : (data.get_sem_block_queue().wait(), false);
273
274 {
275 scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock());
276 if ( 0 != (nsignals_was_left = data.get_nwaiters_to_unblock()) ) {
277 if ( bTimedOut ) { // timeout (or canceled)
278 if ( 0 != data.get_nwaiters_blocked() ) {
279 data.get_nwaiters_blocked()--;
280 }
281 else {
282 data.get_nwaiters_gone()++; // count spurious wakeups.
283 }
284 }
285 if ( 0 == --data.get_nwaiters_to_unblock() ) {
286 if ( 0 != data.get_nwaiters_blocked() ) {
287 data.get_sem_block_lock().post(); // open the gate.
288 nsignals_was_left = 0; // do not open the gate below again.
289 }
290 else if ( 0 != (nwaiters_was_gone = data.get_nwaiters_gone()) ) {
291 data.get_nwaiters_gone() = 0;
292 }
293 }
294 }
295 else if ( (std::numeric_limits<integer_type>::max)()/2
296 == ++data.get_nwaiters_gone() ) { // timeout/canceled or spurious semaphore :-)
297 data.get_sem_block_lock().wait();
298 data.get_nwaiters_blocked() -= data.get_nwaiters_gone(); // something is going on here - test of timeouts? :-)
299 data.get_sem_block_lock().post();
300 data.get_nwaiters_gone() = 0;
301 }
302 //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
303 }
304
305 if ( 1 == nsignals_was_left ) {
306 if ( 0 != nwaiters_was_gone ) {
307 // sem_adjust( data.get_sem_block_queue(),-nwaiters_was_gone );
308 while ( nwaiters_was_gone-- ) {
309 data.get_sem_block_queue().wait(); // better now than spurious later
310 }
311 }
312 data.get_sem_block_lock().post(); // open the gate
313 }
314
315 //lock.lock(); called from unlocker destructor
316
317 return ( bTimedOut ) ? false : true;
318}
319
320
321template<class ConditionMembers>
322class condition_8a_wrapper
323{
324 //Non-copyable
325 condition_8a_wrapper(const condition_8a_wrapper &);
326 condition_8a_wrapper &operator=(const condition_8a_wrapper &);
327
328 ConditionMembers m_data;
329 typedef ipcdetail::condition_algorithm_8a<ConditionMembers> algo_type;
330
331 public:
332
333 condition_8a_wrapper(){}
334
335 //Compiler-generated destructor is OK
336 //~condition_8a_wrapper(){}
337
338 ConditionMembers & get_members()
339 { return m_data; }
340
341 const ConditionMembers & get_members() const
342 { return m_data; }
343
344 void notify_one()
345 { algo_type::signal(m_data, false); }
346
347 void notify_all()
348 { algo_type::signal(m_data, true); }
349
350 template <typename L>
351 void wait(L& lock)
352 {
353 if (!lock)
354 throw lock_exception();
355 algo_type::wait(m_data, lock, false, boost::posix_time::ptime());
356 }
357
358 template <typename L, typename Pr>
359 void wait(L& lock, Pr pred)
360 {
361 if (!lock)
362 throw lock_exception();
363
364 while (!pred())
365 algo_type::wait(m_data, lock, false, boost::posix_time::ptime());
366 }
367
368 template <typename L>
369 bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time)
370 {
371 if (!lock)
372 throw lock_exception();
373 return algo_type::wait(m_data, lock, true, abs_time);
374 }
375
376 template <typename L, typename Pr>
377 bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
378 {
379 if (!lock)
380 throw lock_exception();
381 while (!pred()){
382 if (!algo_type::wait(m_data, lock, true, abs_time))
383 return pred();
384 }
385 return true;
386 }
387};
388
389} //namespace ipcdetail
390} //namespace interprocess
391} //namespace boost
392
393#include <boost/interprocess/detail/config_end.hpp>
394
395#endif //BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP