1 // ==========================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ==========================================================================
4 // Copyright (c) 2006-2015, Knut Reinert, FU Berlin
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
16 // its contributors may be used to endorse or promote products derived
17 // from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
23 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 // DAMAGE.
30 //
31 // ==========================================================================
32 // Author: David Weese <david.weese@fu-berlin.de>
33 // ==========================================================================
34
35 #ifndef SEQAN_HEADER_SYSTEM_EVENT_H
36 #define SEQAN_HEADER_SYSTEM_EVENT_H
37
38 namespace SEQAN_NAMESPACE_MAIN {
39
40 #ifdef PLATFORM_WINDOWS
41
42 static SECURITY_ATTRIBUTES EventDefaultAttributes =
43 {
44 sizeof(SECURITY_ATTRIBUTES),
45 NULL,
46 true
47 };
48
49 struct Event // this class mustn't exceed the size of HANDLE (needed by waitForAll/Any)
50 {
51 typedef HANDLE Handle;
52 enum {Infinite = INFINITE};
53 Handle hEvent;
54
EventEvent55 Event() :
56 hEvent(NULL) {}
57
EventEvent58 Event(BOOL initial)
59 {
60 SEQAN_DO_SYS2(open(initial), "Could not create Event");
61 }
62
63 // Move constructors
EventEvent64 Event(Event & other, Move) :
65 hEvent(other.hEvent)
66 {
67 other.hEvent = NULL;
68 }
69
70 #ifdef SEQAN_CXX11_STANDARD
EventEvent71 Event(Event && other) :
72 hEvent(other.hEvent)
73 {
74 other.hEvent = NULL;
75 }
76 #endif
77
~EventEvent78 ~Event()
79 {
80 if (*this) SEQAN_DO_SYS2(close(), "Could not destroy Event");
81 }
82
83 inline Event & operator=(Event const & origin)
84 {
85 // resource sharing is not yet supported (performance reason)
86 // it needs a reference counting technique
87 if (origin)
88 {
89 hEvent = origin.hEvent;
90 const_cast<Event &>(origin).hEvent = NULL;
91 }
92 else
93 hEvent = NULL;
94 return *this;
95 }
96
97 inline bool open(BOOL initial = FALSE)
98 {
99 return (hEvent = CreateEvent(&EventDefaultAttributes, TRUE, initial, NULL)) != NULL;
100 }
101
closeEvent102 inline bool close()
103 {
104 bool success = CloseHandle(hEvent);
105 hEvent = NULL;
106 return success;
107 }
108
waitEvent109 inline bool wait(DWORD timeoutMilliSec, bool & inProgress)
110 {
111 if (!hEvent)
112 {
113 inProgress = false;
114 return true;
115 }
116 DWORD result = WaitForSingleObject(hEvent, timeoutMilliSec);
117 inProgress = (result == WAIT_TIMEOUT);
118 return result == WAIT_OBJECT_0 || inProgress;
119 }
120
waitEvent121 inline bool wait()
122 {
123 bool dummy;
124 return wait(Infinite, dummy);
125 }
126
signalEvent127 inline bool signal()
128 {
129 return SetEvent(hEvent) != 0;
130 }
131
resetEvent132 inline bool reset()
133 {
134 return ResetEvent(hEvent) != 0;
135 }
136
137 inline operator bool() const
138 {
139 return hEvent != NULL;
140 }
141
142 private:
143
EventEvent144 Event(Event const &) :
145 hEvent(NULL)
146 {
147 // we only support move construction (no copy-construction)
148 }
149 };
150
151
152 //////////////////////////////////////////////////////////////////////////////
153 // global event functions
154
reset(Event & e)155 inline void reset(Event & e)
156 {
157 e.reset();
158 }
159
waitForAll(Event eventList[],DWORD count,DWORD timeoutMilliSec)160 inline bool waitForAll(Event eventList[], DWORD count, DWORD timeoutMilliSec)
161 {
162 return WaitForMultipleObjects(count, &eventList[0].hEvent, true, timeoutMilliSec) != WAIT_TIMEOUT;
163 }
164
waitForAll(Event eventList[],DWORD count)165 inline bool waitForAll(Event eventList[], DWORD count)
166 {
167 return waitForAll(eventList, count, Event::Infinite);
168 }
169
waitForAny(Event eventList[],DWORD count,DWORD timeoutMilliSec)170 inline int waitForAny(Event eventList[], DWORD count, DWORD timeoutMilliSec)
171 {
172 DWORD result = WaitForMultipleObjects(count, &eventList[0].hEvent, false, timeoutMilliSec);
173
174 if (/*result >= WAIT_OBJECT_0 && */ result < WAIT_OBJECT_0 + count)
175 return result - WAIT_OBJECT_0;
176
177 return -1;
178 }
179
waitForAny(Event eventList[],DWORD count)180 inline int waitForAny(Event eventList[], DWORD count)
181 {
182 return waitForAny(eventList, count, Event::Infinite);
183 }
184
185 #else
186
187 struct Event :
188 public Mutex
189 {
190 typedef pthread_cond_t * Handle;
191 enum {Infinite = LONG_MAX};
192 pthread_cond_t data, * hEvent;
193
194 Event() :
195 hEvent(NULL) {}
196
197 Event(bool initial)
198 {
199 SEQAN_DO_SYS(open(initial));
200 }
201
202 // Move constructors
203 Event(Event & other, Move) :
204 Mutex(other, Move()),
205 hEvent(other.hEvent)
206 {
207 other.hEvent = NULL;
208 }
209
210 #ifdef SEQAN_CXX11_STANDARD
211 Event(Event && other) :
212 hEvent(other.hEvent)
213 {
214 other.hEvent = NULL;
215 }
216 #endif
217
218 ~Event()
219 {
220 if (*this)
221 SEQAN_DO_SYS(close());
222 }
223
224 inline Event & operator=(Event const & origin)
225 {
226 // resource sharing is not yet supported (performance reason)
227 // it needs a reference counting technique
228 if (origin)
229 {
230 data = origin.data;
231 const_cast<Event &>(origin).hEvent = NULL;
232 hEvent = &data;
233 }
234 else
235 hEvent = NULL;
236 return *this;
237 }
238
239 inline bool open(bool initial = false)
240 {
241 if (Mutex::open() && pthread_cond_init(&data, NULL) == 0 && (hEvent = &data))
242 {
243 if (initial)
244 return signal();
245
246 return true;
247 }
248 else
249 return false;
250 }
251
252 inline bool close()
253 {
254 bool success = (pthread_cond_destroy(hEvent) == 0);
255 success &= Mutex::close();
256 hEvent = NULL;
257 return success;
258 }
259
260 inline bool wait()
261 {
262 if (!hEvent) return true;
263
264 return pthread_cond_wait(hEvent, Mutex::hMutex) == 0;
265 }
266
267 inline bool wait(long timeoutMilliSec, bool & inProgress)
268 {
269 if (timeoutMilliSec != Infinite)
270 {
271 timespec ts;
272 ts.tv_sec = timeoutMilliSec / 1000;
273 ts.tv_nsec = (timeoutMilliSec % 1000) * 1000;
274 int result = pthread_cond_timedwait(hEvent, Mutex::hMutex, &ts);
275 inProgress = (result == ETIMEDOUT);
276 return result == 0 || inProgress;
277 }
278 else
279 {
280 inProgress = false;
281 return wait();
282 }
283 }
284
285 inline bool signal()
286 {
287 return pthread_cond_broadcast(hEvent) == 0;
288 }
289
290 inline operator bool() const
291 {
292 return hEvent != NULL;
293 }
294
295 private:
296
297 Event(Event const &) :
298 Mutex(),
299 hEvent(NULL)
300 {
301 // we only support move construction (no copy-construction)
302 }
303 };
304
305 #endif
306
307 template <>
308 struct HasMoveConstructor<Event> : True {};
309
310 //////////////////////////////////////////////////////////////////////////////
311 // global event functions
312
313 inline bool open(Event & e, bool initial)
314 {
315 return e.open(initial);
316 }
317
318 inline bool open(Event & e)
319 {
320 return open(e, false);
321 }
322
323 inline bool close(Event & e)
324 {
325 return e.close();
326 }
327
328 inline bool waitFor(Event & e)
329 {
330 return e.wait();
331 }
332
333 template <typename TTime>
334 inline bool waitFor(Event & e, TTime timeoutMilliSec, bool & inProgress)
335 {
336 #ifdef disabledSEQAN_PROFILE
337 double begin = sysTime();
338 bool b = e.wait(timeoutMilliSec, inProgress);
339 double end = sysTime();
340 if (begin != end)
341 std::cerr << "waitTime: " << end - begin << std::endl;
342 return b;
343
344 #else
345 return e.wait(timeoutMilliSec, inProgress);
346
347 #endif
348 }
349
350 inline bool signal(Event & e)
351 {
352 return e.signal();
353 }
354
355 /*
356 //////////////////////////////////////////////////////////////////////////////
357 // emulate events in a singlethreaded environment
358
359 struct DummyEvent {
360 typedef void Handle;
361 DummyEvent(bool initial = false) {}
362 inline bool wait(unsigned timeOut = NULL) { return true; }
363 inline void reset() {}
364 inline void signal() {}
365 };
366
367 //////////////////////////////////////////////////////////////////////////////
368 // global dummy event functions
369
370 template < typename TCount >
371 inline bool waitForAll(DummyEvent eventList[], TCount count) {
372 return true;
373 }
374
375 template < typename TCount, typename TTime >
376 inline bool waitForAll(DummyEvent eventList[], TCount count, TTime timeoutMilliSec) {
377 return true;
378 }
379
380 template < typename TCount >
381 inline TCount waitForAny(DummyEvent eventList[], TCount count) {
382 return 0;
383 }
384 template < typename TCount, typename TTime >
385 inline TCount waitForAny(DummyEvent eventList[], TCount count, TTime timeoutMilliSec) {
386 return 0;
387 }
388 */
389 }
390
391 #endif
392