• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP
12 #define BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP
13 
14 #ifndef BOOST_CONFIG_HPP
15 #  include <boost/config.hpp>
16 #endif
17 #
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
19 #  pragma once
20 #endif
21 
22 #include <boost/interprocess/detail/config_begin.hpp>
23 #include <boost/interprocess/detail/workaround.hpp>
24 #include <boost/interprocess/sync/scoped_lock.hpp>
25 #include <boost/interprocess/sync/detail/locks.hpp>
26 #include <limits>
27 
28 namespace boost {
29 namespace interprocess {
30 namespace ipcdetail {
31 
32 ////////////////////////////////////////////////////////////////////////
33 ////////////////////////////////////////////////////////////////////////
34 ////////////////////////////////////////////////////////////////////////
35 //
36 // Condition variable 'any' (able to use any type of external mutex)
37 //
38 // The code is based on Howard E. Hinnant's ISO C++ N2406 paper.
39 // Many thanks to Howard for his support and comments.
40 ////////////////////////////////////////////////////////////////////////
41 ////////////////////////////////////////////////////////////////////////
42 ////////////////////////////////////////////////////////////////////////
43 
44 // Required interface for ConditionAnyMembers
45 // class ConditionAnyMembers
46 // {
47 //    typedef implementation_defined mutex_type;
48 //    typedef implementation_defined condvar_type;
49 //
50 //    condvar     &get_condvar()
51 //    mutex_type  &get_mutex()
52 // };
53 //
54 // Must be initialized as following
55 //
56 //    get_condvar()  [no threads blocked]
57 //    get_mutex()    [unlocked]
58 
59 template<class ConditionAnyMembers>
60 class condition_any_algorithm
61 {
62    private:
63    condition_any_algorithm();
64    ~condition_any_algorithm();
65    condition_any_algorithm(const condition_any_algorithm &);
66    condition_any_algorithm &operator=(const condition_any_algorithm &);
67 
68    typedef typename ConditionAnyMembers::mutex_type      mutex_type;
69    typedef typename ConditionAnyMembers::condvar_type    condvar_type;
70 
71    template <class Lock>
72    static void do_wait(ConditionAnyMembers &data, Lock& lock);
73 
74    template <class Lock>
75    static bool do_timed_wait(ConditionAnyMembers &data, Lock& lock, const boost::posix_time::ptime &abs_time);
76 
77    public:
78    template<class Lock>
79    static bool wait  ( ConditionAnyMembers &data, Lock &mut
80                      , bool timeout_enabled, const boost::posix_time::ptime &abs_time);
81    static void signal( ConditionAnyMembers &data, bool broadcast);
82 };
83 
84 template<class ConditionAnyMembers>
signal(ConditionAnyMembers & data,bool broadcast)85 void condition_any_algorithm<ConditionAnyMembers>::signal(ConditionAnyMembers &data, bool broadcast)
86 {
87    scoped_lock<mutex_type> internal_lock(data.get_mutex());
88    if(broadcast){
89       data.get_condvar().notify_all();
90    }
91    else{
92       data.get_condvar().notify_one();
93    }
94 }
95 
96 template<class ConditionAnyMembers>
97 template<class Lock>
wait(ConditionAnyMembers & data,Lock & lock,bool tout_enabled,const boost::posix_time::ptime & abs_time)98 bool condition_any_algorithm<ConditionAnyMembers>::wait
99    ( ConditionAnyMembers &data
100    , Lock &lock
101    , bool tout_enabled
102    , const boost::posix_time::ptime &abs_time)
103 {
104    if(tout_enabled){
105       return condition_any_algorithm::do_timed_wait(data, lock, abs_time);
106    }
107    else{
108       condition_any_algorithm::do_wait(data, lock);
109       return true;
110    }
111 }
112 
113 template<class ConditionAnyMembers>
114 template <class Lock>
do_wait(ConditionAnyMembers & data,Lock & lock)115 void condition_any_algorithm<ConditionAnyMembers>::do_wait
116    (ConditionAnyMembers &data, Lock& lock)
117 {
118    //lock internal before unlocking external to avoid race with a notifier
119    scoped_lock<mutex_type> internal_lock(data.get_mutex());
120    {
121       lock_inverter<Lock> inverted_lock(lock);
122       scoped_lock<lock_inverter<Lock> >   external_unlock(inverted_lock);
123       {  //unlock internal first to avoid deadlock with near simultaneous waits
124          scoped_lock<mutex_type>     internal_unlock;
125          internal_lock.swap(internal_unlock);
126          data.get_condvar().wait(internal_unlock);
127       }
128    }
129 }
130 
131 template<class ConditionAnyMembers>
132 template <class Lock>
do_timed_wait(ConditionAnyMembers & data,Lock & lock,const boost::posix_time::ptime & abs_time)133 bool condition_any_algorithm<ConditionAnyMembers>::do_timed_wait
134    (ConditionAnyMembers &data, Lock& lock, const boost::posix_time::ptime &abs_time)
135 {
136    //lock internal before unlocking external to avoid race with a notifier
137    scoped_lock<mutex_type> internal_lock(data.get_mutex());
138    {
139       //Unlock external lock and program for relock
140       lock_inverter<Lock> inverted_lock(lock);
141       scoped_lock<lock_inverter<Lock> >   external_unlock(inverted_lock);
142       {  //unlock internal first to avoid deadlock with near simultaneous waits
143          scoped_lock<mutex_type> internal_unlock;
144          internal_lock.swap(internal_unlock);
145          return data.get_condvar().timed_wait(internal_unlock, abs_time);
146       }
147    }
148 }
149 
150 
151 template<class ConditionAnyMembers>
152 class condition_any_wrapper
153 {
154    //Non-copyable
155    condition_any_wrapper(const condition_any_wrapper &);
156    condition_any_wrapper &operator=(const condition_any_wrapper &);
157 
158    ConditionAnyMembers m_data;
159    typedef ipcdetail::condition_any_algorithm<ConditionAnyMembers> algo_type;
160 
161    public:
162 
condition_any_wrapper()163    condition_any_wrapper(){}
164 
~condition_any_wrapper()165    ~condition_any_wrapper(){}
166 
get_members()167    ConditionAnyMembers & get_members()
168    {  return m_data; }
169 
get_members() const170    const ConditionAnyMembers & get_members() const
171    {  return m_data; }
172 
notify_one()173    void notify_one()
174    {  algo_type::signal(m_data, false);  }
175 
notify_all()176    void notify_all()
177    {  algo_type::signal(m_data, true);  }
178 
179    template <typename L>
wait(L & lock)180    void wait(L& lock)
181    {
182       if (!lock)
183          throw lock_exception();
184       algo_type::wait(m_data, lock, false, boost::posix_time::ptime());
185    }
186 
187    template <typename L, typename Pr>
wait(L & lock,Pr pred)188    void wait(L& lock, Pr pred)
189    {
190       if (!lock)
191          throw lock_exception();
192 
193       while (!pred())
194          algo_type::wait(m_data, lock, false, boost::posix_time::ptime());
195    }
196 
197    template <typename L>
timed_wait(L & lock,const boost::posix_time::ptime & abs_time)198    bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time)
199    {
200       if (!lock)
201          throw lock_exception();
202       return algo_type::wait(m_data, lock, true, abs_time);
203    }
204 
205    template <typename L, typename Pr>
timed_wait(L & lock,const boost::posix_time::ptime & abs_time,Pr pred)206    bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
207    {
208       if (!lock)
209             throw lock_exception();
210       while (!pred()){
211          if (!algo_type::wait(m_data, lock, true, abs_time))
212             return pred();
213       }
214       return true;
215    }
216 };
217 
218 }  //namespace ipcdetail
219 }  //namespace interprocess
220 }  //namespace boost
221 
222 #include <boost/interprocess/detail/config_end.hpp>
223 
224 #endif   //BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP
225