summaryrefslogtreecommitdiff
path: root/boost/interprocess/sync/detail/condition_any_algorithm.hpp
blob: 5819acfa281b868d35c165af8086f908187cf419 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
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