Chris@16: //////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Code based on Howard Hinnant's upgrade_mutex class Chris@16: // Chris@16: // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/interprocess for documentation. Chris@16: // Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #ifndef BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP Chris@16: #define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP Chris@16: Chris@101: #ifndef BOOST_CONFIG_HPP Chris@101: # include Chris@101: #endif Chris@101: # Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: Chris@16: //!\file Chris@16: //!Describes interprocess_upgradable_mutex class Chris@16: Chris@16: namespace boost { Chris@16: namespace interprocess { Chris@16: Chris@16: //!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be Chris@16: //!shared between processes. Allows timed lock tries Chris@16: class interprocess_upgradable_mutex Chris@16: { Chris@16: //Non-copyable Chris@16: interprocess_upgradable_mutex(const interprocess_upgradable_mutex &); Chris@16: interprocess_upgradable_mutex &operator=(const interprocess_upgradable_mutex &); Chris@16: Chris@16: friend class interprocess_condition; Chris@16: public: Chris@16: Chris@16: //!Constructs the upgradable lock. Chris@16: //!Throws interprocess_exception on error. Chris@16: interprocess_upgradable_mutex(); Chris@16: Chris@16: //!Destroys the upgradable lock. Chris@16: //!Does not throw. Chris@16: ~interprocess_upgradable_mutex(); Chris@16: Chris@16: //Exclusive locking Chris@16: Chris@16: //!Effects: The calling thread tries to obtain exclusive ownership of the mutex, Chris@16: //! and if another thread has exclusive, sharable or upgradable ownership of Chris@16: //! the mutex, it waits until it can obtain the ownership. Chris@16: //!Throws: interprocess_exception on error. Chris@16: void lock(); Chris@16: Chris@16: //!Effects: The calling thread tries to acquire exclusive ownership of the mutex Chris@16: //! without waiting. If no other thread has exclusive, sharable or upgradable Chris@16: //! ownership of the mutex this succeeds. Chris@16: //!Returns: If it can acquire exclusive ownership immediately returns true. Chris@16: //! If it has to wait, returns false. Chris@16: //!Throws: interprocess_exception on error. Chris@16: bool try_lock(); Chris@16: Chris@16: //!Effects: The calling thread tries to acquire exclusive ownership of the mutex Chris@16: //! waiting if necessary until no other thread has exclusive, sharable or Chris@16: //! upgradable ownership of the mutex or abs_time is reached. Chris@16: //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. Chris@16: //!Throws: interprocess_exception on error. Chris@16: bool timed_lock(const boost::posix_time::ptime &abs_time); Chris@16: Chris@16: //!Precondition: The thread must have exclusive ownership of the mutex. Chris@16: //!Effects: The calling thread releases the exclusive ownership of the mutex. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: void unlock(); Chris@16: Chris@16: //Sharable locking Chris@16: Chris@16: //!Effects: The calling thread tries to obtain sharable ownership of the mutex, Chris@16: //! and if another thread has exclusive ownership of the mutex, Chris@16: //! waits until it can obtain the ownership. Chris@16: //!Throws: interprocess_exception on error. Chris@16: void lock_sharable(); Chris@16: Chris@16: //!Effects: The calling thread tries to acquire sharable ownership of the mutex Chris@16: //! without waiting. If no other thread has exclusive ownership Chris@16: //! of the mutex this succeeds. Chris@16: //!Returns: If it can acquire sharable ownership immediately returns true. If it Chris@16: //! has to wait, returns false. Chris@16: //!Throws: interprocess_exception on error. Chris@16: bool try_lock_sharable(); Chris@16: Chris@16: //!Effects: The calling thread tries to acquire sharable ownership of the mutex Chris@16: //! waiting if necessary until no other thread has exclusive Chris@16: //! ownership of the mutex or abs_time is reached. Chris@16: //!Returns: If acquires sharable ownership, returns true. Otherwise returns false. Chris@16: //!Throws: interprocess_exception on error. Chris@16: bool timed_lock_sharable(const boost::posix_time::ptime &abs_time); Chris@16: Chris@16: //!Precondition: The thread must have sharable ownership of the mutex. Chris@16: //!Effects: The calling thread releases the sharable ownership of the mutex. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: void unlock_sharable(); Chris@16: Chris@16: //Upgradable locking Chris@16: Chris@16: //!Effects: The calling thread tries to obtain upgradable ownership of the mutex, Chris@16: //! and if another thread has exclusive or upgradable ownership of the mutex, Chris@16: //! waits until it can obtain the ownership. Chris@16: //!Throws: interprocess_exception on error. Chris@16: void lock_upgradable(); Chris@16: Chris@16: //!Effects: The calling thread tries to acquire upgradable ownership of the mutex Chris@16: //! without waiting. If no other thread has exclusive or upgradable ownership Chris@16: //! of the mutex this succeeds. Chris@16: //!Returns: If it can acquire upgradable ownership immediately returns true. Chris@16: //! If it has to wait, returns false. Chris@16: //!Throws: interprocess_exception on error. Chris@16: bool try_lock_upgradable(); Chris@16: Chris@16: //!Effects: The calling thread tries to acquire upgradable ownership of the mutex Chris@16: //! waiting if necessary until no other thread has exclusive or upgradable Chris@16: //! ownership of the mutex or abs_time is reached. Chris@16: //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false. Chris@16: //!Throws: interprocess_exception on error. Chris@16: bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time); Chris@16: Chris@16: //!Precondition: The thread must have upgradable ownership of the mutex. Chris@16: //!Effects: The calling thread releases the upgradable ownership of the mutex. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: void unlock_upgradable(); Chris@16: Chris@16: //Demotions Chris@16: Chris@16: //!Precondition: The thread must have exclusive ownership of the mutex. Chris@16: //!Effects: The thread atomically releases exclusive ownership and acquires Chris@16: //! upgradable ownership. This operation is non-blocking. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: void unlock_and_lock_upgradable(); Chris@16: Chris@16: //!Precondition: The thread must have exclusive ownership of the mutex. Chris@16: //!Effects: The thread atomically releases exclusive ownership and acquires Chris@16: //! sharable ownership. This operation is non-blocking. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: void unlock_and_lock_sharable(); Chris@16: Chris@16: //!Precondition: The thread must have upgradable ownership of the mutex. Chris@16: //!Effects: The thread atomically releases upgradable ownership and acquires Chris@16: //! sharable ownership. This operation is non-blocking. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: void unlock_upgradable_and_lock_sharable(); Chris@16: Chris@16: //Promotions Chris@16: Chris@16: //!Precondition: The thread must have upgradable ownership of the mutex. Chris@16: //!Effects: The thread atomically releases upgradable ownership and acquires Chris@16: //! exclusive ownership. This operation will block until all threads with Chris@16: //! sharable ownership release their sharable lock. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: void unlock_upgradable_and_lock(); Chris@16: Chris@16: //!Precondition: The thread must have upgradable ownership of the mutex. Chris@16: //!Effects: The thread atomically releases upgradable ownership and tries to Chris@16: //! acquire exclusive ownership. This operation will fail if there are threads Chris@16: //! with sharable ownership, but it will maintain upgradable ownership. Chris@16: //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: bool try_unlock_upgradable_and_lock(); Chris@16: Chris@16: //!Precondition: The thread must have upgradable ownership of the mutex. Chris@16: //!Effects: The thread atomically releases upgradable ownership and tries to acquire Chris@16: //! exclusive ownership, waiting if necessary until abs_time. This operation will Chris@16: //! fail if there are threads with sharable ownership or timeout reaches, but it Chris@16: //! will maintain upgradable ownership. Chris@16: //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. Chris@16: //!Throws: An exception derived from interprocess_exception on error. */ Chris@16: bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time); Chris@16: Chris@16: //!Precondition: The thread must have sharable ownership of the mutex. Chris@16: //!Effects: The thread atomically releases sharable ownership and tries to acquire Chris@16: //! exclusive ownership. This operation will fail if there are threads with sharable Chris@16: //! or upgradable ownership, but it will maintain sharable ownership. Chris@16: //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: bool try_unlock_sharable_and_lock(); Chris@16: Chris@16: //!Precondition: The thread must have sharable ownership of the mutex. Chris@16: //!Effects: The thread atomically releases sharable ownership and tries to acquire Chris@16: //! upgradable ownership. This operation will fail if there are threads with sharable Chris@16: //! or upgradable ownership, but it will maintain sharable ownership. Chris@16: //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false. Chris@16: //!Throws: An exception derived from interprocess_exception on error. Chris@16: bool try_unlock_sharable_and_lock_upgradable(); Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: private: Chris@16: typedef scoped_lock scoped_lock_t; Chris@16: Chris@16: //Pack all the control data in a word to be able Chris@16: //to use atomic instructions in the future Chris@16: struct control_word_t Chris@16: { Chris@16: unsigned exclusive_in : 1; Chris@16: unsigned upgradable_in : 1; Chris@16: unsigned num_upr_shar : sizeof(unsigned)*CHAR_BIT-2; Chris@16: } m_ctrl; Chris@16: Chris@16: interprocess_mutex m_mut; Chris@16: interprocess_condition m_first_gate; Chris@16: interprocess_condition m_second_gate; Chris@16: Chris@16: private: Chris@16: //Rollback structures for exceptions or failure return values Chris@16: struct exclusive_rollback Chris@16: { Chris@16: exclusive_rollback(control_word_t &ctrl Chris@16: ,interprocess_condition &first_gate) Chris@16: : mp_ctrl(&ctrl), m_first_gate(first_gate) Chris@16: {} Chris@16: Chris@16: void release() Chris@16: { mp_ctrl = 0; } Chris@16: Chris@16: ~exclusive_rollback() Chris@16: { Chris@16: if(mp_ctrl){ Chris@16: mp_ctrl->exclusive_in = 0; Chris@16: m_first_gate.notify_all(); Chris@16: } Chris@16: } Chris@16: control_word_t *mp_ctrl; Chris@16: interprocess_condition &m_first_gate; Chris@16: }; Chris@16: Chris@16: struct upgradable_to_exclusive_rollback Chris@16: { Chris@16: upgradable_to_exclusive_rollback(control_word_t &ctrl) Chris@16: : mp_ctrl(&ctrl) Chris@16: {} Chris@16: Chris@16: void release() Chris@16: { mp_ctrl = 0; } Chris@16: Chris@16: ~upgradable_to_exclusive_rollback() Chris@16: { Chris@16: if(mp_ctrl){ Chris@16: //Recover upgradable lock Chris@16: mp_ctrl->upgradable_in = 1; Chris@16: ++mp_ctrl->num_upr_shar; Chris@16: //Execute the second half of exclusive locking Chris@16: mp_ctrl->exclusive_in = 0; Chris@16: } Chris@16: } Chris@16: control_word_t *mp_ctrl; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct base_constants_t Chris@16: { Chris@16: static const unsigned max_readers Chris@16: = ~(unsigned(3) << (sizeof(unsigned)*CHAR_BIT-2)); Chris@16: }; Chris@16: typedef base_constants_t<0> constants; Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: }; Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: Chris@16: template Chris@16: const unsigned interprocess_upgradable_mutex::base_constants_t::max_readers; Chris@16: Chris@16: inline interprocess_upgradable_mutex::interprocess_upgradable_mutex() Chris@16: { Chris@16: this->m_ctrl.exclusive_in = 0; Chris@16: this->m_ctrl.upgradable_in = 0; Chris@16: this->m_ctrl.num_upr_shar = 0; Chris@16: } Chris@16: Chris@16: inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex() Chris@16: {} Chris@16: Chris@16: inline void interprocess_upgradable_mutex::lock() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: Chris@16: //The exclusive lock must block in the first gate Chris@16: //if an exclusive or upgradable lock has been acquired Chris@16: while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){ Chris@16: this->m_first_gate.wait(lck); Chris@16: } Chris@16: Chris@16: //Mark that exclusive lock has been acquired Chris@16: this->m_ctrl.exclusive_in = 1; Chris@16: Chris@16: //Prepare rollback Chris@16: exclusive_rollback rollback(this->m_ctrl, this->m_first_gate); Chris@16: Chris@16: //Now wait until all readers are gone Chris@16: while (this->m_ctrl.num_upr_shar){ Chris@16: this->m_second_gate.wait(lck); Chris@16: } Chris@16: rollback.release(); Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::try_lock() Chris@16: { Chris@16: scoped_lock_t lck(m_mut, try_to_lock); Chris@16: Chris@16: //If we can't lock or any has there is any exclusive, upgradable Chris@16: //or sharable mark return false; Chris@16: if(!lck.owns() Chris@16: || this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.num_upr_shar){ Chris@16: return false; Chris@16: } Chris@16: this->m_ctrl.exclusive_in = 1; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::timed_lock Chris@16: (const boost::posix_time::ptime &abs_time) Chris@16: { Chris@101: //Mutexes and condvars handle just fine infinite abs_times Chris@101: //so avoid checking it here Chris@16: scoped_lock_t lck(m_mut, abs_time); Chris@16: if(!lck.owns()) return false; Chris@16: Chris@16: //The exclusive lock must block in the first gate Chris@16: //if an exclusive or upgradable lock has been acquired Chris@16: while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){ Chris@16: if(!this->m_first_gate.timed_wait(lck, abs_time)){ Chris@16: if(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){ Chris@16: return false; Chris@16: } Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: //Mark that exclusive lock has been acquired Chris@16: this->m_ctrl.exclusive_in = 1; Chris@16: Chris@16: //Prepare rollback Chris@16: exclusive_rollback rollback(this->m_ctrl, this->m_first_gate); Chris@16: Chris@16: //Now wait until all readers are gone Chris@16: while (this->m_ctrl.num_upr_shar){ Chris@16: if(!this->m_second_gate.timed_wait(lck, abs_time)){ Chris@16: if(this->m_ctrl.num_upr_shar){ Chris@16: return false; Chris@16: } Chris@16: break; Chris@16: } Chris@16: } Chris@16: rollback.release(); Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline void interprocess_upgradable_mutex::unlock() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: this->m_ctrl.exclusive_in = 0; Chris@16: this->m_first_gate.notify_all(); Chris@16: } Chris@16: Chris@16: //Upgradable locking Chris@16: Chris@16: inline void interprocess_upgradable_mutex::lock_upgradable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: Chris@16: //The upgradable lock must block in the first gate Chris@16: //if an exclusive or upgradable lock has been acquired Chris@16: //or there are too many sharable locks Chris@16: while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in Chris@16: || this->m_ctrl.num_upr_shar == constants::max_readers){ Chris@16: this->m_first_gate.wait(lck); Chris@16: } Chris@16: Chris@16: //Mark that upgradable lock has been acquired Chris@16: //And add upgradable to the sharable count Chris@16: this->m_ctrl.upgradable_in = 1; Chris@16: ++this->m_ctrl.num_upr_shar; Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::try_lock_upgradable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut, try_to_lock); Chris@16: Chris@16: //The upgradable lock must fail Chris@16: //if an exclusive or upgradable lock has been acquired Chris@16: //or there are too many sharable locks Chris@16: if(!lck.owns() Chris@16: || this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.upgradable_in Chris@16: || this->m_ctrl.num_upr_shar == constants::max_readers){ Chris@16: return false; Chris@16: } Chris@16: Chris@16: //Mark that upgradable lock has been acquired Chris@16: //And add upgradable to the sharable count Chris@16: this->m_ctrl.upgradable_in = 1; Chris@16: ++this->m_ctrl.num_upr_shar; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::timed_lock_upgradable Chris@16: (const boost::posix_time::ptime &abs_time) Chris@16: { Chris@101: //Mutexes and condvars handle just fine infinite abs_times Chris@101: //so avoid checking it here Chris@16: scoped_lock_t lck(m_mut, abs_time); Chris@16: if(!lck.owns()) return false; Chris@16: Chris@16: //The upgradable lock must block in the first gate Chris@16: //if an exclusive or upgradable lock has been acquired Chris@16: //or there are too many sharable locks Chris@16: while(this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.upgradable_in Chris@16: || this->m_ctrl.num_upr_shar == constants::max_readers){ Chris@16: if(!this->m_first_gate.timed_wait(lck, abs_time)){ Chris@16: if((this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.upgradable_in Chris@16: || this->m_ctrl.num_upr_shar == constants::max_readers)){ Chris@16: return false; Chris@16: } Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: //Mark that upgradable lock has been acquired Chris@16: //And add upgradable to the sharable count Chris@16: this->m_ctrl.upgradable_in = 1; Chris@16: ++this->m_ctrl.num_upr_shar; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline void interprocess_upgradable_mutex::unlock_upgradable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: //Mark that upgradable lock has been acquired Chris@16: //And add upgradable to the sharable count Chris@16: this->m_ctrl.upgradable_in = 0; Chris@16: --this->m_ctrl.num_upr_shar; Chris@16: this->m_first_gate.notify_all(); Chris@16: } Chris@16: Chris@16: //Sharable locking Chris@16: Chris@16: inline void interprocess_upgradable_mutex::lock_sharable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: Chris@16: //The sharable lock must block in the first gate Chris@16: //if an exclusive lock has been acquired Chris@16: //or there are too many sharable locks Chris@16: while(this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.num_upr_shar == constants::max_readers){ Chris@16: this->m_first_gate.wait(lck); Chris@16: } Chris@16: Chris@16: //Increment sharable count Chris@16: ++this->m_ctrl.num_upr_shar; Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::try_lock_sharable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut, try_to_lock); Chris@16: Chris@16: //The sharable lock must fail Chris@16: //if an exclusive lock has been acquired Chris@16: //or there are too many sharable locks Chris@16: if(!lck.owns() Chris@16: || this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.num_upr_shar == constants::max_readers){ Chris@16: return false; Chris@16: } Chris@16: Chris@16: //Increment sharable count Chris@16: ++this->m_ctrl.num_upr_shar; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::timed_lock_sharable Chris@16: (const boost::posix_time::ptime &abs_time) Chris@16: { Chris@101: //Mutexes and condvars handle just fine infinite abs_times Chris@101: //so avoid checking it here Chris@16: scoped_lock_t lck(m_mut, abs_time); Chris@16: if(!lck.owns()) return false; Chris@16: Chris@16: //The sharable lock must block in the first gate Chris@16: //if an exclusive lock has been acquired Chris@16: //or there are too many sharable locks Chris@16: while (this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.num_upr_shar == constants::max_readers){ Chris@101: if(!this->m_first_gate.timed_wait(lck, abs_time)){ Chris@16: if(this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.num_upr_shar == constants::max_readers){ Chris@16: return false; Chris@16: } Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: //Increment sharable count Chris@16: ++this->m_ctrl.num_upr_shar; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline void interprocess_upgradable_mutex::unlock_sharable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: //Decrement sharable count Chris@16: --this->m_ctrl.num_upr_shar; Chris@16: if (this->m_ctrl.num_upr_shar == 0){ Chris@16: this->m_second_gate.notify_one(); Chris@16: } Chris@16: //Check if there are blocked sharables because of Chris@16: //there were too many sharables Chris@16: else if(this->m_ctrl.num_upr_shar == (constants::max_readers-1)){ Chris@16: this->m_first_gate.notify_all(); Chris@16: } Chris@16: } Chris@16: Chris@16: //Downgrading Chris@16: Chris@16: inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: //Unmark it as exclusive Chris@16: this->m_ctrl.exclusive_in = 0; Chris@16: //Mark it as upgradable Chris@16: this->m_ctrl.upgradable_in = 1; Chris@16: //The sharable count should be 0 so increment it Chris@16: this->m_ctrl.num_upr_shar = 1; Chris@16: //Notify readers that they can enter Chris@16: m_first_gate.notify_all(); Chris@16: } Chris@16: Chris@16: inline void interprocess_upgradable_mutex::unlock_and_lock_sharable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: //Unmark it as exclusive Chris@16: this->m_ctrl.exclusive_in = 0; Chris@16: //The sharable count should be 0 so increment it Chris@16: this->m_ctrl.num_upr_shar = 1; Chris@16: //Notify readers that they can enter Chris@16: m_first_gate.notify_all(); Chris@16: } Chris@16: Chris@16: inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: //Unmark it as upgradable (we don't have to decrement count) Chris@16: this->m_ctrl.upgradable_in = 0; Chris@16: //Notify readers/upgradable that they can enter Chris@16: m_first_gate.notify_all(); Chris@16: } Chris@16: Chris@16: //Upgrading Chris@16: Chris@16: inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock() Chris@16: { Chris@16: scoped_lock_t lck(m_mut); Chris@16: //Simulate unlock_upgradable() without Chris@16: //notifying sharables. Chris@16: this->m_ctrl.upgradable_in = 0; Chris@16: --this->m_ctrl.num_upr_shar; Chris@16: //Execute the second half of exclusive locking Chris@16: this->m_ctrl.exclusive_in = 1; Chris@16: Chris@16: //Prepare rollback Chris@16: upgradable_to_exclusive_rollback rollback(m_ctrl); Chris@16: Chris@16: while (this->m_ctrl.num_upr_shar){ Chris@16: this->m_second_gate.wait(lck); Chris@16: } Chris@16: rollback.release(); Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock() Chris@16: { Chris@16: scoped_lock_t lck(m_mut, try_to_lock); Chris@16: //Check if there are no readers Chris@16: if(!lck.owns() Chris@16: || this->m_ctrl.num_upr_shar != 1){ Chris@16: return false; Chris@16: } Chris@16: //Now unlock upgradable and mark exclusive Chris@16: this->m_ctrl.upgradable_in = 0; Chris@16: --this->m_ctrl.num_upr_shar; Chris@16: this->m_ctrl.exclusive_in = 1; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock Chris@16: (const boost::posix_time::ptime &abs_time) Chris@16: { Chris@101: //Mutexes and condvars handle just fine infinite abs_times Chris@101: //so avoid checking it here Chris@16: scoped_lock_t lck(m_mut, abs_time); Chris@16: if(!lck.owns()) return false; Chris@16: Chris@16: //Simulate unlock_upgradable() without Chris@16: //notifying sharables. Chris@16: this->m_ctrl.upgradable_in = 0; Chris@16: --this->m_ctrl.num_upr_shar; Chris@16: //Execute the second half of exclusive locking Chris@16: this->m_ctrl.exclusive_in = 1; Chris@16: Chris@16: //Prepare rollback Chris@16: upgradable_to_exclusive_rollback rollback(m_ctrl); Chris@16: Chris@16: while (this->m_ctrl.num_upr_shar){ Chris@16: if(!this->m_second_gate.timed_wait(lck, abs_time)){ Chris@16: if(this->m_ctrl.num_upr_shar){ Chris@16: return false; Chris@16: } Chris@16: break; Chris@16: } Chris@16: } Chris@16: rollback.release(); Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock() Chris@16: { Chris@16: scoped_lock_t lck(m_mut, try_to_lock); Chris@16: Chris@16: //If we can't lock or any has there is any exclusive, upgradable Chris@16: //or sharable mark return false; Chris@16: if(!lck.owns() Chris@16: || this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.upgradable_in Chris@16: || this->m_ctrl.num_upr_shar != 1){ Chris@16: return false; Chris@16: } Chris@16: this->m_ctrl.exclusive_in = 1; Chris@16: this->m_ctrl.num_upr_shar = 0; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable() Chris@16: { Chris@16: scoped_lock_t lck(m_mut, try_to_lock); Chris@16: Chris@16: //The upgradable lock must fail Chris@16: //if an exclusive or upgradable lock has been acquired Chris@16: if(!lck.owns() Chris@16: || this->m_ctrl.exclusive_in Chris@16: || this->m_ctrl.upgradable_in){ Chris@16: return false; Chris@16: } Chris@16: Chris@16: //Mark that upgradable lock has been acquired Chris@16: this->m_ctrl.upgradable_in = 1; Chris@16: return true; Chris@16: } Chris@16: Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: Chris@16: } //namespace interprocess { Chris@16: } //namespace boost { Chris@16: Chris@16: Chris@16: #include Chris@16: Chris@16: #endif //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP