Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 08:13:57

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