summaryrefslogtreecommitdiff
path: root/boost/interprocess/sync/detail
diff options
context:
space:
mode:
Diffstat (limited to 'boost/interprocess/sync/detail')
-rw-r--r--boost/interprocess/sync/detail/common_algorithms.hpp77
-rw-r--r--boost/interprocess/sync/detail/condition_algorithm_8a.hpp127
-rw-r--r--boost/interprocess/sync/detail/condition_any_algorithm.hpp220
-rw-r--r--boost/interprocess/sync/detail/locks.hpp97
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