]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/thread/pthread/shared_mutex_assert.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / thread / pthread / shared_mutex_assert.hpp
1 #ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
2 #define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
3
4 // (C) Copyright 2006-8 Anthony Williams
5 // (C) Copyright 2012 Vicente J. Botet Escriba
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See
8 // accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10
11 #include <boost/assert.hpp>
12 #include <boost/static_assert.hpp>
13 #include <boost/thread/mutex.hpp>
14 #include <boost/thread/condition_variable.hpp>
15 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
16 #include <boost/thread/detail/thread_interruption.hpp>
17 #endif
18 #ifdef BOOST_THREAD_USES_CHRONO
19 #include <boost/chrono/system_clocks.hpp>
20 #include <boost/chrono/ceil.hpp>
21 #endif
22 #include <boost/thread/detail/delete.hpp>
23 #include <boost/assert.hpp>
24
25 #include <boost/config/abi_prefix.hpp>
26
27 namespace boost
28 {
29 class shared_mutex
30 {
31 private:
32 class state_data
33 {
34 public:
35 state_data () :
36 shared_count(0),
37 exclusive(false),
38 upgrade(false),
39 exclusive_waiting_blocked(false)
40 {}
41
42 void assert_free() const
43 {
44 BOOST_ASSERT( ! exclusive );
45 BOOST_ASSERT( ! upgrade );
46 BOOST_ASSERT( shared_count==0 );
47 }
48
49 void assert_locked() const
50 {
51 BOOST_ASSERT( exclusive );
52 BOOST_ASSERT( shared_count==0 );
53 BOOST_ASSERT( ! upgrade );
54 }
55
56 void assert_lock_shared () const
57 {
58 BOOST_ASSERT( ! exclusive );
59 BOOST_ASSERT( shared_count>0 );
60 //BOOST_ASSERT( (! upgrade) || (shared_count>1));
61 // if upgraded there are at least 2 threads sharing the mutex,
62 // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
63 }
64
65 void assert_lock_upgraded () const
66 {
67 BOOST_ASSERT( ! exclusive );
68 BOOST_ASSERT( upgrade );
69 BOOST_ASSERT( shared_count>0 );
70 }
71
72 void assert_lock_not_upgraded () const
73 {
74 BOOST_ASSERT( ! upgrade );
75 }
76
77 bool can_lock () const
78 {
79 return ! (shared_count || exclusive);
80 }
81
82 void exclusive_blocked (bool blocked)
83 {
84 exclusive_waiting_blocked = blocked;
85 }
86
87 void lock ()
88 {
89 exclusive = true;
90 }
91
92 void unlock ()
93 {
94 exclusive = false;
95 exclusive_waiting_blocked = false;
96 }
97
98 bool can_lock_shared () const
99 {
100 return ! (exclusive || exclusive_waiting_blocked);
101 }
102
103 bool is_last_shared () const
104 {
105 return !shared_count ;
106 }
107 unsigned get_shared_count () const
108 {
109 return shared_count ;
110 }
111 unsigned lock_shared ()
112 {
113 return ++shared_count;
114 }
115
116
117 void unlock_shared ()
118 {
119 --shared_count;
120 }
121
122 bool unlock_shared_downgrades()
123 {
124 if (upgrade) {
125 upgrade=false;
126 exclusive=true;
127 return true;
128 } else {
129 exclusive_waiting_blocked=false;
130 return false;
131 }
132 }
133
134 void lock_upgrade ()
135 {
136 lock_shared ();
137 upgrade=true;
138 }
139 bool can_lock_upgrade () const
140 {
141 return ! (exclusive || exclusive_waiting_blocked || upgrade);
142 }
143
144 void unlock_upgrade ()
145 {
146 upgrade=false;
147 unlock_shared();
148 }
149
150 //private:
151 unsigned shared_count;
152 bool exclusive;
153 bool upgrade;
154 bool exclusive_waiting_blocked;
155 };
156
157
158
159 state_data state;
160 boost::mutex state_change;
161 boost::condition_variable shared_cond;
162 boost::condition_variable exclusive_cond;
163 boost::condition_variable upgrade_cond;
164
165 void release_waiters()
166 {
167 exclusive_cond.notify_one();
168 shared_cond.notify_all();
169 }
170
171 public:
172 BOOST_THREAD_NO_COPYABLE(shared_mutex)
173
174 shared_mutex()
175 {
176 }
177
178 ~shared_mutex()
179 {
180 }
181
182 void lock_shared()
183 {
184 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
185 boost::this_thread::disable_interruption do_not_disturb;
186 #endif
187 boost::unique_lock<boost::mutex> lk(state_change);
188
189 while(!state.can_lock_shared())
190 {
191 shared_cond.wait(lk);
192 }
193 state.lock_shared();
194 }
195
196 bool try_lock_shared()
197 {
198 boost::unique_lock<boost::mutex> lk(state_change);
199 if(!state.can_lock_shared())
200 {
201 return false;
202 }
203 else
204 {
205 state.lock_shared();
206 return true;
207 }
208 }
209
210 #if defined BOOST_THREAD_USES_DATETIME
211 bool timed_lock_shared(system_time const& timeout)
212 {
213 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
214 boost::this_thread::disable_interruption do_not_disturb;
215 #endif
216 boost::unique_lock<boost::mutex> lk(state_change);
217
218 while(!state.can_lock_shared())
219 {
220 if(!shared_cond.timed_wait(lk,timeout))
221 {
222 return false;
223 }
224 }
225 state.lock_shared();
226 return true;
227 }
228
229 template<typename TimeDuration>
230 bool timed_lock_shared(TimeDuration const & relative_time)
231 {
232 return timed_lock_shared(get_system_time()+relative_time);
233 }
234 #endif
235 #ifdef BOOST_THREAD_USES_CHRONO
236 template <class Rep, class Period>
237 bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
238 {
239 return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
240 }
241 template <class Clock, class Duration>
242 bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
243 {
244 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
245 boost::this_thread::disable_interruption do_not_disturb;
246 #endif
247 boost::unique_lock<boost::mutex> lk(state_change);
248
249 while(!state.can_lock_shared())
250 {
251 if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
252 {
253 return false;
254 }
255 }
256 state.lock_shared();
257 return true;
258 }
259 #endif
260 void unlock_shared()
261 {
262 boost::unique_lock<boost::mutex> lk(state_change);
263 state.assert_lock_shared();
264 state.unlock_shared();
265 if (state.get_shared_count () == 0)
266 {
267 if (state.unlock_shared_downgrades())
268 {
269 lk.unlock();
270 upgrade_cond.notify_one();
271 } else {
272 lk.unlock();
273 }
274 release_waiters();
275 }
276 }
277
278 void lock()
279 {
280 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
281 boost::this_thread::disable_interruption do_not_disturb;
282 #endif
283 boost::unique_lock<boost::mutex> lk(state_change);
284
285 while(!state.can_lock())
286 {
287 state.exclusive_blocked(true);
288 exclusive_cond.wait(lk);
289 }
290 state.lock();
291 }
292
293 #if defined BOOST_THREAD_USES_DATETIME
294 bool timed_lock(system_time const& timeout)
295 {
296 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
297 boost::this_thread::disable_interruption do_not_disturb;
298 #endif
299 boost::unique_lock<boost::mutex> lk(state_change);
300
301 while(!state.can_lock())
302 {
303 state.exclusive_blocked(true);
304 if(!exclusive_cond.timed_wait(lk,timeout))
305 {
306 if(!state.can_lock())
307 {
308 state.exclusive_blocked(false);
309 release_waiters();
310 return false;
311 }
312 break;
313 }
314 }
315 state.exclusive=true;
316 //state.lock();
317 return true;
318 }
319
320 template<typename TimeDuration>
321 bool timed_lock(TimeDuration const & relative_time)
322 {
323 return timed_lock(get_system_time()+relative_time);
324 }
325 #endif
326 #ifdef BOOST_THREAD_USES_CHRONO
327 template <class Rep, class Period>
328 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
329 {
330 return try_lock_until(chrono::steady_clock::now() + rel_time);
331 }
332 template <class Clock, class Duration>
333 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
334 {
335 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
336 boost::this_thread::disable_interruption do_not_disturb;
337 #endif
338 boost::unique_lock<boost::mutex> lk(state_change);
339
340 while(!state.can_lock())
341 {
342 state.exclusive_blocked(true);
343 if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
344 {
345 if(!state.can_lock())
346 {
347 state.exclusive_blocked(false);
348 release_waiters();
349 return false;
350 }
351 break;
352 }
353 }
354 state.exclusive=true;
355 //state.lock();
356 return true;
357 }
358 #endif
359
360 bool try_lock()
361 {
362 boost::unique_lock<boost::mutex> lk(state_change);
363
364 if(!state.can_lock())
365 {
366 return false;
367 }
368 else
369 {
370 state.lock();
371 return true;
372 }
373
374 }
375
376 void unlock()
377 {
378 boost::unique_lock<boost::mutex> lk(state_change);
379 state.assert_locked();
380 state.unlock();
381 state.assert_free();
382 release_waiters();
383 }
384
385 void lock_upgrade()
386 {
387 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
388 boost::this_thread::disable_interruption do_not_disturb;
389 #endif
390 boost::unique_lock<boost::mutex> lk(state_change);
391 while(!state.can_lock_upgrade())
392 {
393 shared_cond.wait(lk);
394 }
395 state.lock_upgrade();
396 }
397
398 #if defined BOOST_THREAD_USES_DATETIME
399 bool timed_lock_upgrade(system_time const& timeout)
400 {
401 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
402 boost::this_thread::disable_interruption do_not_disturb;
403 #endif
404 boost::unique_lock<boost::mutex> lk(state_change);
405 while(!state.can_lock_upgrade())
406 {
407 if(!shared_cond.timed_wait(lk,timeout))
408 {
409 if(!state.can_lock_upgrade())
410 {
411 return false;
412 }
413 break;
414 }
415 }
416 state.lock_upgrade();
417 return true;
418 }
419
420 template<typename TimeDuration>
421 bool timed_lock_upgrade(TimeDuration const & relative_time)
422 {
423 return timed_lock_upgrade(get_system_time()+relative_time);
424 }
425 #endif
426 #ifdef BOOST_THREAD_USES_CHRONO
427 template <class Rep, class Period>
428 bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
429 {
430 return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
431 }
432 template <class Clock, class Duration>
433 bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
434 {
435 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
436 boost::this_thread::disable_interruption do_not_disturb;
437 #endif
438 boost::unique_lock<boost::mutex> lk(state_change);
439 while(!state.can_lock_upgrade())
440 {
441 if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
442 {
443 if(!state.can_lock_upgrade())
444 {
445 return false;
446 }
447 break;
448 }
449 }
450 state.lock_upgrade();
451 return true;
452 }
453 #endif
454 bool try_lock_upgrade()
455 {
456 boost::unique_lock<boost::mutex> lk(state_change);
457 if(!state.can_lock_upgrade())
458 {
459 return false;
460 }
461 else
462 {
463 state.lock_upgrade();
464 state.assert_lock_upgraded();
465 return true;
466 }
467 }
468
469 void unlock_upgrade()
470 {
471 boost::unique_lock<boost::mutex> lk(state_change);
472 state.assert_lock_upgraded();
473 state.unlock_upgrade();
474 state.assert_lock_not_upgraded ();
475 if(state.get_shared_count () == 0)
476 {
477 state.exclusive_blocked(false);
478 lk.unlock();
479 release_waiters();
480 } else {
481 lk.unlock();
482 shared_cond.notify_all();
483 }
484 }
485
486 // Upgrade <-> Exclusive
487 void unlock_upgrade_and_lock()
488 {
489 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
490 boost::this_thread::disable_interruption do_not_disturb;
491 #endif
492 boost::unique_lock<boost::mutex> lk(state_change);
493 state.assert_lock_upgraded();
494 // assert state.get_shared_count() >=1
495 while(
496 //! state.exclusive_waiting_blocked // Fixme: is this needed?
497 //&&
498 state.get_shared_count()!=1)
499 {
500 upgrade_cond.wait(lk);
501 }
502 state.unlock_upgrade();
503 state.lock();
504 state.assert_locked();
505 }
506
507 void unlock_and_lock_upgrade()
508 {
509 boost::unique_lock<boost::mutex> lk(state_change);
510 state.assert_locked();
511 state.unlock();
512 state.lock_upgrade();
513 state.assert_lock_upgraded();
514 release_waiters();
515 }
516
517 bool try_unlock_upgrade_and_lock()
518 {
519 boost::unique_lock<boost::mutex> lk(state_change);
520 state.assert_lock_upgraded();
521 if( //!state.exclusive // this should be removed once the assertion work
522 ! state.exclusive_waiting_blocked // Fixme: why this is needed?
523 //&& state.upgrade // this should be removed once the assertion work
524 && state.get_shared_count()==1)
525 {
526 state.unlock_upgrade();
527 state.lock();
528 state.assert_locked();
529 return true;
530 }
531 return false;
532 }
533 #ifdef BOOST_THREAD_USES_CHRONO
534 template <class Rep, class Period>
535 bool
536 try_unlock_upgrade_and_lock_for(
537 const chrono::duration<Rep, Period>& rel_time)
538 {
539 return try_unlock_upgrade_and_lock_until(
540 chrono::steady_clock::now() + rel_time);
541 }
542 template <class Clock, class Duration>
543 bool
544 try_unlock_upgrade_and_lock_until(
545 const chrono::time_point<Clock, Duration>& abs_time)
546 {
547 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
548 boost::this_thread::disable_interruption do_not_disturb;
549 #endif
550 boost::unique_lock<boost::mutex> lk(state_change);
551 state.assert_lock_upgraded();
552 if (//state.exclusive // this should be removed once the assertion work
553 state.exclusive_waiting_blocked // Fixme: is this needed?
554 //|| ! state.upgrade // this should be removed once the assertion work
555 || state.get_shared_count() != 1)
556 {
557 for (;;)
558 {
559 //cv_status status = shared_cond.wait_until(lk,abs_time);
560 cv_status status = upgrade_cond.wait_until(lk,abs_time);
561 if (//!state.exclusive // this should be removed once the assertion work
562 ! state.exclusive_waiting_blocked // Fixme: is this needed?
563 //&& ! state.upgrade // this should be removed once the assertion work
564 && state.get_shared_count() == 1)
565 break;
566 if(status == cv_status::timeout)
567 return false;
568 }
569 }
570 state.unlock_upgrade();
571 state.lock();
572 return true;
573 }
574 #endif
575
576 // Shared <-> Exclusive
577 void unlock_and_lock_shared()
578 {
579 boost::unique_lock<boost::mutex> lk(state_change);
580 state.assert_locked();
581 state.unlock();
582 state.lock_shared();
583 release_waiters();
584 }
585
586 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
587 bool try_unlock_shared_and_lock()
588 {
589 boost::unique_lock<boost::mutex> lk(state_change);
590 state.assert_lock_shared();
591 if( //!state.exclusive // this should be removed once the assertion work
592 ! state.exclusive_waiting_blocked // Fixme: why this is needed?
593 //&& ! state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
594 && state.get_shared_count()==1)
595 {
596 state.unlock_shared();
597 state.lock();
598 return true;
599 }
600 return false;
601 }
602 #ifdef BOOST_THREAD_USES_CHRONO
603 template <class Rep, class Period>
604 bool
605 try_unlock_shared_and_lock_for(
606 const chrono::duration<Rep, Period>& rel_time)
607 {
608 return try_unlock_shared_and_lock_until(
609 chrono::steady_clock::now() + rel_time);
610 }
611 template <class Clock, class Duration>
612 bool
613 try_unlock_shared_and_lock_until(
614 const chrono::time_point<Clock, Duration>& abs_time)
615 {
616 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
617 boost::this_thread::disable_interruption do_not_disturb;
618 #endif
619 boost::unique_lock<boost::mutex> lk(state_change);
620 state.assert_lock_shared();
621 if ( // !state.exclusive // this should be removed once the assertion work
622 state.exclusive_waiting_blocked // Fixme: is this needed?
623 //|| state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
624 || state.get_shared_count() != 1)
625 {
626 for (;;)
627 {
628 cv_status status = shared_cond.wait_until(lk,abs_time);
629 if ( //! state.exclusive // this should be removed once the assertion work
630 ! state.exclusive_waiting_blocked // Fixme: is this needed?
631 //&& ! state.upgrade
632 && state.get_shared_count() == 1)
633 break;
634 if(status == cv_status::timeout)
635 return false;
636 }
637 }
638 state.unlock_shared();
639 state.lock();
640 state.upgrade=false; // Is this absolutely needed?
641 state.exclusive_waiting_blocked=false; // Is this absolutely needed?
642 return true;
643 }
644 #endif
645 #endif
646
647 // Shared <-> Upgrade
648 void unlock_upgrade_and_lock_shared()
649 {
650 boost::unique_lock<boost::mutex> lk(state_change);
651 state.assert_lock_upgraded();
652 //state.unlock_upgrade();
653 //state.lock_shared(); // less efficient
654 state.upgrade=false;
655 state.exclusive_waiting_blocked=false; // Is this absolutely needed?
656 release_waiters();
657 }
658
659 #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
660 bool try_unlock_shared_and_lock_upgrade()
661 {
662 boost::unique_lock<boost::mutex> lk(state_change);
663 state.assert_lock_shared();
664 if( //! state.exclusive // this should be removed once the assertion work
665 ! state.exclusive_waiting_blocked // Fixme: is this needed?
666 && ! state.upgrade
667 )
668 {
669 state.upgrade=true;
670 return true;
671 }
672 return false;
673 }
674 #ifdef BOOST_THREAD_USES_CHRONO
675 template <class Rep, class Period>
676 bool
677 try_unlock_shared_and_lock_upgrade_for(
678 const chrono::duration<Rep, Period>& rel_time)
679 {
680 return try_unlock_shared_and_lock_upgrade_until(
681 chrono::steady_clock::now() + rel_time);
682 }
683 template <class Clock, class Duration>
684 bool
685 try_unlock_shared_and_lock_upgrade_until(
686 const chrono::time_point<Clock, Duration>& abs_time)
687 {
688 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
689 boost::this_thread::disable_interruption do_not_disturb;
690 #endif
691 boost::unique_lock<boost::mutex> lk(state_change);
692 state.assert_lock_shared();
693 if( //state.exclusive // this should be removed once the assertion work
694 state.exclusive_waiting_blocked // Fixme: is this needed?
695 || state.upgrade
696 )
697 {
698 for (;;)
699 {
700 cv_status status = exclusive_cond.wait_until(lk,abs_time);
701 if( //! state.exclusive // this should be removed once the assertion work
702 ! state.exclusive_waiting_blocked // Fixme: is this needed?
703 && ! state.upgrade
704 )
705 break;
706 if(status == cv_status::timeout)
707 return false;
708 }
709 }
710 //state.unlock_shared();
711 //state.lock_upgrade(); // less efficient
712 state.upgrade=true;
713 return true;
714 }
715 #endif
716 #endif
717 };
718
719 typedef shared_mutex upgrade_mutex;
720 }
721
722 #include <boost/config/abi_suffix.hpp>
723
724 #endif