Ice 3.7 C++11 API Reference
Loading...
Searching...
No Matches
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
15namespace IceUtilInternal
16{
17//
18// Needed for implementation.
19//
20class Semaphore
21{
22public:
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
31private:
32
33 mutable HANDLE _sem;
34};
35}
36#endif
37
38namespace IceUtil
39{
40
41//
42// Forward declaration (for friend declarations).
43//
44template <class T> class Monitor;
45class RecMutex;
46class Mutex;
47
48//
49// Condition variable implementation. Conforms to the same semantics
50// as a POSIX threads condition variable.
51//
52class ICE_API Cond : private noncopyable
53{
54public:
55
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 reacquired. 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
111private:
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
205template <typename M> inline void
206Cond::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
221template <typename M> inline bool
222Cond::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
253template <typename M> inline void
254Cond::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
269template <typename M> inline bool
270Cond::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
#define ICE_API
Definition Config.h:197
void broadcast()
void wait(const Lock &lock) const
Definition Cond.h:85
bool timedWait(const Lock &lock, const Time &timeout) const
Definition Cond.h:102
Definition Monitor.h:22
Definition Mutex.h:33
Definition RecMutex.h:25
Definition ThreadException.h:27
Definition Time.h:18
static Time microSeconds(Int64)
static Time now(Clock=Realtime)
@ Realtime
Definition Time.h:27
@ Monotonic
Definition Time.h:27
noncopyable()
Definition Config.h:316
Definition Optional.h:1095
long long Int64
Definition Config.h:342