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