1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 //  Code based on Howard Hinnant's upgrade_mutex class
4 //
5 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
6 // Software License, Version 1.0. (See accompanying file
7 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // See http://www.boost.org/libs/interprocess for documentation.
10 //
11 //////////////////////////////////////////////////////////////////////////////
12 
13 #ifndef BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
14 #define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
15 
16 #ifndef BOOST_CONFIG_HPP
17 #  include <boost/config.hpp>
18 #endif
19 #
20 #if defined(BOOST_HAS_PRAGMA_ONCE)
21 #  pragma once
22 #endif
23 
24 #include <boost/interprocess/detail/config_begin.hpp>
25 #include <boost/interprocess/detail/workaround.hpp>
26 #include <boost/interprocess/sync/scoped_lock.hpp>
27 #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
28 #include <boost/interprocess/sync/interprocess_mutex.hpp>
29 #include <boost/interprocess/sync/interprocess_condition.hpp>
30 #include <climits>
31 
32 
33 //!\file
34 //!Describes interprocess_upgradable_mutex class
35 
36 namespace boost {
37 namespace interprocess {
38 
39 //!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be
40 //!shared between processes. Allows timed lock tries
41 class interprocess_upgradable_mutex
42 {
43    //Non-copyable
44    interprocess_upgradable_mutex(const interprocess_upgradable_mutex &);
45    interprocess_upgradable_mutex &operator=(const interprocess_upgradable_mutex &);
46 
47    friend class interprocess_condition;
48    public:
49 
50    //!Constructs the upgradable lock.
51    //!Throws interprocess_exception on error.
52    interprocess_upgradable_mutex();
53 
54    //!Destroys the upgradable lock.
55    //!Does not throw.
56    ~interprocess_upgradable_mutex();
57 
58    //Exclusive locking
59 
60    //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
61    //!   and if another thread has exclusive, sharable or upgradable ownership of
62    //!   the mutex, it waits until it can obtain the ownership.
63    //!Throws: interprocess_exception on error.
64    void lock();
65 
66    //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
67    //!   without waiting. If no other thread has exclusive, sharable or upgradable
68    //!   ownership of the mutex this succeeds.
69    //!Returns: If it can acquire exclusive ownership immediately returns true.
70    //!   If it has to wait, returns false.
71    //!Throws: interprocess_exception on error.
72    bool try_lock();
73 
74    //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
75    //!   waiting if necessary until no other thread has exclusive, sharable or
76    //!   upgradable ownership of the mutex or abs_time is reached.
77    //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
78    //!Throws: interprocess_exception on error.
79    bool timed_lock(const boost::posix_time::ptime &abs_time);
80 
81    //!Precondition: The thread must have exclusive ownership of the mutex.
82    //!Effects: The calling thread releases the exclusive ownership of the mutex.
83    //!Throws: An exception derived from interprocess_exception on error.
84    void unlock();
85 
86    //Sharable locking
87 
88    //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
89    //!   and if another thread has exclusive ownership of the mutex,
90    //!   waits until it can obtain the ownership.
91    //!Throws: interprocess_exception on error.
92    void lock_sharable();
93 
94    //!Effects: The calling thread tries to acquire sharable ownership of the mutex
95    //!   without waiting. If no other thread has exclusive ownership
96    //!   of the mutex this succeeds.
97    //!Returns: If it can acquire sharable ownership immediately returns true. If it
98    //!   has to wait, returns false.
99    //!Throws: interprocess_exception on error.
100    bool try_lock_sharable();
101 
102    //!Effects: The calling thread tries to acquire sharable ownership of the mutex
103    //!   waiting if necessary until no other thread has exclusive
104    //!   ownership of the mutex or abs_time is reached.
105    //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
106    //!Throws: interprocess_exception on error.
107    bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
108 
109    //!Precondition: The thread must have sharable ownership of the mutex.
110    //!Effects: The calling thread releases the sharable ownership of the mutex.
111    //!Throws: An exception derived from interprocess_exception on error.
112    void unlock_sharable();
113 
114    //Upgradable locking
115 
116    //!Effects: The calling thread tries to obtain upgradable ownership of the mutex,
117    //!   and if another thread has exclusive or upgradable ownership of the mutex,
118    //!   waits until it can obtain the ownership.
119    //!Throws: interprocess_exception on error.
120    void lock_upgradable();
121 
122    //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
123    //!   without waiting. If no other thread has exclusive or upgradable ownership
124    //!   of the mutex this succeeds.
125    //!Returns: If it can acquire upgradable ownership immediately returns true.
126    //!   If it has to wait, returns false.
127    //!Throws: interprocess_exception on error.
128    bool try_lock_upgradable();
129 
130    //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
131    //!   waiting if necessary until no other thread has exclusive or upgradable
132    //!   ownership of the mutex or abs_time is reached.
133    //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
134    //!Throws: interprocess_exception on error.
135    bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time);
136 
137    //!Precondition: The thread must have upgradable ownership of the mutex.
138    //!Effects: The calling thread releases the upgradable ownership of the mutex.
139    //!Throws: An exception derived from interprocess_exception on error.
140    void unlock_upgradable();
141 
142    //Demotions
143 
144    //!Precondition: The thread must have exclusive ownership of the mutex.
145    //!Effects: The thread atomically releases exclusive ownership and acquires
146    //!   upgradable ownership. This operation is non-blocking.
147    //!Throws: An exception derived from interprocess_exception on error.
148    void unlock_and_lock_upgradable();
149 
150    //!Precondition: The thread must have exclusive ownership of the mutex.
151    //!Effects: The thread atomically releases exclusive ownership and acquires
152    //!   sharable ownership. This operation is non-blocking.
153    //!Throws: An exception derived from interprocess_exception on error.
154    void unlock_and_lock_sharable();
155 
156    //!Precondition: The thread must have upgradable ownership of the mutex.
157    //!Effects: The thread atomically releases upgradable ownership and acquires
158    //!   sharable ownership. This operation is non-blocking.
159    //!Throws: An exception derived from interprocess_exception on error.
160    void unlock_upgradable_and_lock_sharable();
161 
162    //Promotions
163 
164    //!Precondition: The thread must have upgradable ownership of the mutex.
165    //!Effects: The thread atomically releases upgradable ownership and acquires
166    //!   exclusive ownership. This operation will block until all threads with
167    //!   sharable ownership release their sharable lock.
168    //!Throws: An exception derived from interprocess_exception on error.
169    void unlock_upgradable_and_lock();
170 
171    //!Precondition: The thread must have upgradable ownership of the mutex.
172    //!Effects: The thread atomically releases upgradable ownership and tries to
173    //!   acquire exclusive ownership. This operation will fail if there are threads
174    //!   with sharable ownership, but it will maintain upgradable ownership.
175    //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
176    //!Throws: An exception derived from interprocess_exception on error.
177    bool try_unlock_upgradable_and_lock();
178 
179    //!Precondition: The thread must have upgradable ownership of the mutex.
180    //!Effects: The thread atomically releases upgradable ownership and tries to acquire
181    //!   exclusive ownership, waiting if necessary until abs_time. This operation will
182    //!   fail if there are threads with sharable ownership or timeout reaches, but it
183    //!   will maintain upgradable ownership.
184    //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
185    //!Throws: An exception derived from interprocess_exception on error. */
186    bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time);
187 
188    //!Precondition: The thread must have sharable ownership of the mutex.
189    //!Effects: The thread atomically releases sharable ownership and tries to acquire
190    //!   exclusive ownership. This operation will fail if there are threads with sharable
191    //!   or upgradable ownership, but it will maintain sharable ownership.
192    //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
193    //!Throws: An exception derived from interprocess_exception on error.
194    bool try_unlock_sharable_and_lock();
195 
196    //!Precondition: The thread must have sharable ownership of the mutex.
197    //!Effects: The thread atomically releases sharable ownership and tries to acquire
198    //!   upgradable ownership. This operation will fail if there are threads with sharable
199    //!   or upgradable ownership, but it will maintain sharable ownership.
200    //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
201    //!Throws: An exception derived from interprocess_exception on error.
202    bool try_unlock_sharable_and_lock_upgradable();
203 
204    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
205    private:
206    typedef scoped_lock<interprocess_mutex> scoped_lock_t;
207 
208    //Pack all the control data in a word to be able
209    //to use atomic instructions in the future
210    struct control_word_t
211    {
212       unsigned exclusive_in         : 1;
213       unsigned upgradable_in        : 1;
214       unsigned num_upr_shar         : sizeof(unsigned)*CHAR_BIT-2;
215    }                       m_ctrl;
216 
217    interprocess_mutex      m_mut;
218    interprocess_condition  m_first_gate;
219    interprocess_condition  m_second_gate;
220 
221    private:
222    //Rollback structures for exceptions or failure return values
223    struct exclusive_rollback
224    {
exclusive_rollbackboost::interprocess::interprocess_upgradable_mutex::exclusive_rollback225       exclusive_rollback(control_word_t         &ctrl
226                         ,interprocess_condition &first_gate)
227          :  mp_ctrl(&ctrl), m_first_gate(first_gate)
228       {}
229 
releaseboost::interprocess::interprocess_upgradable_mutex::exclusive_rollback230       void release()
231       {  mp_ctrl = 0;   }
232 
~exclusive_rollbackboost::interprocess::interprocess_upgradable_mutex::exclusive_rollback233       ~exclusive_rollback()
234       {
235          if(mp_ctrl){
236             mp_ctrl->exclusive_in = 0;
237             m_first_gate.notify_all();
238          }
239       }
240       control_word_t          *mp_ctrl;
241       interprocess_condition  &m_first_gate;
242    };
243 
244    struct upgradable_to_exclusive_rollback
245    {
upgradable_to_exclusive_rollbackboost::interprocess::interprocess_upgradable_mutex::upgradable_to_exclusive_rollback246       upgradable_to_exclusive_rollback(control_word_t         &ctrl)
247          :  mp_ctrl(&ctrl)
248       {}
249 
releaseboost::interprocess::interprocess_upgradable_mutex::upgradable_to_exclusive_rollback250       void release()
251       {  mp_ctrl = 0;   }
252 
~upgradable_to_exclusive_rollbackboost::interprocess::interprocess_upgradable_mutex::upgradable_to_exclusive_rollback253       ~upgradable_to_exclusive_rollback()
254       {
255          if(mp_ctrl){
256             //Recover upgradable lock
257             mp_ctrl->upgradable_in = 1;
258             ++mp_ctrl->num_upr_shar;
259             //Execute the second half of exclusive locking
260             mp_ctrl->exclusive_in = 0;
261          }
262       }
263       control_word_t          *mp_ctrl;
264    };
265 
266    template<int Dummy>
267    struct base_constants_t
268    {
269       static const unsigned max_readers
270          = ~(unsigned(3) << (sizeof(unsigned)*CHAR_BIT-2));
271    };
272    typedef base_constants_t<0> constants;
273    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
274 };
275 
276 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
277 
278 template <int Dummy>
279 const unsigned interprocess_upgradable_mutex::base_constants_t<Dummy>::max_readers;
280 
interprocess_upgradable_mutex()281 inline interprocess_upgradable_mutex::interprocess_upgradable_mutex()
282 {
283    this->m_ctrl.exclusive_in  = 0;
284    this->m_ctrl.upgradable_in = 0;
285    this->m_ctrl.num_upr_shar   = 0;
286 }
287 
~interprocess_upgradable_mutex()288 inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex()
289 {}
290 
lock()291 inline void interprocess_upgradable_mutex::lock()
292 {
293    scoped_lock_t lck(m_mut);
294 
295    //The exclusive lock must block in the first gate
296    //if an exclusive or upgradable lock has been acquired
297    while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
298       this->m_first_gate.wait(lck);
299    }
300 
301    //Mark that exclusive lock has been acquired
302    this->m_ctrl.exclusive_in = 1;
303 
304    //Prepare rollback
305    exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
306 
307    //Now wait until all readers are gone
308    while (this->m_ctrl.num_upr_shar){
309       this->m_second_gate.wait(lck);
310    }
311    rollback.release();
312 }
313 
try_lock()314 inline bool interprocess_upgradable_mutex::try_lock()
315 {
316    scoped_lock_t lck(m_mut, try_to_lock);
317 
318    //If we can't lock or any has there is any exclusive, upgradable
319    //or sharable mark return false;
320    if(!lck.owns()
321       || this->m_ctrl.exclusive_in
322       || this->m_ctrl.num_upr_shar){
323       return false;
324    }
325    this->m_ctrl.exclusive_in = 1;
326    return true;
327 }
328 
timed_lock(const boost::posix_time::ptime & abs_time)329 inline bool interprocess_upgradable_mutex::timed_lock
330    (const boost::posix_time::ptime &abs_time)
331 {
332    //Mutexes and condvars handle just fine infinite abs_times
333    //so avoid checking it here
334    scoped_lock_t lck(m_mut, abs_time);
335    if(!lck.owns())   return false;
336 
337    //The exclusive lock must block in the first gate
338    //if an exclusive or upgradable lock has been acquired
339    while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
340       if(!this->m_first_gate.timed_wait(lck, abs_time)){
341          if(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
342             return false;
343          }
344          break;
345       }
346    }
347 
348    //Mark that exclusive lock has been acquired
349    this->m_ctrl.exclusive_in = 1;
350 
351    //Prepare rollback
352    exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
353 
354    //Now wait until all readers are gone
355    while (this->m_ctrl.num_upr_shar){
356       if(!this->m_second_gate.timed_wait(lck, abs_time)){
357          if(this->m_ctrl.num_upr_shar){
358             return false;
359          }
360          break;
361       }
362    }
363    rollback.release();
364    return true;
365 }
366 
unlock()367 inline void interprocess_upgradable_mutex::unlock()
368 {
369    scoped_lock_t lck(m_mut);
370    this->m_ctrl.exclusive_in = 0;
371    this->m_first_gate.notify_all();
372 }
373 
374 //Upgradable locking
375 
lock_upgradable()376 inline void interprocess_upgradable_mutex::lock_upgradable()
377 {
378    scoped_lock_t lck(m_mut);
379 
380    //The upgradable lock must block in the first gate
381    //if an exclusive or upgradable lock has been acquired
382    //or there are too many sharable locks
383    while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in
384          || this->m_ctrl.num_upr_shar == constants::max_readers){
385       this->m_first_gate.wait(lck);
386    }
387 
388    //Mark that upgradable lock has been acquired
389    //And add upgradable to the sharable count
390    this->m_ctrl.upgradable_in = 1;
391    ++this->m_ctrl.num_upr_shar;
392 }
393 
try_lock_upgradable()394 inline bool interprocess_upgradable_mutex::try_lock_upgradable()
395 {
396    scoped_lock_t lck(m_mut, try_to_lock);
397 
398    //The upgradable lock must fail
399    //if an exclusive or upgradable lock has been acquired
400    //or there are too many sharable locks
401    if(!lck.owns()
402       || this->m_ctrl.exclusive_in
403       || this->m_ctrl.upgradable_in
404       || this->m_ctrl.num_upr_shar == constants::max_readers){
405       return false;
406    }
407 
408    //Mark that upgradable lock has been acquired
409    //And add upgradable to the sharable count
410    this->m_ctrl.upgradable_in = 1;
411    ++this->m_ctrl.num_upr_shar;
412    return true;
413 }
414 
timed_lock_upgradable(const boost::posix_time::ptime & abs_time)415 inline bool interprocess_upgradable_mutex::timed_lock_upgradable
416    (const boost::posix_time::ptime &abs_time)
417 {
418    //Mutexes and condvars handle just fine infinite abs_times
419    //so avoid checking it here
420    scoped_lock_t lck(m_mut, abs_time);
421    if(!lck.owns())   return false;
422 
423    //The upgradable lock must block in the first gate
424    //if an exclusive or upgradable lock has been acquired
425    //or there are too many sharable locks
426    while(this->m_ctrl.exclusive_in
427          || this->m_ctrl.upgradable_in
428          || this->m_ctrl.num_upr_shar == constants::max_readers){
429       if(!this->m_first_gate.timed_wait(lck, abs_time)){
430          if((this->m_ctrl.exclusive_in
431              || this->m_ctrl.upgradable_in
432              || this->m_ctrl.num_upr_shar == constants::max_readers)){
433             return false;
434          }
435          break;
436       }
437    }
438 
439    //Mark that upgradable lock has been acquired
440    //And add upgradable to the sharable count
441    this->m_ctrl.upgradable_in = 1;
442    ++this->m_ctrl.num_upr_shar;
443    return true;
444 }
445 
unlock_upgradable()446 inline void interprocess_upgradable_mutex::unlock_upgradable()
447 {
448    scoped_lock_t lck(m_mut);
449    //Mark that upgradable lock has been acquired
450    //And add upgradable to the sharable count
451    this->m_ctrl.upgradable_in = 0;
452    --this->m_ctrl.num_upr_shar;
453    this->m_first_gate.notify_all();
454 }
455 
456 //Sharable locking
457 
lock_sharable()458 inline void interprocess_upgradable_mutex::lock_sharable()
459 {
460    scoped_lock_t lck(m_mut);
461 
462    //The sharable lock must block in the first gate
463    //if an exclusive lock has been acquired
464    //or there are too many sharable locks
465    while(this->m_ctrl.exclusive_in
466         || this->m_ctrl.num_upr_shar == constants::max_readers){
467       this->m_first_gate.wait(lck);
468    }
469 
470    //Increment sharable count
471    ++this->m_ctrl.num_upr_shar;
472 }
473 
try_lock_sharable()474 inline bool interprocess_upgradable_mutex::try_lock_sharable()
475 {
476    scoped_lock_t lck(m_mut, try_to_lock);
477 
478    //The sharable lock must fail
479    //if an exclusive lock has been acquired
480    //or there are too many sharable locks
481    if(!lck.owns()
482       || this->m_ctrl.exclusive_in
483       || this->m_ctrl.num_upr_shar == constants::max_readers){
484       return false;
485    }
486 
487    //Increment sharable count
488    ++this->m_ctrl.num_upr_shar;
489    return true;
490 }
491 
timed_lock_sharable(const boost::posix_time::ptime & abs_time)492 inline bool interprocess_upgradable_mutex::timed_lock_sharable
493    (const boost::posix_time::ptime &abs_time)
494 {
495    //Mutexes and condvars handle just fine infinite abs_times
496    //so avoid checking it here
497    scoped_lock_t lck(m_mut, abs_time);
498    if(!lck.owns())   return false;
499 
500    //The sharable lock must block in the first gate
501    //if an exclusive lock has been acquired
502    //or there are too many sharable locks
503    while (this->m_ctrl.exclusive_in
504          || this->m_ctrl.num_upr_shar == constants::max_readers){
505       if(!this->m_first_gate.timed_wait(lck, abs_time)){
506          if(this->m_ctrl.exclusive_in
507             || this->m_ctrl.num_upr_shar == constants::max_readers){
508             return false;
509          }
510          break;
511       }
512    }
513 
514    //Increment sharable count
515    ++this->m_ctrl.num_upr_shar;
516    return true;
517 }
518 
unlock_sharable()519 inline void interprocess_upgradable_mutex::unlock_sharable()
520 {
521    scoped_lock_t lck(m_mut);
522    //Decrement sharable count
523    --this->m_ctrl.num_upr_shar;
524    if (this->m_ctrl.num_upr_shar == 0){
525       this->m_second_gate.notify_one();
526    }
527    //Check if there are blocked sharables because of
528    //there were too many sharables
529    else if(this->m_ctrl.num_upr_shar == (constants::max_readers-1)){
530       this->m_first_gate.notify_all();
531    }
532 }
533 
534 //Downgrading
535 
unlock_and_lock_upgradable()536 inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable()
537 {
538    scoped_lock_t lck(m_mut);
539    //Unmark it as exclusive
540    this->m_ctrl.exclusive_in     = 0;
541    //Mark it as upgradable
542    this->m_ctrl.upgradable_in    = 1;
543    //The sharable count should be 0 so increment it
544    this->m_ctrl.num_upr_shar   = 1;
545    //Notify readers that they can enter
546    m_first_gate.notify_all();
547 }
548 
unlock_and_lock_sharable()549 inline void interprocess_upgradable_mutex::unlock_and_lock_sharable()
550 {
551    scoped_lock_t lck(m_mut);
552    //Unmark it as exclusive
553    this->m_ctrl.exclusive_in   = 0;
554    //The sharable count should be 0 so increment it
555    this->m_ctrl.num_upr_shar   = 1;
556    //Notify readers that they can enter
557    m_first_gate.notify_all();
558 }
559 
unlock_upgradable_and_lock_sharable()560 inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable()
561 {
562    scoped_lock_t lck(m_mut);
563    //Unmark it as upgradable (we don't have to decrement count)
564    this->m_ctrl.upgradable_in    = 0;
565    //Notify readers/upgradable that they can enter
566    m_first_gate.notify_all();
567 }
568 
569 //Upgrading
570 
unlock_upgradable_and_lock()571 inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock()
572 {
573    scoped_lock_t lck(m_mut);
574    //Simulate unlock_upgradable() without
575    //notifying sharables.
576    this->m_ctrl.upgradable_in = 0;
577    --this->m_ctrl.num_upr_shar;
578    //Execute the second half of exclusive locking
579    this->m_ctrl.exclusive_in = 1;
580 
581    //Prepare rollback
582    upgradable_to_exclusive_rollback rollback(m_ctrl);
583 
584    while (this->m_ctrl.num_upr_shar){
585       this->m_second_gate.wait(lck);
586    }
587    rollback.release();
588 }
589 
try_unlock_upgradable_and_lock()590 inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock()
591 {
592    scoped_lock_t lck(m_mut, try_to_lock);
593    //Check if there are no readers
594    if(!lck.owns()
595       || this->m_ctrl.num_upr_shar != 1){
596       return false;
597    }
598    //Now unlock upgradable and mark exclusive
599    this->m_ctrl.upgradable_in = 0;
600    --this->m_ctrl.num_upr_shar;
601    this->m_ctrl.exclusive_in = 1;
602    return true;
603 }
604 
timed_unlock_upgradable_and_lock(const boost::posix_time::ptime & abs_time)605 inline bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock
606    (const boost::posix_time::ptime &abs_time)
607 {
608    //Mutexes and condvars handle just fine infinite abs_times
609    //so avoid checking it here
610    scoped_lock_t lck(m_mut, abs_time);
611    if(!lck.owns())   return false;
612 
613    //Simulate unlock_upgradable() without
614    //notifying sharables.
615    this->m_ctrl.upgradable_in = 0;
616    --this->m_ctrl.num_upr_shar;
617    //Execute the second half of exclusive locking
618    this->m_ctrl.exclusive_in = 1;
619 
620    //Prepare rollback
621    upgradable_to_exclusive_rollback rollback(m_ctrl);
622 
623    while (this->m_ctrl.num_upr_shar){
624       if(!this->m_second_gate.timed_wait(lck, abs_time)){
625          if(this->m_ctrl.num_upr_shar){
626             return false;
627          }
628          break;
629       }
630    }
631    rollback.release();
632    return true;
633 }
634 
try_unlock_sharable_and_lock()635 inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock()
636 {
637    scoped_lock_t lck(m_mut, try_to_lock);
638 
639    //If we can't lock or any has there is any exclusive, upgradable
640    //or sharable mark return false;
641    if(!lck.owns()
642       || this->m_ctrl.exclusive_in
643       || this->m_ctrl.upgradable_in
644       || this->m_ctrl.num_upr_shar != 1){
645       return false;
646    }
647    this->m_ctrl.exclusive_in = 1;
648    this->m_ctrl.num_upr_shar = 0;
649    return true;
650 }
651 
try_unlock_sharable_and_lock_upgradable()652 inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
653 {
654    scoped_lock_t lck(m_mut, try_to_lock);
655 
656    //The upgradable lock must fail
657    //if an exclusive or upgradable lock has been acquired
658    if(!lck.owns()
659       || this->m_ctrl.exclusive_in
660       || this->m_ctrl.upgradable_in){
661       return false;
662    }
663 
664    //Mark that upgradable lock has been acquired
665    this->m_ctrl.upgradable_in = 1;
666    return true;
667 }
668 
669 #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
670 
671 }  //namespace interprocess {
672 }  //namespace boost {
673 
674 
675 #include <boost/interprocess/detail/config_end.hpp>
676 
677 #endif   //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
678