src/boost/interprocess/sync/detail/condition_any_algorithm.hpp
11faef7a
 //////////////////////////////////////////////////////////////////////////////
 //
 // (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
 
 #ifndef BOOST_CONFIG_HPP
 #  include <boost/config.hpp>
 #endif
 #
 #if defined(BOOST_HAS_PRAGMA_ONCE)
 #  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