diff options
Diffstat (limited to 'boost/interprocess/sync/detail')
-rw-r--r-- | boost/interprocess/sync/detail/common_algorithms.hpp | 77 | ||||
-rw-r--r-- | boost/interprocess/sync/detail/condition_algorithm_8a.hpp | 127 | ||||
-rw-r--r-- | boost/interprocess/sync/detail/condition_any_algorithm.hpp | 220 | ||||
-rw-r--r-- | boost/interprocess/sync/detail/locks.hpp | 97 |
4 files changed, 495 insertions, 26 deletions
diff --git a/boost/interprocess/sync/detail/common_algorithms.hpp b/boost/interprocess/sync/detail/common_algorithms.hpp new file mode 100644 index 0000000000..76d1c5c9e8 --- /dev/null +++ b/boost/interprocess/sync/detail/common_algorithms.hpp @@ -0,0 +1,77 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP +#define BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#include <boost/interprocess/sync/spin/wait.hpp> + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template<class MutexType> +bool try_based_timed_lock(MutexType &m, const boost::posix_time::ptime &abs_time) +{ + //Same as lock() + if(abs_time == boost::posix_time::pos_infin){ + m.lock(); + return true; + } + //Always try to lock to achieve POSIX guarantees: + // "Under no circumstance shall the function fail with a timeout if the mutex + // can be locked immediately. The validity of the abs_timeout parameter need not + // be checked if the mutex can be locked immediately." + else if(m.try_lock()){ + return true; + } + else{ + spin_wait swait; + while(microsec_clock::universal_time() < abs_time){ + if(m.try_lock()){ + return true; + } + swait.yield(); + } + return false; + } +} + +template<class MutexType> +void try_based_lock(MutexType &m) +{ + if(!m.try_lock()){ + spin_wait swait; + do{ + if(m.try_lock()){ + break; + } + else{ + swait.yield(); + } + } + while(1); + } +} + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_SYNC_DETAIL_COMMON_ALGORITHMS_HPP diff --git a/boost/interprocess/sync/detail/condition_algorithm_8a.hpp b/boost/interprocess/sync/detail/condition_algorithm_8a.hpp index eaad671cdf..be93af7b8f 100644 --- a/boost/interprocess/sync/detail/condition_algorithm_8a.hpp +++ b/boost/interprocess/sync/detail/condition_algorithm_8a.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,9 +11,14 @@ #ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP #define BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/sync/detail/locks.hpp> #include <limits> namespace boost { @@ -161,6 +166,15 @@ namespace ipcdetail { // mutex_type &get_mtx_unblock_lock() // }; // +// Must be initialized as following +// +// get_nwaiters_blocked() == 0 +// get_nwaiters_gone() == 0 +// get_nwaiters_to_unblock() == 0 +// get_sem_block_queue() == initial count 0 +// get_sem_block_lock() == initial count 1 +// get_mtx_unblock_lock() (unlocked) +// template<class ConditionMembers> class condition_algorithm_8a { @@ -174,16 +188,10 @@ class condition_algorithm_8a typedef typename ConditionMembers::mutex_type mutex_type; typedef typename ConditionMembers::integer_type integer_type; - // nwaiters_blocked == 0 - // nwaiters_gone() == 0 - // nwaiters_to_unblock == 0 - // sem_block_queue() == initial count 0 - // sem_block_lock() == initial count 1 - // mtx_unblock_lock (unlocked) - public: - template<class InterprocessMutex> - static bool wait (ConditionMembers &data, bool timeout_enabled, const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); + template<class Lock> + static bool wait ( ConditionMembers &data, Lock &lock + , bool timeout_enabled, const boost::posix_time::ptime &abs_time); static void signal(ConditionMembers &data, bool broadcast); }; @@ -235,9 +243,13 @@ inline void condition_algorithm_8a<ConditionMembers>::signal(ConditionMembers &d } template<class ConditionMembers> -template<class InterprocessMutex> +template<class Lock> inline bool condition_algorithm_8a<ConditionMembers>::wait - (ConditionMembers &data, bool tout_enabled, const boost::posix_time::ptime &abs_time, InterprocessMutex &mtxExternal) + ( ConditionMembers &data + , Lock &lock + , bool tout_enabled + , const boost::posix_time::ptime &abs_time + ) { //Initialize to avoid warnings integer_type nsignals_was_left = 0; @@ -247,19 +259,13 @@ inline bool condition_algorithm_8a<ConditionMembers>::wait ++data.get_nwaiters_blocked(); data.get_sem_block_lock().post(); - struct scoped_unlock - { - InterprocessMutex & mut; - scoped_unlock(InterprocessMutex & m) - : mut(m) - { m.unlock(); } + //Unlock external lock and program for relock + lock_inverter<Lock> inverted_lock(lock); + scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock); - ~scoped_unlock() - { mut.lock(); } - } unlocker(mtxExternal); - - - bool bTimedOut = tout_enabled ? !data.get_sem_block_queue().timed_wait(abs_time) : (data.get_sem_block_queue().wait(), false); + bool bTimedOut = tout_enabled + ? !data.get_sem_block_queue().timed_wait(abs_time) + : (data.get_sem_block_queue().wait(), false); { scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock()); @@ -290,7 +296,7 @@ inline bool condition_algorithm_8a<ConditionMembers>::wait data.get_nwaiters_gone() = 0; } //locker's destructor triggers data.get_mtx_unblock_lock().unlock() - } + } if ( 1 == nsignals_was_left ) { if ( 0 != nwaiters_was_gone ) { @@ -302,11 +308,80 @@ inline bool condition_algorithm_8a<ConditionMembers>::wait data.get_sem_block_lock().post(); // open the gate } - //mtxExternal.lock(); called from unlocker + //lock.lock(); called from unlocker destructor return ( bTimedOut ) ? false : true; } + +template<class ConditionMembers> +class condition_8a_wrapper +{ + //Non-copyable + condition_8a_wrapper(const condition_8a_wrapper &); + condition_8a_wrapper &operator=(const condition_8a_wrapper &); + + ConditionMembers m_data; + typedef ipcdetail::condition_algorithm_8a<ConditionMembers> algo_type; + + public: + + condition_8a_wrapper(){} + + //Compiler-generated destructor is OK + //~condition_8a_wrapper(){} + + ConditionMembers & get_members() + { return m_data; } + + const ConditionMembers & get_members() const + { return m_data; } + + void notify_one() + { algo_type::signal(m_data, false); } + + void notify_all() + { algo_type::signal(m_data, true); } + + template <typename L> + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + } + + template <typename L, typename Pr> + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + } + + template <typename L> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + if (!lock) + throw lock_exception(); + return algo_type::wait(m_data, lock, true, abs_time); + } + + template <typename L, typename Pr> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + if (!lock) + throw lock_exception(); + while (!pred()){ + if (!algo_type::wait(m_data, lock, true, abs_time)) + return pred(); + } + return true; + } +}; + } //namespace ipcdetail } //namespace interprocess } //namespace boost diff --git a/boost/interprocess/sync/detail/condition_any_algorithm.hpp b/boost/interprocess/sync/detail/condition_any_algorithm.hpp new file mode 100644 index 0000000000..5819acfa28 --- /dev/null +++ b/boost/interprocess/sync/detail/condition_any_algorithm.hpp @@ -0,0 +1,220 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP +#define BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/sync/detail/locks.hpp> +#include <limits> + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// +// Condition variable 'any' (able to use any type of external mutex) +// +// The code is based on Howard E. Hinnant's ISO C++ N2406 paper. +// Many thanks to Howard for his support and comments. +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +// Required interface for ConditionAnyMembers +// class ConditionAnyMembers +// { +// typedef implementation_defined mutex_type; +// typedef implementation_defined condvar_type; +// +// condvar &get_condvar() +// mutex_type &get_mutex() +// }; +// +// Must be initialized as following +// +// get_condvar() [no threads blocked] +// get_mutex() [unlocked] + +template<class ConditionAnyMembers> +class condition_any_algorithm +{ + private: + condition_any_algorithm(); + ~condition_any_algorithm(); + condition_any_algorithm(const condition_any_algorithm &); + condition_any_algorithm &operator=(const condition_any_algorithm &); + + typedef typename ConditionAnyMembers::mutex_type mutex_type; + typedef typename ConditionAnyMembers::condvar_type condvar_type; + + template <class Lock> + static void do_wait(ConditionAnyMembers &data, Lock& lock); + + template <class Lock> + static bool do_timed_wait(ConditionAnyMembers &data, Lock& lock, const boost::posix_time::ptime &abs_time); + + public: + template<class Lock> + static bool wait ( ConditionAnyMembers &data, Lock &mut + , bool timeout_enabled, const boost::posix_time::ptime &abs_time); + static void signal( ConditionAnyMembers &data, bool broadcast); +}; + +template<class ConditionAnyMembers> +void condition_any_algorithm<ConditionAnyMembers>::signal(ConditionAnyMembers &data, bool broadcast) +{ + scoped_lock<mutex_type> internal_lock(data.get_mutex()); + if(broadcast){ + data.get_condvar().notify_all(); + } + else{ + data.get_condvar().notify_one(); + } +} + +template<class ConditionAnyMembers> +template<class Lock> +bool condition_any_algorithm<ConditionAnyMembers>::wait + ( ConditionAnyMembers &data + , Lock &lock + , bool tout_enabled + , const boost::posix_time::ptime &abs_time) +{ + if(tout_enabled){ + return condition_any_algorithm::do_timed_wait(data, lock, abs_time); + } + else{ + condition_any_algorithm::do_wait(data, lock); + return true; + } +} + +template<class ConditionAnyMembers> +template <class Lock> +void condition_any_algorithm<ConditionAnyMembers>::do_wait + (ConditionAnyMembers &data, Lock& lock) +{ + //lock internal before unlocking external to avoid race with a notifier + scoped_lock<mutex_type> internal_lock(data.get_mutex()); + { + lock_inverter<Lock> inverted_lock(lock); + scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock); + { //unlock internal first to avoid deadlock with near simultaneous waits + scoped_lock<mutex_type> internal_unlock; + internal_lock.swap(internal_unlock); + data.get_condvar().wait(internal_unlock); + } + } +} + +template<class ConditionAnyMembers> +template <class Lock> +bool condition_any_algorithm<ConditionAnyMembers>::do_timed_wait + (ConditionAnyMembers &data, Lock& lock, const boost::posix_time::ptime &abs_time) +{ + //lock internal before unlocking external to avoid race with a notifier + scoped_lock<mutex_type> internal_lock(data.get_mutex()); + { + //Unlock external lock and program for relock + lock_inverter<Lock> inverted_lock(lock); + scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock); + { //unlock internal first to avoid deadlock with near simultaneous waits + scoped_lock<mutex_type> internal_unlock; + internal_lock.swap(internal_unlock); + return data.get_condvar().timed_wait(internal_unlock, abs_time); + } + } +} + + +template<class ConditionAnyMembers> +class condition_any_wrapper +{ + //Non-copyable + condition_any_wrapper(const condition_any_wrapper &); + condition_any_wrapper &operator=(const condition_any_wrapper &); + + ConditionAnyMembers m_data; + typedef ipcdetail::condition_any_algorithm<ConditionAnyMembers> algo_type; + + public: + + condition_any_wrapper(){} + + ~condition_any_wrapper(){} + + ConditionAnyMembers & get_members() + { return m_data; } + + const ConditionAnyMembers & get_members() const + { return m_data; } + + void notify_one() + { algo_type::signal(m_data, false); } + + void notify_all() + { algo_type::signal(m_data, true); } + + template <typename L> + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + } + + template <typename L, typename Pr> + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + } + + template <typename L> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + if (!lock) + throw lock_exception(); + return algo_type::wait(m_data, lock, true, abs_time); + } + + template <typename L, typename Pr> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + if (!lock) + throw lock_exception(); + while (!pred()){ + if (!algo_type::wait(m_data, lock, true, abs_time)) + return pred(); + } + return true; + } +}; + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP diff --git a/boost/interprocess/sync/detail/locks.hpp b/boost/interprocess/sync/detail/locks.hpp new file mode 100644 index 0000000000..05652003a8 --- /dev/null +++ b/boost/interprocess/sync/detail/locks.hpp @@ -0,0 +1,97 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_LOCKS_HPP +#define BOOST_INTERPROCESS_DETAIL_LOCKS_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template<class Lock> +class internal_mutex_lock +{ + typedef void (internal_mutex_lock::*unspecified_bool_type)(); + public: + + typedef typename Lock::mutex_type::internal_mutex_type mutex_type; + + + internal_mutex_lock(Lock &l) + : l_(l) + {} + + mutex_type* mutex() const + { return l_ ? &l_.mutex()->internal_mutex() : 0; } + + void lock() { l_.lock(); } + + void unlock() { l_.unlock(); } + + operator unspecified_bool_type() const + { return l_ ? &internal_mutex_lock::lock : 0; } + + private: + Lock &l_; +}; + +template <class Lock> +class lock_inverter +{ + Lock &l_; + public: + lock_inverter(Lock &l) + : l_(l) + {} + void lock() { l_.unlock(); } + void unlock() { l_.lock(); } +}; + +template <class Lock> +class lock_to_sharable +{ + Lock &l_; + + public: + explicit lock_to_sharable(Lock &l) + : l_(l) + {} + void lock() { l_.lock_sharable(); } + bool try_lock(){ return l_.try_lock_sharable(); } + void unlock() { l_.unlock_sharable(); } +}; + +template <class Lock> +class lock_to_wait +{ + Lock &l_; + + public: + explicit lock_to_wait(Lock &l) + : l_(l) + {} + void lock() { l_.wait(); } + bool try_lock(){ return l_.try_wait(); } +}; + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DETAIL_LOCKS_HPP |