summaryrefslogtreecommitdiff
path: root/boost/interprocess/sync/detail/condition_any_algorithm.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/interprocess/sync/detail/condition_any_algorithm.hpp')
-rw-r--r--boost/interprocess/sync/detail/condition_any_algorithm.hpp220
1 files changed, 220 insertions, 0 deletions
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