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:
state_data()35             state_data () :
36               shared_count(0),
37               exclusive(false),
38               upgrade(false),
39               exclusive_waiting_blocked(false)
40             {}
41 
assert_free() const42             void assert_free() const
43             {
44                 BOOST_ASSERT( ! exclusive );
45                 BOOST_ASSERT( ! upgrade );
46                 BOOST_ASSERT( shared_count==0 );
47             }
48 
assert_locked() const49             void assert_locked() const
50             {
51                 BOOST_ASSERT( exclusive );
52                 BOOST_ASSERT( shared_count==0 );
53                 BOOST_ASSERT( ! upgrade );
54             }
55 
assert_lock_shared() const56             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 
assert_lock_upgraded() const65             void assert_lock_upgraded () const
66             {
67                 BOOST_ASSERT( ! exclusive );
68                 BOOST_ASSERT(  upgrade );
69                 BOOST_ASSERT(  shared_count>0 );
70             }
71 
assert_lock_not_upgraded() const72             void assert_lock_not_upgraded () const
73             {
74                 BOOST_ASSERT(  ! upgrade );
75             }
76 
can_lock() const77             bool can_lock () const
78             {
79                 return ! (shared_count || exclusive);
80             }
81 
exclusive_blocked(bool blocked)82             void exclusive_blocked (bool blocked)
83             {
84                 exclusive_waiting_blocked = blocked;
85             }
86 
lock()87             void lock ()
88             {
89                 exclusive = true;
90             }
91 
unlock()92             void unlock ()
93             {
94                 exclusive = false;
95                 exclusive_waiting_blocked = false;
96             }
97 
can_lock_shared() const98             bool can_lock_shared () const
99             {
100                 return ! (exclusive || exclusive_waiting_blocked);
101             }
102 
is_last_shared() const103             bool is_last_shared () const
104             {
105                 return !shared_count ;
106             }
get_shared_count() const107             unsigned get_shared_count () const
108             {
109                 return shared_count ;
110             }
lock_shared()111             unsigned  lock_shared ()
112             {
113                 return ++shared_count;
114             }
115 
116 
unlock_shared()117             void unlock_shared ()
118             {
119                 --shared_count;
120             }
121 
unlock_shared_downgrades()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 
lock_upgrade()134             void lock_upgrade ()
135             {
136                 lock_shared ();
137                 upgrade=true;
138             }
can_lock_upgrade() const139             bool can_lock_upgrade () const
140             {
141                 return ! (exclusive || exclusive_waiting_blocked || upgrade);
142             }
143 
unlock_upgrade()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 
release_waiters()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 
shared_mutex()174         shared_mutex()
175         {
176         }
177 
~shared_mutex()178         ~shared_mutex()
179         {
180         }
181 
lock_shared()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 
try_lock_shared()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
timed_lock_shared(system_time const & timeout)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>
timed_lock_shared(TimeDuration const & relative_time)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>
try_lock_shared_for(const chrono::duration<Rep,Period> & rel_time)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>
try_lock_shared_until(const chrono::time_point<Clock,Duration> & abs_time)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
unlock_shared()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 
lock()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
timed_lock(system_time const & timeout)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>
timed_lock(TimeDuration const & relative_time)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>
try_lock_for(const chrono::duration<Rep,Period> & rel_time)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>
try_lock_until(const chrono::time_point<Clock,Duration> & abs_time)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 
try_lock()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 
unlock()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 
lock_upgrade()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
timed_lock_upgrade(system_time const & timeout)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>
timed_lock_upgrade(TimeDuration const & relative_time)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>
try_lock_upgrade_for(const chrono::duration<Rep,Period> & rel_time)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>
try_lock_upgrade_until(const chrono::time_point<Clock,Duration> & abs_time)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
try_lock_upgrade()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 
unlock_upgrade()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
unlock_upgrade_and_lock()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 
unlock_and_lock_upgrade()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 
try_unlock_upgrade_and_lock()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
try_unlock_upgrade_and_lock_for(const chrono::duration<Rep,Period> & rel_time)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
try_unlock_upgrade_and_lock_until(const chrono::time_point<Clock,Duration> & abs_time)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
unlock_and_lock_shared()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
try_unlock_shared_and_lock()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
try_unlock_shared_and_lock_for(const chrono::duration<Rep,Period> & rel_time)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
try_unlock_shared_and_lock_until(const chrono::time_point<Clock,Duration> & abs_time)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
unlock_upgrade_and_lock_shared()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
try_unlock_shared_and_lock_upgrade()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
try_unlock_shared_and_lock_upgrade_for(const chrono::duration<Rep,Period> & rel_time)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
try_unlock_shared_and_lock_upgrade_until(const chrono::time_point<Clock,Duration> & abs_time)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
725