/[svn]/linuxsampler/trunk/src/common/Condition.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/common/Condition.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1560 - (hide annotations) (download)
Thu Dec 6 17:19:16 2007 UTC (16 years, 4 months ago) by schoenebeck
File size: 16474 byte(s)
* minor code refactoring of win32 Condition code
* preparations for release 0.5.1

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 1221 * Copyright (C) 2005 - 2007 Christian Schoenebeck *
7 schoenebeck 53 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24 persson 417 #include <sys/time.h>
25    
26 schoenebeck 53 #include "Condition.h"
27    
28 schoenebeck 1424 #include "global_private.h"
29 schoenebeck 63
30 schoenebeck 1560 namespace LinuxSampler {
31    
32     // *************** Internal data types (for Windows only) ***************
33     // *
34    
35 senoner 1481 #if defined(WIN32)
36 schoenebeck 1560
37     typedef HANDLE win32thread_mutex_t;
38    
39 senoner 1481 //NOTE: since pthread_condattr_t is not needed in the Condition class so just set it to int
40     typedef int win32thread_condattr_t;
41    
42     typedef struct {
43 schoenebeck 1560 unsigned long tv_sec;
44     unsigned long tv_nsec;
45     } win32_timespec;
46 senoner 1481
47    
48 schoenebeck 1560
49     // *************** ConditionInternal (for Windows only) ***************
50     // *
51    
52     class ConditionInternal {
53     public:
54    
55     static
56     int win32thread_cond_init (Condition::win32thread_cond_t *cv, const win32thread_condattr_t *)
57 senoner 1481 {
58     dmsg(7,("win32thread_cond_init:\n"));
59     cv->waiters_count_ = 0;
60     cv->was_broadcast_ = 0;
61     cv->sema_ = CreateSemaphore (NULL, // no security
62     0, // initially 0
63     0x7fffffff, // max count
64 schoenebeck 1560 NULL); // unnamed
65     dmsg(7,("win32thread_cond_init: after CreateSemaphore retval=%d\n",cv->sema_));
66 senoner 1481 InitializeCriticalSection (&cv->waiters_count_lock_);
67     cv->waiters_done_ = CreateEvent (NULL, // no security
68     FALSE, // auto-reset
69     FALSE, // non-signaled initially
70     NULL); // unnamed
71 schoenebeck 1560 dmsg(7,("win32thread_cond_init: after CreateEvent retval=%d\n",cv->waiters_done_));
72    
73 senoner 1481 return 0;
74     }
75    
76 schoenebeck 1560 static
77     int win32thread_cond_destroy(Condition::win32thread_cond_t *cv) {
78     dmsg(7,("win32thread_cond_destroy ptr=%d\n",cv));
79 senoner 1481 CloseHandle(cv->waiters_done_);
80     DeleteCriticalSection(&cv->waiters_count_lock_);
81     CloseHandle(cv->sema_);
82     return 0;
83     }
84    
85 schoenebeck 1560 static
86     int win32thread_cond_timedwait (Condition::win32thread_cond_t *cv, win32thread_mutex_t *external_mutex, win32_timespec *timeout)
87 senoner 1481 {
88 schoenebeck 1560 dmsg(7,("win32thread_cond_timedwait: external mutex=%d BEGIN!\n",external_mutex));
89 senoner 1481 // Avoid race conditions.
90     dmsg(7,("win32thread_cond_timedwait: before EnterCriticalSection (&cv->waiters_count_lock_) cv->waiters_count_=%d\n",cv->waiters_count_));
91     EnterCriticalSection (&cv->waiters_count_lock_);
92     cv->waiters_count_++;
93     LeaveCriticalSection (&cv->waiters_count_lock_);
94     dmsg(7,("win32thread_cond_timedwait: after LeaveCriticalSection (&cv->waiters_count_lock_) cv->waiters_count_=%d\n",cv->waiters_count_));
95    
96 schoenebeck 1560
97 senoner 1481 // This call atomically releases the mutex and waits on the
98     // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
99     // are called by another thread.
100 schoenebeck 1560
101 senoner 1481 DWORD dwMilliseconds;
102     if(timeout->tv_sec || timeout->tv_nsec) {
103     dwMilliseconds = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000;
104     }
105     else {
106     dmsg(7,("win32thread_cond_timedwait: dwMilliseconds = INFINITE\n"));
107     dwMilliseconds = INFINITE;
108     }
109     dmsg(7,("win32thread_cond_timedwait: before SignalObjectAndWait(*external_mutex, cv->sema_, dwMilliseconds, FALSE), dwMilliseconds=%d\n",dwMilliseconds));
110     DWORD res;
111     res = SignalObjectAndWait (*external_mutex, cv->sema_, dwMilliseconds, FALSE);
112     dmsg(7,("win32thread_cond_timedwait: after SignalObjectAndWait, res=%d\n",res));
113 schoenebeck 1560 if(res == WAIT_TIMEOUT) return -1;
114 senoner 1481
115     // Reacquire lock to avoid race conditions.
116 schoenebeck 1560 dmsg(7,("win32thread_cond_timedwait: before EnterCriticalSection (2) (&cv->waiters_count_lock_) cv->waiters_count=%d\n",cv->waiters_count_));
117 senoner 1481 EnterCriticalSection (&cv->waiters_count_lock_);
118 schoenebeck 1560 dmsg(7,("win32thread_cond_timedwait: after EnterCriticalSection (2) (&cv->waiters_count_lock_) cv->waiters_count=%d\n",cv->waiters_count_));
119 senoner 1481
120     // We're no longer waiting...
121     cv->waiters_count_--;
122    
123     // Check to see if we're the last waiter after <pthread_cond_broadcast>.
124     int last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0;
125    
126     LeaveCriticalSection (&cv->waiters_count_lock_);
127 schoenebeck 1560 dmsg(7,("win32thread_cond_timedwait: after LeaveCriticalSection (2) (&cv->waiters_count_lock_) last_waiter=%d\n",last_waiter));
128 senoner 1481
129     // If we're the last waiter thread during this particular broadcast
130     // then let all the other threads proceed.
131     if (last_waiter) {
132     // This call atomically signals the <waiters_done_> event and waits until
133 schoenebeck 1560 // it can acquire the <external_mutex>. This is required to ensure fairness.
134 senoner 1481 dmsg(7,("win32thread_cond_timedwait: before SignalObjectAndWait (cv->waiters_done_, *external_mutex, dwMilliseconds, FALSE) \n"));
135     res = SignalObjectAndWait (cv->waiters_done_, *external_mutex, dwMilliseconds, FALSE);
136     dmsg(7,("win32thread_cond_timedwait: after SignalObjectAndWait (cv->waiters_done_, *external_mutex, dwMilliseconds, FALSE) res=%d\n",res));
137     if(res == WAIT_TIMEOUT) {
138     dmsg(7,("win32thread_cond_timedwait: after SignalObjectAndWait: WAIT_TIMEOUT! returning -1\n"));
139     return -1;
140     }
141     }
142     else {
143     // Always regain the external mutex since that's the guarantee we
144 schoenebeck 1560 // give to our callers.
145 senoner 1481 dmsg(7,("win32thread_cond_timedwait: before WaitForSingleObject (*external_mutex, dwMilliseconds)\n"));
146     res = WaitForSingleObject (*external_mutex, dwMilliseconds);
147     dmsg(7,("win32thread_cond_timedwait: after WaitForSingleObject (*external_mutex, dwMilliseconds) res=%d\n",res));
148     if(res == WAIT_TIMEOUT) {
149     dmsg(7,("win32thread_cond_timedwait: after WaitForSingleObject: WAIT_TIMEOUT ! returning -1\n"));
150     return -1;
151     }
152     }
153     dmsg(7,("win32thread_cond_timedwait: all OK. returning 0\n"));
154     return 0;
155     }
156    
157 schoenebeck 1560 static
158     int win32thread_cond_broadcast (Condition::win32thread_cond_t *cv)
159 senoner 1481 {
160     DWORD res;
161     dmsg(7,("win32thread_cond_broadcast: cv=%d\n",cv));
162     dmsg(7,("win32thread_cond_broadcast: before EnterCriticalSection (&cv->waiters_count_lock_)\n"));
163     // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
164     // consistent relative to each other.
165     EnterCriticalSection (&cv->waiters_count_lock_);
166     int have_waiters = 0;
167    
168     dmsg(7,("win32thread_cond_broadcast: cv->waiters_count_=%d\n",cv->waiters_count_));
169     if (cv->waiters_count_ > 0) {
170     dmsg(7,("win32thread_cond_broadcast: cv->waiters_count > 0 !\n"));
171     // We are broadcasting, even if there is just one waiter...
172     // Record that we are broadcasting, which helps optimize
173     // <pthread_cond_wait> for the non-broadcast case.
174     cv->was_broadcast_ = 1;
175     have_waiters = 1;
176     }
177     dmsg(7,("win32thread_cond_broadcast: cv->was_broadcast_=%d have_waiters=%d\n",cv->was_broadcast_,have_waiters));
178    
179     if (have_waiters) {
180     // Wake up all the waiters atomically.
181     dmsg(7,("win32thread_cond_broadcast: have_waiters ! before ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0);\n"));
182     ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0);
183    
184     LeaveCriticalSection (&cv->waiters_count_lock_);
185     dmsg(7,("win32thread_cond_broadcast: have_waiters ! after LeaveCriticalSection (&cv->waiters_count_lock_)\n"));
186    
187     // Wait for all the awakened threads to acquire the counting
188 schoenebeck 1560 // semaphore.
189 senoner 1481 dmsg(7,("win32thread_cond_broadcast: before WaitForSingleObject (cv->waiters_done_, INFINITE)\n"));
190     res = WaitForSingleObject (cv->waiters_done_, INFINITE);
191     dmsg(7,("win32thread_cond_broadcast: after WaitForSingleObject (cv->waiters_done_, INFINITE) res=%d\n",res));
192 schoenebeck 1560 // This assignment is okay, even without the <waiters_count_lock_> held
193 senoner 1481 // because no other waiter threads can wake up to access it.
194     cv->was_broadcast_ = 0;
195     }
196     else {
197     LeaveCriticalSection (&cv->waiters_count_lock_);
198     dmsg(7,("win32thread_cond_broadcast: after LeaveCriticalSection (&cv->waiters_count_lock_)\n"));
199     }
200 schoenebeck 1560 dmsg(7,("win32thread_cond_broadcast: all OK, returning 0.\n"));
201 senoner 1481 return 0;
202     }
203    
204 schoenebeck 1560 /* TODO: the following two functions are currently not used yet
205     static
206     int win32thread_cond_signal (Condition::win32thread_cond_t *cv)
207     {
208 senoner 1481
209 schoenebeck 1560 dmsg(7,("win32thread_cond_signal cv=%d\n",cv));
210     dmsg(7,("win32thread_cond_signal before EnterCriticalSection (&cv->waiters_count_lock_)\n"));
211     EnterCriticalSection (&cv->waiters_count_lock_);
212     int have_waiters = cv->waiters_count_ > 0;
213     LeaveCriticalSection (&cv->waiters_count_lock_);
214     dmsg(7,("win32thread_cond_signal after LeaveCriticalSection (&cv->waiters_count_lock_)\n"));
215 senoner 1481
216 schoenebeck 1560 dmsg(7,("win32thread_cond_signal have_waiters=%d\n",have_waiters));
217     // If there aren't any waiters, then this is a no-op.
218     if (have_waiters) {
219     dmsg(7,("win32thread_cond have_waiters is TRUE, before ReleaseSemaphore (cv->sema_, 1, 0)\n"));
220     ReleaseSemaphore (cv->sema_, 1, 0);
221     }
222     dmsg(7,("win32thread_cond_signal: all OK. returning 0\n"));
223     return 0;
224     }
225 senoner 1481
226 schoenebeck 1560 static
227     int win32thread_cond_wait (Condition::win32thread_cond_t *cv, win32thread_mutex_t *external_mutex) {
228     dmsg(7,("win32thread_cond_wait: (calls win32thread_cond_timedwait) cv=%d external_mutex=%d\n",cv, external_mutex));
229     win32_timespec timeout;
230     timeout.tv_sec = 0;
231     timeout.tv_nsec = 0;
232     return win32thread_cond_timedwait (cv, external_mutex, &timeout);
233     }
234     */
235 senoner 1481
236 schoenebeck 1560 }; // class ConditionInternal
237 schoenebeck 880
238 schoenebeck 1560 #endif // WIN32
239    
240    
241    
242     // *************** Condition ***************
243     // *
244    
245 schoenebeck 53 Condition::Condition(bool bInitialCondition) {
246 senoner 1481 dmsg(7,("Condition:: constructor, bInitialCondition=%d\n", bInitialCondition));
247     #if defined(WIN32)
248 schoenebeck 1560 ConditionInternal::win32thread_cond_init(&__win32_true_condition, NULL);
249     ConditionInternal::win32thread_cond_init(&__win32_false_condition, NULL);
250 senoner 1481 #else
251 schoenebeck 53 pthread_cond_init(&__posix_true_condition, NULL);
252     pthread_cond_init(&__posix_false_condition, NULL);
253 schoenebeck 1560 #endif
254 schoenebeck 53 bCondition = bInitialCondition;
255     }
256    
257     Condition::~Condition() {
258 senoner 1481 #if defined(WIN32)
259 schoenebeck 1560 ConditionInternal::win32thread_cond_destroy(&__win32_true_condition);
260     ConditionInternal::win32thread_cond_destroy(&__win32_false_condition);
261 senoner 1481 #else
262 schoenebeck 53 pthread_cond_destroy(&__posix_true_condition);
263     pthread_cond_destroy(&__posix_false_condition);
264 senoner 1481 #endif
265 schoenebeck 53 }
266    
267     int Condition::WaitIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
268 senoner 1481 dmsg(7,("Condition::WaitIf: bCondition=%d TimeoutSeconds=%d TimeoutNanoSeconds=%d\n",bCondition, TimeoutSeconds, TimeoutNanoSeconds));
269 schoenebeck 63 dmsg(7,("Condition::Waitif() -> LOCK()\n"));
270 schoenebeck 53 Lock();
271 schoenebeck 63 dmsg(7,("Condition::Waitif() -> LOCK() passed\n"));
272 schoenebeck 53 int res = 0;
273     if (this->bCondition == bCondition) {
274 schoenebeck 63 if (bCondition) { // wait until condition turned 'false'
275 senoner 1481 #if defined(WIN32)
276     win32_timespec timeout;
277     timeout.tv_sec = TimeoutSeconds;
278     timeout.tv_nsec = TimeoutNanoSeconds;
279     dmsg(7,("Condition::Waitif() -> waiting for 'false' condition with timeout\n"));
280 schoenebeck 1560 res = ConditionInternal::win32thread_cond_timedwait(&__win32_false_condition, &hMutex, &timeout);
281 senoner 1481 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
282     #else
283 schoenebeck 63 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
284 persson 417 struct timeval now;
285     gettimeofday(&now, 0);
286 schoenebeck 53 timespec timeout;
287 persson 417 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
288     timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
289 schoenebeck 63 dmsg(7,("Condition::Waitif() -> waiting for 'false' condition with timeout\n"));
290 schoenebeck 53 res = pthread_cond_timedwait(&__posix_false_condition, &__posix_mutex, &timeout);
291 schoenebeck 63 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
292 schoenebeck 53 }
293 schoenebeck 63 else { // wait without timeout
294     dmsg(7,("Condition::Waitif() -> waiting for 'false' condition\n"));
295     pthread_cond_wait(&__posix_false_condition, &__posix_mutex);
296     dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
297     }
298 senoner 1481 #endif
299 schoenebeck 53 }
300 schoenebeck 63 else { // wait until condition turned 'true'
301 senoner 1481 #if defined(WIN32)
302     win32_timespec timeout;
303     timeout.tv_sec = TimeoutSeconds;
304     timeout.tv_nsec = TimeoutNanoSeconds;
305     dmsg(7,("Condition::Waitif() -> waiting for 'true' condition with timeout\n"));
306 schoenebeck 1560 res = ConditionInternal::win32thread_cond_timedwait(&__win32_true_condition, &hMutex, &timeout);
307 senoner 1481 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
308     #else
309 schoenebeck 63 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
310 persson 417 struct timeval now;
311     gettimeofday(&now, 0);
312 schoenebeck 53 timespec timeout;
313 persson 417 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
314     timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
315 schoenebeck 63 dmsg(7,("Condition::Waitif() -> waiting for 'true' condition with timeout\n"));
316 schoenebeck 53 res = pthread_cond_timedwait(&__posix_true_condition, &__posix_mutex, &timeout);
317 schoenebeck 63 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
318 schoenebeck 53 }
319 schoenebeck 63 else { // wait without timeout
320     dmsg(7,("Condition::Waitif() -> waiting for 'true' condition\n"));
321     pthread_cond_wait(&__posix_true_condition, &__posix_mutex);
322     dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
323     }
324 senoner 1481 #endif
325 schoenebeck 53 }
326     }
327     return res;
328     }
329    
330     int Condition::WaitAndUnlockIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
331     int res = WaitIf(bCondition, TimeoutSeconds, TimeoutNanoSeconds);
332 schoenebeck 63 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK()\n"));
333 schoenebeck 53 Unlock();
334 schoenebeck 63 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK() passed\n"));
335 schoenebeck 53 return res;
336     }
337    
338     void Condition::Set(bool bCondition) {
339 schoenebeck 63 dmsg(7,("Condition::Set() -> LOCK()\n"));
340 schoenebeck 53 Lock();
341 schoenebeck 63 dmsg(7,("Condition::Set() -> LOCK() passed\n"));
342 schoenebeck 53 if (this->bCondition != bCondition) {
343     this->bCondition = bCondition;
344 schoenebeck 63 if (bCondition) {
345     dmsg(7,("Condition::Set() -> broadcasting 'true' condition\n"));
346 senoner 1481 #if defined(WIN32)
347     win32thread_cond_broadcast(&__win32_true_condition);
348     #else
349 schoenebeck 63 pthread_cond_broadcast(&__posix_true_condition);
350 senoner 1481 #endif
351 schoenebeck 63 }
352     else {
353     dmsg(7,("Condition::Set() -> broadcasting 'false' condition\n"));
354 senoner 1481 #if defined(WIN32)
355     win32thread_cond_broadcast(&__win32_false_condition);
356     #else
357 schoenebeck 63 pthread_cond_broadcast(&__posix_false_condition);
358 senoner 1481 #endif
359 schoenebeck 63 }
360 schoenebeck 53 }
361 schoenebeck 63 Unlock();
362 schoenebeck 53 }
363 schoenebeck 880
364 schoenebeck 1221 bool Condition::GetUnsafe() {
365     return bCondition;
366     }
367    
368 schoenebeck 880 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC