Ice 3.7 C++11 API Reference
Cond.h
Go to the documentation of this file.
1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #ifndef ICE_UTIL_COND_H
6 #define ICE_UTIL_COND_H
7 
8 #include <IceUtil/Config.h>
9 #include <IceUtil/Time.h>
11 
12 #if defined(_WIN32) && !defined(ICE_HAS_WIN32_CONDVAR)
13 # include <IceUtil/Mutex.h>
14 
15 namespace IceUtilInternal
16 {
17 //
18 // Needed for implementation.
19 //
20 class Semaphore
21 {
22 public:
23 
24  Semaphore(long = 0);
25  ICE_API ~Semaphore();
26 
27  void wait() const;
28  bool timedWait(const IceUtil::Time&) const;
29  void post(int = 1) const;
30 
31 private:
32 
33  mutable HANDLE _sem;
34 };
35 }
36 #endif
37 
38 namespace IceUtil
39 {
40 
41 //
42 // Forward declaration (for friend declarations).
43 //
44 template <class T> class Monitor;
45 class RecMutex;
46 class Mutex;
47 
48 //
49 // Condition variable implementation. Conforms to the same semantics
50 // as a POSIX threads condition variable.
51 //
52 class ICE_API Cond : private noncopyable
53 {
54 public:
55 
56  Cond();
57  ~Cond();
58 
59  //
60  // signal restarts one of the threads that are waiting on the
61  // condition variable cond. If no threads are waiting on cond,
62  // nothing happens. If several threads are waiting on cond,
63  // exactly one is restarted, but it is not specified which.
64  //
65  void signal();
66 
67  //
68  // broadcast restarts all the threads that are waiting on the
69  // condition variable cond. Nothing happens if no threads are
70  // waiting on cond.
71  //
72  void broadcast();
73 
74  //
75  // MSVC doesn't support out-of-class definitions of member
76  // templates. See KB Article Q241949 for details.
77  //
78 
79  //
80  // wait atomically unlocks the mutex and waits for the condition
81  // variable to be signaled. Before returning to the calling thread
82  // the mutex is reaquired.
83  //
84  template <typename Lock> inline void
85  wait(const Lock& lock) const
86  {
87  if(!lock.acquired())
88  {
89  throw ThreadLockedException(__FILE__, __LINE__);
90  }
91  waitImpl(lock._mutex);
92  }
93 
94  //
95  // wait atomically unlocks the mutex and waits for the condition
96  // variable to be signaled for up to the given timeout. Before
97  // returning to the calling thread the mutex is reaquired. Returns
98  // true if the condition variable was signaled, false on a
99  // timeout.
100  //
101  template <typename Lock> inline bool
102  timedWait(const Lock& lock, const Time& timeout) const
103  {
104  if(!lock.acquired())
105  {
106  throw ThreadLockedException(__FILE__, __LINE__);
107  }
108  return timedWaitImpl(lock._mutex, timeout);
109  }
110 
111 private:
112 
113  friend class Monitor<Mutex>;
114  friend class Monitor<RecMutex>;
115 
116  //
117  // The Monitor implementation uses waitImpl & timedWaitImpl.
118  //
119 #if defined(_WIN32) && !defined(ICE_HAS_WIN32_CONDVAR)
120 
121  template <typename M> void
122  waitImpl(const M& mutex) const
123  {
124  preWait();
125 
126  typedef typename M::LockState LockState;
127 
128  LockState state;
129  mutex.unlock(state);
130 
131  try
132  {
133  dowait();
134  mutex.lock(state);
135  }
136  catch(...)
137  {
138  mutex.lock(state);
139  throw;
140  }
141  }
142  template <typename M> bool
143  timedWaitImpl(const M& mutex, const Time& timeout) const
144  {
145  preWait();
146 
147  typedef typename M::LockState LockState;
148 
149  LockState state;
150  mutex.unlock(state);
151 
152  try
153  {
154  bool rc = timedDowait(timeout);
155  mutex.lock(state);
156  return rc;
157  }
158  catch(...)
159  {
160  mutex.lock(state);
161  throw;
162  }
163  }
164 
165 #else
166 
167  template <typename M> void waitImpl(const M&) const;
168  template <typename M> bool timedWaitImpl(const M&, const Time&) const;
169 
170 #endif
171 
172 #ifdef _WIN32
173 # ifdef ICE_HAS_WIN32_CONDVAR
174  mutable CONDITION_VARIABLE _cond;
175 # else
176  void wake(bool);
177  void preWait() const;
178  void postWait(bool) const;
179  bool timedDowait(const Time&) const;
180  void dowait() const;
181 
182  Mutex _internal;
183  IceUtilInternal::Semaphore _gate;
184  IceUtilInternal::Semaphore _queue;
185  mutable long _blocked;
186  mutable long _unblocked;
187  enum State
188  {
189  StateIdle,
190  StateSignal,
191  StateBroadcast
192  };
193  mutable State _state;
194 # endif
195 #else
196  mutable pthread_cond_t _cond;
197 #endif
198 
199 };
200 
201 #ifdef _WIN32
202 
203 # ifdef ICE_HAS_WIN32_CONDVAR
204 
205 template <typename M> inline void
206 Cond::waitImpl(const M& mutex) const
207 {
208  typedef typename M::LockState LockState;
209 
210  LockState state;
211  mutex.unlock(state);
212  BOOL ok = SleepConditionVariableCS(&_cond, state.mutex, INFINITE);
213  mutex.lock(state);
214 
215  if(!ok)
216  {
217  throw ThreadSyscallException(__FILE__, __LINE__, GetLastError());
218  }
219 }
220 
221 template <typename M> inline bool
222 Cond::timedWaitImpl(const M& mutex, const Time& timeout) const
223 {
224  IceUtil::Int64 msTimeout = timeout.toMilliSeconds();
225  if(msTimeout < 0 || msTimeout > 0x7FFFFFFF)
226  {
227  throw IceUtil::InvalidTimeoutException(__FILE__, __LINE__, timeout);
228  }
229 
230  typedef typename M::LockState LockState;
231 
232  LockState state;
233  mutex.unlock(state);
234  BOOL ok = SleepConditionVariableCS(&_cond, state.mutex, static_cast<DWORD>(msTimeout));
235  mutex.lock(state);
236 
237  if(!ok)
238  {
239  DWORD err = GetLastError();
240 
241  if(err != ERROR_TIMEOUT)
242  {
243  throw ThreadSyscallException(__FILE__, __LINE__, err);
244  }
245  return false;
246  }
247  return true;
248 }
249 
250 # endif
251 
252 #else
253 template <typename M> inline void
254 Cond::waitImpl(const M& mutex) const
255 {
256  typedef typename M::LockState LockState;
257 
258  LockState state;
259  mutex.unlock(state);
260  int rc = pthread_cond_wait(&_cond, state.mutex);
261  mutex.lock(state);
262 
263  if(rc != 0)
264  {
265  throw ThreadSyscallException(__FILE__, __LINE__, rc);
266  }
267 }
268 
269 template <typename M> inline bool
270 Cond::timedWaitImpl(const M& mutex, const Time& timeout) const
271 {
272  if(timeout < Time::microSeconds(0))
273  {
274  throw InvalidTimeoutException(__FILE__, __LINE__, timeout);
275  }
276 
277  typedef typename M::LockState LockState;
278 
279  LockState state;
280  mutex.unlock(state);
281 
282 # ifdef __APPLE__
283  //
284  // The monotonic time is based on mach_absolute_time and pthread
285  // condition variables require time from gettimeofday so we get
286  // the realtime time.
287  //
288  timeval tv = Time::now(Time::Realtime) + timeout;
289 # else
290  timeval tv = Time::now(Time::Monotonic) + timeout;
291 # endif
292  timespec ts;
293  ts.tv_sec = tv.tv_sec;
294  ts.tv_nsec = tv.tv_usec * 1000;
295  int rc = pthread_cond_timedwait(&_cond, state.mutex, &ts);
296  mutex.lock(state);
297 
298  if(rc != 0)
299  {
300  //
301  // pthread_cond_timedwait returns ETIMEOUT in the event of a
302  // timeout.
303  //
304  if(rc != ETIMEDOUT)
305  {
306  throw ThreadSyscallException(__FILE__, __LINE__, rc);
307  }
308  return false;
309  }
310  return true;
311 }
312 
313 #endif
314 
315 } // End namespace IceUtil
316 
317 #endif
IceUtil::RecMutex
Definition: RecMutex.h:25
IceUtil::Time::now
static Time now(Clock=Realtime)
IceUtil::Time::Monotonic
@ Monotonic
Definition: Time.h:27
IceUtil::Cond
Definition: Cond.h:53
IceUtil::Time::Realtime
@ Realtime
Definition: Time.h:27
IceUtil::InvalidTimeoutException
Definition: ThreadException.h:76
IceUtil
Definition: Optional.h:1095
IceUtil::Time::microSeconds
static Time microSeconds(Int64)
ICE_API
#define ICE_API
Definition: Config.h:197
IceUtil::Cond::timedWait
bool timedWait(const Lock &lock, const Time &timeout) const
Definition: Cond.h:102
IceUtil::Monitor
Definition: Monitor.h:22
IceUtil::Cond::Cond
Cond()
IceUtil::Time
Definition: Time.h:18
IceUtil::noncopyable
Definition: Config.h:313
IceUtil::Cond::~Cond
~Cond()
Time.h
IceUtil::ThreadLockedException
Definition: ThreadException.h:27
Config.h
IceUtil::Mutex
Definition: Mutex.h:33
Mutex.h
IceUtil::Cond::broadcast
void broadcast()
IceUtil::Int64
long long Int64
Definition: Config.h:342
ThreadException.h
IceUtil::Cond::signal
void signal()
IceUtil::Cond::wait
void wait(const Lock &lock) const
Definition: Cond.h:85