Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:33

0001 ////////////////////////////////////////////////////////////////////////////////
0002 //
0003 //  Code based on Howard Hinnant's upgrade_mutex class
0004 //
0005 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
0006 // Software License, Version 1.0. (See accompanying file
0007 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0008 //
0009 // See http://www.boost.org/libs/interprocess for documentation.
0010 //
0011 //////////////////////////////////////////////////////////////////////////////
0012 
0013 #ifndef BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
0014 #define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
0015 
0016 #ifndef BOOST_CONFIG_HPP
0017 #  include <boost/config.hpp>
0018 #endif
0019 #
0020 #if defined(BOOST_HAS_PRAGMA_ONCE)
0021 #  pragma once
0022 #endif
0023 
0024 #include <boost/interprocess/detail/config_begin.hpp>
0025 #include <boost/interprocess/detail/workaround.hpp>
0026 #include <boost/interprocess/sync/scoped_lock.hpp>
0027 #include <boost/interprocess/sync/interprocess_mutex.hpp>
0028 #include <boost/interprocess/sync/interprocess_condition.hpp>
0029 #include <climits>
0030 
0031 
0032 //!\file
0033 //!Describes interprocess_upgradable_mutex class
0034 
0035 namespace boost {
0036 namespace interprocess {
0037 
0038 //!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be
0039 //!shared between processes. Allows timed lock tries
0040 class interprocess_upgradable_mutex
0041 {
0042    //Non-copyable
0043    interprocess_upgradable_mutex(const interprocess_upgradable_mutex &);
0044    interprocess_upgradable_mutex &operator=(const interprocess_upgradable_mutex &);
0045 
0046    friend class interprocess_condition;
0047    public:
0048 
0049    //!Constructs the upgradable lock.
0050    //!Throws interprocess_exception on error.
0051    interprocess_upgradable_mutex();
0052 
0053    //!Destroys the upgradable lock.
0054    //!Does not throw.
0055    ~interprocess_upgradable_mutex();
0056 
0057    //Exclusive locking
0058 
0059    //!Requires: The calling thread does not own the mutex.
0060    //!
0061    //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
0062    //!   and if another thread has exclusive, sharable or upgradable ownership of
0063    //!   the mutex, it waits until it can obtain the ownership.
0064    //!Throws: interprocess_exception on error.
0065    //! 
0066    //!Note: A program may deadlock if the thread that has ownership calls 
0067    //!   this function. If the implementation can detect the deadlock,
0068    //!   an exception could be thrown.
0069    void lock();
0070 
0071    //!Requires: The calling thread does not own the mutex.
0072    //!
0073    //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
0074    //!   without waiting. If no other thread has exclusive, sharable or upgradable
0075    //!   ownership of the mutex this succeeds.
0076    //!Returns: If it can acquire exclusive ownership immediately returns true.
0077    //!   If it has to wait, returns false.
0078    //!Throws: interprocess_exception on error.
0079    //! 
0080    //!Note: A program may deadlock if the thread that has ownership calls 
0081    //!   this function. If the implementation can detect the deadlock,
0082    //!   an exception could be thrown.
0083    bool try_lock();
0084 
0085    //!Requires: The calling thread does not own the mutex.
0086    //!
0087    //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
0088    //!   waiting if necessary until no other thread has exclusive, sharable or
0089    //!   upgradable ownership of the mutex or abs_time is reached.
0090    //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
0091    //!Throws: interprocess_exception on error.
0092    //! 
0093    //!Note: A program may deadlock if the thread that has ownership calls 
0094    //!   this function. If the implementation can detect the deadlock,
0095    //!   an exception could be thrown.
0096    template<class TimePoint>
0097    bool timed_lock(const TimePoint &abs_time);
0098 
0099    //!Same as `timed_lock`, but this function is modeled after the
0100    //!standard library interface.
0101    template<class TimePoint> bool try_lock_until(const TimePoint &abs_time)
0102    {  return this->timed_lock(abs_time);  }
0103 
0104    //!Same as `timed_lock`, but this function is modeled after the
0105    //!standard library interface.
0106    template<class Duration>  bool try_lock_for(const Duration &dur)
0107    {  return this->timed_lock(ipcdetail::duration_to_ustime(dur)); }
0108 
0109 
0110    //!Precondition: The thread must have exclusive ownership of the mutex.
0111    //!Effects: The calling thread releases the exclusive ownership of the mutex.
0112    //!Throws: An exception derived from interprocess_exception on error.
0113    void unlock();
0114 
0115    //Sharable locking
0116 
0117    //!Requires: The calling thread does not own the mutex.
0118    //!
0119    //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
0120    //!   and if another thread has exclusive ownership of the mutex,
0121    //!   waits until it can obtain the ownership.
0122    //!Throws: interprocess_exception on error.
0123    //! 
0124    //!Note: A program may deadlock if the thread that has ownership calls 
0125    //!   this function. If the implementation can detect the deadlock,
0126    //!   an exception could be thrown.
0127    void lock_sharable();
0128 
0129    //!Same as `lock_sharable` but with a std-compatible interface
0130    //! 
0131    void lock_shared()
0132    {  this->lock_sharable();  }
0133 
0134    //!Requires: The calling thread does not own the mutex.
0135    //!
0136    //!Effects: The calling thread tries to acquire sharable ownership of the mutex
0137    //!   without waiting. If no other thread has exclusive ownership
0138    //!   of the mutex this succeeds.
0139    //!Returns: If it can acquire sharable ownership immediately returns true. If it
0140    //!   has to wait, returns false.
0141    //!Throws: interprocess_exception on error.
0142    //! 
0143    //!Note: A program may deadlock if the thread that has ownership calls 
0144    //!   this function. If the implementation can detect the deadlock,
0145    //!   an exception could be thrown.
0146    bool try_lock_sharable();
0147 
0148    //!Same as `try_lock_sharable` but with a std-compatible interface
0149    //! 
0150    bool try_lock_shared()
0151    {  return this->try_lock_sharable();  }
0152 
0153    //!Requires: The calling thread does not own the mutex.
0154    //!
0155    //!Effects: The calling thread tries to acquire sharable ownership of the mutex
0156    //!   waiting if necessary until no other thread has exclusive
0157    //!   ownership of the mutex or abs_time is reached.
0158    //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
0159    //!Throws: interprocess_exception on error.
0160    //! 
0161    //!Note: A program may deadlock if the thread that has ownership calls 
0162    //!   this function. If the implementation can detect the deadlock,
0163    //!   an exception could be thrown.
0164    template<class TimePoint>
0165    bool timed_lock_sharable(const TimePoint &abs_time);
0166 
0167    //!Same as `timed_lock_sharable`, but this function is modeled after the
0168    //!standard library interface.
0169    template<class TimePoint> bool try_lock_shared_until(const TimePoint &abs_time)
0170    {  return this->timed_lock_sharable(abs_time);  }
0171 
0172    //!Same as `timed_lock_sharable`, but this function is modeled after the
0173    //!standard library interface.
0174    template<class Duration>  bool try_lock_shared_for(const Duration &dur)
0175    {  return this->timed_lock_sharable(ipcdetail::duration_to_ustime(dur)); }
0176 
0177    //!Precondition: The thread must have sharable ownership of the mutex.
0178    //!Effects: The calling thread releases the sharable ownership of the mutex.
0179    //!Throws: An exception derived from interprocess_exception on error.
0180    void unlock_sharable();
0181 
0182    //!Same as `unlock_sharable` but with a std-compatible interface
0183    //! 
0184    void unlock_shared()
0185    {  this->unlock_sharable();  }
0186 
0187    //Upgradable locking
0188 
0189    //!Requires: The calling thread does not own the mutex.
0190    //!
0191    //!Effects: The calling thread tries to obtain upgradable ownership of the mutex,
0192    //!   and if another thread has exclusive or upgradable ownership of the mutex,
0193    //!   waits until it can obtain the ownership.
0194    //!Throws: interprocess_exception on error.
0195    //!
0196    //!Note: A program may deadlock if the thread that has ownership calls 
0197    //!   this function. If the implementation can detect the deadlock,
0198    //!   an exception could be thrown.
0199    void lock_upgradable();
0200 
0201    //!Requires: The calling thread does not own the mutex.
0202    //!
0203    //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
0204    //!   without waiting. If no other thread has exclusive or upgradable ownership
0205    //!   of the mutex this succeeds.
0206    //!Returns: If it can acquire upgradable ownership immediately returns true.
0207    //!   If it has to wait, returns false.
0208    //!Throws: interprocess_exception on error.
0209    //!
0210    //!Note: A program may deadlock if the thread that has ownership calls 
0211    //!   this function. If the implementation can detect the deadlock,
0212    //!   an exception could be thrown.
0213    bool try_lock_upgradable();
0214 
0215    //!Requires: The calling thread does not own the mutex.
0216    //!
0217    //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
0218    //!   waiting if necessary until no other thread has exclusive or upgradable
0219    //!   ownership of the mutex or abs_time is reached.
0220    //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
0221    //!Throws: interprocess_exception on error.
0222    //!
0223    //!Note: A program may deadlock if the thread that has ownership calls 
0224    //!   this function. If the implementation can detect the deadlock,
0225    //!   an exception could be thrown.
0226    template<class TimePoint>
0227    bool timed_lock_upgradable(const TimePoint &abs_time);
0228 
0229    //!Precondition: The thread must have upgradable ownership of the mutex.
0230    //!Effects: The calling thread releases the upgradable ownership of the mutex.
0231    //!Throws: An exception derived from interprocess_exception on error.
0232    void unlock_upgradable();
0233 
0234    //Demotions
0235 
0236    //!Precondition: The thread must have exclusive ownership of the mutex.
0237    //!Effects: The thread atomically releases exclusive ownership and acquires
0238    //!   upgradable ownership. This operation is non-blocking.
0239    //!Throws: An exception derived from interprocess_exception on error.
0240    void unlock_and_lock_upgradable();
0241 
0242    //!Precondition: The thread must have exclusive ownership of the mutex.
0243    //!Effects: The thread atomically releases exclusive ownership and acquires
0244    //!   sharable ownership. This operation is non-blocking.
0245    //!Throws: An exception derived from interprocess_exception on error.
0246    void unlock_and_lock_sharable();
0247 
0248    //!Precondition: The thread must have upgradable ownership of the mutex.
0249    //!Effects: The thread atomically releases upgradable ownership and acquires
0250    //!   sharable ownership. This operation is non-blocking.
0251    //!Throws: An exception derived from interprocess_exception on error.
0252    void unlock_upgradable_and_lock_sharable();
0253 
0254    //Promotions
0255 
0256    //!Precondition: The thread must have upgradable ownership of the mutex.
0257    //!Effects: The thread atomically releases upgradable ownership and acquires
0258    //!   exclusive ownership. This operation will block until all threads with
0259    //!   sharable ownership release their sharable lock.
0260    //!Throws: An exception derived from interprocess_exception on error.
0261    void unlock_upgradable_and_lock();
0262 
0263    //!Precondition: The thread must have upgradable ownership of the mutex.
0264    //!Effects: The thread atomically releases upgradable ownership and tries to
0265    //!   acquire exclusive ownership. This operation will fail if there are threads
0266    //!   with sharable ownership, but it will maintain upgradable ownership.
0267    //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
0268    //!Throws: An exception derived from interprocess_exception on error.
0269    bool try_unlock_upgradable_and_lock();
0270 
0271    //!Precondition: The thread must have upgradable ownership of the mutex.
0272    //!Effects: The thread atomically releases upgradable ownership and tries to acquire
0273    //!   exclusive ownership, waiting if necessary until abs_time. This operation will
0274    //!   fail if there are threads with sharable ownership or timeout reaches, but it
0275    //!   will maintain upgradable ownership.
0276    //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
0277    //!Throws: An exception derived from interprocess_exception on error. */
0278    template<class TimePoint>
0279    bool timed_unlock_upgradable_and_lock(const TimePoint &abs_time);
0280 
0281    //!Precondition: The thread must have sharable ownership of the mutex.
0282    //!Effects: The thread atomically releases sharable ownership and tries to acquire
0283    //!   exclusive ownership. This operation will fail if there are threads with sharable
0284    //!   or upgradable ownership, but it will maintain sharable ownership.
0285    //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
0286    //!Throws: An exception derived from interprocess_exception on error.
0287    bool try_unlock_sharable_and_lock();
0288 
0289    //!Precondition: The thread must have sharable ownership of the mutex.
0290    //!Effects: The thread atomically releases sharable ownership and tries to acquire
0291    //!   upgradable ownership. This operation will fail if there are threads with sharable
0292    //!   or upgradable ownership, but it will maintain sharable ownership.
0293    //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
0294    //!Throws: An exception derived from interprocess_exception on error.
0295    bool try_unlock_sharable_and_lock_upgradable();
0296 
0297    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
0298    private:
0299    typedef scoped_lock<interprocess_mutex> scoped_lock_t;
0300 
0301    //Pack all the control data in a word to be able
0302    //to use atomic instructions in the future
0303    struct control_word_t
0304    {
0305       unsigned exclusive_in         : 1;
0306       unsigned upgradable_in        : 1;
0307       unsigned num_upr_shar         : sizeof(unsigned)*CHAR_BIT-2;
0308    }                       m_ctrl;
0309 
0310    interprocess_mutex      m_mut;
0311    interprocess_condition  m_first_gate;
0312    interprocess_condition  m_second_gate;
0313 
0314    private:
0315    //Rollback structures for exceptions or failure return values
0316    struct exclusive_rollback
0317    {
0318       exclusive_rollback(control_word_t         &ctrl
0319                         ,interprocess_condition &first_gate)
0320          :  mp_ctrl(&ctrl), m_first_gate(first_gate)
0321       {}
0322 
0323       void release()
0324       {  mp_ctrl = 0;   }
0325 
0326       ~exclusive_rollback()
0327       {
0328          if(mp_ctrl){
0329             mp_ctrl->exclusive_in = 0;
0330             m_first_gate.notify_all();
0331          }
0332       }
0333       control_word_t          *mp_ctrl;
0334       interprocess_condition  &m_first_gate;
0335    };
0336 
0337    struct upgradable_to_exclusive_rollback
0338    {
0339       upgradable_to_exclusive_rollback(control_word_t         &ctrl)
0340          :  mp_ctrl(&ctrl)
0341       {}
0342 
0343       void release()
0344       {  mp_ctrl = 0;   }
0345 
0346       ~upgradable_to_exclusive_rollback()
0347       {
0348          if(mp_ctrl){
0349             //Recover upgradable lock
0350             mp_ctrl->upgradable_in = 1;
0351             ++mp_ctrl->num_upr_shar;
0352             //Execute the second half of exclusive locking
0353             mp_ctrl->exclusive_in = 0;
0354          }
0355       }
0356       control_word_t          *mp_ctrl;
0357    };
0358 
0359    template<int Dummy>
0360    struct base_constants_t
0361    {
0362       static const unsigned max_readers
0363          = ~(unsigned(3) << (sizeof(unsigned)*CHAR_BIT-2));
0364    };
0365    typedef base_constants_t<0> constants;
0366    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
0367 };
0368 
0369 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
0370 
0371 template <int Dummy>
0372 const unsigned interprocess_upgradable_mutex::base_constants_t<Dummy>::max_readers;
0373 
0374 inline interprocess_upgradable_mutex::interprocess_upgradable_mutex()
0375 {
0376    this->m_ctrl.exclusive_in  = 0;
0377    this->m_ctrl.upgradable_in = 0;
0378    this->m_ctrl.num_upr_shar   = 0;
0379 }
0380 
0381 inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex()
0382 {}
0383 
0384 inline void interprocess_upgradable_mutex::lock()
0385 {
0386    scoped_lock_t lck(m_mut);
0387 
0388    //The exclusive lock must block in the first gate
0389    //if an exclusive or upgradable lock has been acquired
0390    while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
0391       this->m_first_gate.wait(lck);
0392    }
0393 
0394    //Mark that exclusive lock has been acquired
0395    this->m_ctrl.exclusive_in = 1;
0396 
0397    //Prepare rollback
0398    exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
0399 
0400    //Now wait until all readers are gone
0401    while (this->m_ctrl.num_upr_shar){
0402       this->m_second_gate.wait(lck);
0403    }
0404    rollback.release();
0405 }
0406 
0407 inline bool interprocess_upgradable_mutex::try_lock()
0408 {
0409    scoped_lock_t lck(m_mut, try_to_lock);
0410 
0411    //If we can't lock or any has there is any exclusive, upgradable
0412    //or sharable mark return false;
0413    if(!lck.owns()
0414       || this->m_ctrl.exclusive_in
0415       || this->m_ctrl.num_upr_shar){
0416       return false;
0417    }
0418    this->m_ctrl.exclusive_in = 1;
0419    return true;
0420 }
0421 
0422 template<class TimePoint>
0423 bool interprocess_upgradable_mutex::timed_lock(const TimePoint &abs_time)
0424 {
0425    //Mutexes and condvars handle just fine infinite abs_times
0426    //so avoid checking it here
0427    scoped_lock_t lck(m_mut, abs_time);
0428    if(!lck.owns())   return false;
0429 
0430    //The exclusive lock must block in the first gate
0431    //if an exclusive or upgradable lock has been acquired
0432    while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
0433       if(!this->m_first_gate.timed_wait(lck, abs_time)){
0434          if(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
0435             return false;
0436          }
0437          break;
0438       }
0439    }
0440 
0441    //Mark that exclusive lock has been acquired
0442    this->m_ctrl.exclusive_in = 1;
0443 
0444    //Prepare rollback
0445    exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
0446 
0447    //Now wait until all readers are gone
0448    while (this->m_ctrl.num_upr_shar){
0449       if(!this->m_second_gate.timed_wait(lck, abs_time)){
0450          if(this->m_ctrl.num_upr_shar){
0451             return false;
0452          }
0453          break;
0454       }
0455    }
0456    rollback.release();
0457    return true;
0458 }
0459 
0460 inline void interprocess_upgradable_mutex::unlock()
0461 {
0462    scoped_lock_t lck(m_mut);
0463    this->m_ctrl.exclusive_in = 0;
0464    this->m_first_gate.notify_all();
0465 }
0466 
0467 //Upgradable locking
0468 
0469 inline void interprocess_upgradable_mutex::lock_upgradable()
0470 {
0471    scoped_lock_t lck(m_mut);
0472 
0473    //The upgradable lock must block in the first gate
0474    //if an exclusive or upgradable lock has been acquired
0475    //or there are too many sharable locks
0476    while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in
0477          || this->m_ctrl.num_upr_shar == constants::max_readers){
0478       this->m_first_gate.wait(lck);
0479    }
0480 
0481    //Mark that upgradable lock has been acquired
0482    //And add upgradable to the sharable count
0483    this->m_ctrl.upgradable_in = 1;
0484    ++this->m_ctrl.num_upr_shar;
0485 }
0486 
0487 inline bool interprocess_upgradable_mutex::try_lock_upgradable()
0488 {
0489    scoped_lock_t lck(m_mut, try_to_lock);
0490 
0491    //The upgradable lock must fail
0492    //if an exclusive or upgradable lock has been acquired
0493    //or there are too many sharable locks
0494    if(!lck.owns()
0495       || this->m_ctrl.exclusive_in
0496       || this->m_ctrl.upgradable_in
0497       || this->m_ctrl.num_upr_shar == constants::max_readers){
0498       return false;
0499    }
0500 
0501    //Mark that upgradable lock has been acquired
0502    //And add upgradable to the sharable count
0503    this->m_ctrl.upgradable_in = 1;
0504    ++this->m_ctrl.num_upr_shar;
0505    return true;
0506 }
0507 
0508 template<class TimePoint>
0509 bool interprocess_upgradable_mutex::timed_lock_upgradable(const TimePoint &abs_time)
0510 {
0511    //Mutexes and condvars handle just fine infinite abs_times
0512    //so avoid checking it here
0513    scoped_lock_t lck(m_mut, abs_time);
0514    if(!lck.owns())   return false;
0515 
0516    //The upgradable lock must block in the first gate
0517    //if an exclusive or upgradable lock has been acquired
0518    //or there are too many sharable locks
0519    while(this->m_ctrl.exclusive_in
0520          || this->m_ctrl.upgradable_in
0521          || this->m_ctrl.num_upr_shar == constants::max_readers){
0522       if(!this->m_first_gate.timed_wait(lck, abs_time)){
0523          if((this->m_ctrl.exclusive_in
0524              || this->m_ctrl.upgradable_in
0525              || this->m_ctrl.num_upr_shar == constants::max_readers)){
0526             return false;
0527          }
0528          break;
0529       }
0530    }
0531 
0532    //Mark that upgradable lock has been acquired
0533    //And add upgradable to the sharable count
0534    this->m_ctrl.upgradable_in = 1;
0535    ++this->m_ctrl.num_upr_shar;
0536    return true;
0537 }
0538 
0539 inline void interprocess_upgradable_mutex::unlock_upgradable()
0540 {
0541    scoped_lock_t lck(m_mut);
0542    //Mark that upgradable lock has been acquired
0543    //And add upgradable to the sharable count
0544    this->m_ctrl.upgradable_in = 0;
0545    --this->m_ctrl.num_upr_shar;
0546    this->m_first_gate.notify_all();
0547 }
0548 
0549 //Sharable locking
0550 
0551 inline void interprocess_upgradable_mutex::lock_sharable()
0552 {
0553    scoped_lock_t lck(m_mut);
0554 
0555    //The sharable lock must block in the first gate
0556    //if an exclusive lock has been acquired
0557    //or there are too many sharable locks
0558    while(this->m_ctrl.exclusive_in
0559         || this->m_ctrl.num_upr_shar == constants::max_readers){
0560       this->m_first_gate.wait(lck);
0561    }
0562 
0563    //Increment sharable count
0564    ++this->m_ctrl.num_upr_shar;
0565 }
0566 
0567 inline bool interprocess_upgradable_mutex::try_lock_sharable()
0568 {
0569    scoped_lock_t lck(m_mut, try_to_lock);
0570 
0571    //The sharable lock must fail
0572    //if an exclusive lock has been acquired
0573    //or there are too many sharable locks
0574    if(!lck.owns()
0575       || this->m_ctrl.exclusive_in
0576       || this->m_ctrl.num_upr_shar == constants::max_readers){
0577       return false;
0578    }
0579 
0580    //Increment sharable count
0581    ++this->m_ctrl.num_upr_shar;
0582    return true;
0583 }
0584 
0585 template<class TimePoint>
0586 inline bool interprocess_upgradable_mutex::timed_lock_sharable(const TimePoint &abs_time)
0587 {
0588    //Mutexes and condvars handle just fine infinite abs_times
0589    //so avoid checking it here
0590    scoped_lock_t lck(m_mut, abs_time);
0591    if(!lck.owns())   return false;
0592 
0593    //The sharable lock must block in the first gate
0594    //if an exclusive lock has been acquired
0595    //or there are too many sharable locks
0596    while (this->m_ctrl.exclusive_in
0597          || this->m_ctrl.num_upr_shar == constants::max_readers){
0598       if(!this->m_first_gate.timed_wait(lck, abs_time)){
0599          if(this->m_ctrl.exclusive_in
0600             || this->m_ctrl.num_upr_shar == constants::max_readers){
0601             return false;
0602          }
0603          break;
0604       }
0605    }
0606 
0607    //Increment sharable count
0608    ++this->m_ctrl.num_upr_shar;
0609    return true;
0610 }
0611 
0612 inline void interprocess_upgradable_mutex::unlock_sharable()
0613 {
0614    scoped_lock_t lck(m_mut);
0615    //Decrement sharable count
0616    --this->m_ctrl.num_upr_shar;
0617    if (this->m_ctrl.num_upr_shar == 0){
0618       this->m_second_gate.notify_one();
0619    }
0620    //Check if there are blocked sharables because of
0621    //there were too many sharables
0622    else if(this->m_ctrl.num_upr_shar == (constants::max_readers-1)){
0623       this->m_first_gate.notify_all();
0624    }
0625 }
0626 
0627 //Downgrading
0628 
0629 inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable()
0630 {
0631    scoped_lock_t lck(m_mut);
0632    //Unmark it as exclusive
0633    this->m_ctrl.exclusive_in     = 0;
0634    //Mark it as upgradable
0635    this->m_ctrl.upgradable_in    = 1;
0636    //The sharable count should be 0 so increment it
0637    this->m_ctrl.num_upr_shar   = 1;
0638    //Notify readers that they can enter
0639    m_first_gate.notify_all();
0640 }
0641 
0642 inline void interprocess_upgradable_mutex::unlock_and_lock_sharable()
0643 {
0644    scoped_lock_t lck(m_mut);
0645    //Unmark it as exclusive
0646    this->m_ctrl.exclusive_in   = 0;
0647    //The sharable count should be 0 so increment it
0648    this->m_ctrl.num_upr_shar   = 1;
0649    //Notify readers that they can enter
0650    m_first_gate.notify_all();
0651 }
0652 
0653 inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable()
0654 {
0655    scoped_lock_t lck(m_mut);
0656    //Unmark it as upgradable (we don't have to decrement count)
0657    this->m_ctrl.upgradable_in    = 0;
0658    //Notify readers/upgradable that they can enter
0659    m_first_gate.notify_all();
0660 }
0661 
0662 //Upgrading
0663 
0664 inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock()
0665 {
0666    scoped_lock_t lck(m_mut);
0667    //Simulate unlock_upgradable() without
0668    //notifying sharables.
0669    this->m_ctrl.upgradable_in = 0;
0670    --this->m_ctrl.num_upr_shar;
0671    //Execute the second half of exclusive locking
0672    this->m_ctrl.exclusive_in = 1;
0673 
0674    //Prepare rollback
0675    upgradable_to_exclusive_rollback rollback(m_ctrl);
0676 
0677    while (this->m_ctrl.num_upr_shar){
0678       this->m_second_gate.wait(lck);
0679    }
0680    rollback.release();
0681 }
0682 
0683 inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock()
0684 {
0685    scoped_lock_t lck(m_mut, try_to_lock);
0686    //Check if there are no readers
0687    if(!lck.owns()
0688       || this->m_ctrl.num_upr_shar != 1){
0689       return false;
0690    }
0691    //Now unlock upgradable and mark exclusive
0692    this->m_ctrl.upgradable_in = 0;
0693    --this->m_ctrl.num_upr_shar;
0694    this->m_ctrl.exclusive_in = 1;
0695    return true;
0696 }
0697 
0698 template<class TimePoint>
0699 bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock(const TimePoint &abs_time)
0700 {
0701    //Mutexes and condvars handle just fine infinite abs_times
0702    //so avoid checking it here
0703    scoped_lock_t lck(m_mut, abs_time);
0704    if(!lck.owns())   return false;
0705 
0706    //Simulate unlock_upgradable() without
0707    //notifying sharables.
0708    this->m_ctrl.upgradable_in = 0;
0709    --this->m_ctrl.num_upr_shar;
0710    //Execute the second half of exclusive locking
0711    this->m_ctrl.exclusive_in = 1;
0712 
0713    //Prepare rollback
0714    upgradable_to_exclusive_rollback rollback(m_ctrl);
0715 
0716    while (this->m_ctrl.num_upr_shar){
0717       if(!this->m_second_gate.timed_wait(lck, abs_time)){
0718          if(this->m_ctrl.num_upr_shar){
0719             return false;
0720          }
0721          break;
0722       }
0723    }
0724    rollback.release();
0725    return true;
0726 }
0727 
0728 inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock()
0729 {
0730    scoped_lock_t lck(m_mut, try_to_lock);
0731 
0732    //If we can't lock or any has there is any exclusive, upgradable
0733    //or sharable mark return false;
0734    if(!lck.owns()
0735       || this->m_ctrl.exclusive_in
0736       || this->m_ctrl.upgradable_in
0737       || this->m_ctrl.num_upr_shar != 1){
0738       return false;
0739    }
0740    this->m_ctrl.exclusive_in = 1;
0741    this->m_ctrl.num_upr_shar = 0;
0742    return true;
0743 }
0744 
0745 inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
0746 {
0747    scoped_lock_t lck(m_mut, try_to_lock);
0748 
0749    //The upgradable lock must fail
0750    //if an exclusive or upgradable lock has been acquired
0751    if(!lck.owns()
0752       || this->m_ctrl.exclusive_in
0753       || this->m_ctrl.upgradable_in){
0754       return false;
0755    }
0756 
0757    //Mark that upgradable lock has been acquired
0758    this->m_ctrl.upgradable_in = 1;
0759    return true;
0760 }
0761 
0762 #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
0763 
0764 }  //namespace interprocess {
0765 }  //namespace boost {
0766 
0767 
0768 #include <boost/interprocess/detail/config_end.hpp>
0769 
0770 #endif   //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP