Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-07 08:07:50

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