/[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 2427 - (hide annotations) (download)
Sat Mar 2 07:03:04 2013 UTC (11 years, 2 months ago) by persson
File size: 17272 byte(s)
* code refactoring: added a lock guard class for exception safe mutex
  handling and used it everywhere appropriate

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 persson 2427 * Copyright (C) 2005 - 2013 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 nagata 1649 #if CONFIG_PTHREAD_TESTCANCEL
31     #include "Thread.h"
32     #endif
33    
34 schoenebeck 1560 namespace LinuxSampler {
35    
36     // *************** Internal data types (for Windows only) ***************
37     // *
38    
39 senoner 1481 #if defined(WIN32)
40 schoenebeck 1560
41     typedef HANDLE win32thread_mutex_t;
42    
43 senoner 1481 //NOTE: since pthread_condattr_t is not needed in the Condition class so just set it to int
44     typedef int win32thread_condattr_t;
45    
46     typedef struct {
47 schoenebeck 1560 unsigned long tv_sec;
48     unsigned long tv_nsec;
49     } win32_timespec;
50 senoner 1481
51    
52 schoenebeck 1560
53     // *************** ConditionInternal (for Windows only) ***************
54     // *
55    
56     class ConditionInternal {
57     public:
58    
59     static
60     int win32thread_cond_init (Condition::win32thread_cond_t *cv, const win32thread_condattr_t *)
61 senoner 1481 {
62     dmsg(7,("win32thread_cond_init:\n"));
63     cv->waiters_count_ = 0;
64     cv->was_broadcast_ = 0;
65     cv->sema_ = CreateSemaphore (NULL, // no security
66     0, // initially 0
67     0x7fffffff, // max count
68 schoenebeck 1560 NULL); // unnamed
69     dmsg(7,("win32thread_cond_init: after CreateSemaphore retval=%d\n",cv->sema_));
70 senoner 1481 InitializeCriticalSection (&cv->waiters_count_lock_);
71     cv->waiters_done_ = CreateEvent (NULL, // no security
72     FALSE, // auto-reset
73     FALSE, // non-signaled initially
74     NULL); // unnamed
75 schoenebeck 1560 dmsg(7,("win32thread_cond_init: after CreateEvent retval=%d\n",cv->waiters_done_));
76    
77 senoner 1481 return 0;
78     }
79    
80 schoenebeck 1560 static
81     int win32thread_cond_destroy(Condition::win32thread_cond_t *cv) {
82     dmsg(7,("win32thread_cond_destroy ptr=%d\n",cv));
83 senoner 1481 CloseHandle(cv->waiters_done_);
84     DeleteCriticalSection(&cv->waiters_count_lock_);
85     CloseHandle(cv->sema_);
86     return 0;
87     }
88    
89 schoenebeck 1560 static
90     int win32thread_cond_timedwait (Condition::win32thread_cond_t *cv, win32thread_mutex_t *external_mutex, win32_timespec *timeout)
91 senoner 1481 {
92 schoenebeck 1560 dmsg(7,("win32thread_cond_timedwait: external mutex=%d BEGIN!\n",external_mutex));
93 senoner 1481 // Avoid race conditions.
94     dmsg(7,("win32thread_cond_timedwait: before EnterCriticalSection (&cv->waiters_count_lock_) cv->waiters_count_=%d\n",cv->waiters_count_));
95     EnterCriticalSection (&cv->waiters_count_lock_);
96     cv->waiters_count_++;
97     LeaveCriticalSection (&cv->waiters_count_lock_);
98     dmsg(7,("win32thread_cond_timedwait: after LeaveCriticalSection (&cv->waiters_count_lock_) cv->waiters_count_=%d\n",cv->waiters_count_));
99    
100 schoenebeck 1560
101 senoner 1481 // This call atomically releases the mutex and waits on the
102     // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
103     // are called by another thread.
104 schoenebeck 1560
105 senoner 1481 DWORD dwMilliseconds;
106     if(timeout->tv_sec || timeout->tv_nsec) {
107     dwMilliseconds = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000;
108     }
109     else {
110     dmsg(7,("win32thread_cond_timedwait: dwMilliseconds = INFINITE\n"));
111     dwMilliseconds = INFINITE;
112     }
113     dmsg(7,("win32thread_cond_timedwait: before SignalObjectAndWait(*external_mutex, cv->sema_, dwMilliseconds, FALSE), dwMilliseconds=%d\n",dwMilliseconds));
114     DWORD res;
115     res = SignalObjectAndWait (*external_mutex, cv->sema_, dwMilliseconds, FALSE);
116     dmsg(7,("win32thread_cond_timedwait: after SignalObjectAndWait, res=%d\n",res));
117 schoenebeck 1560 if(res == WAIT_TIMEOUT) return -1;
118 senoner 1481
119     // Reacquire lock to avoid race conditions.
120 schoenebeck 1560 dmsg(7,("win32thread_cond_timedwait: before EnterCriticalSection (2) (&cv->waiters_count_lock_) cv->waiters_count=%d\n",cv->waiters_count_));
121 senoner 1481 EnterCriticalSection (&cv->waiters_count_lock_);
122 schoenebeck 1560 dmsg(7,("win32thread_cond_timedwait: after EnterCriticalSection (2) (&cv->waiters_count_lock_) cv->waiters_count=%d\n",cv->waiters_count_));
123 senoner 1481
124     // We're no longer waiting...
125     cv->waiters_count_--;
126    
127     // Check to see if we're the last waiter after <pthread_cond_broadcast>.
128     int last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0;
129    
130     LeaveCriticalSection (&cv->waiters_count_lock_);
131 schoenebeck 1560 dmsg(7,("win32thread_cond_timedwait: after LeaveCriticalSection (2) (&cv->waiters_count_lock_) last_waiter=%d\n",last_waiter));
132 senoner 1481
133     // If we're the last waiter thread during this particular broadcast
134     // then let all the other threads proceed.
135     if (last_waiter) {
136     // This call atomically signals the <waiters_done_> event and waits until
137 schoenebeck 1560 // it can acquire the <external_mutex>. This is required to ensure fairness.
138 senoner 1481 dmsg(7,("win32thread_cond_timedwait: before SignalObjectAndWait (cv->waiters_done_, *external_mutex, dwMilliseconds, FALSE) \n"));
139     res = SignalObjectAndWait (cv->waiters_done_, *external_mutex, dwMilliseconds, FALSE);
140     dmsg(7,("win32thread_cond_timedwait: after SignalObjectAndWait (cv->waiters_done_, *external_mutex, dwMilliseconds, FALSE) res=%d\n",res));
141     if(res == WAIT_TIMEOUT) {
142     dmsg(7,("win32thread_cond_timedwait: after SignalObjectAndWait: WAIT_TIMEOUT! returning -1\n"));
143     return -1;
144     }
145     }
146     else {
147     // Always regain the external mutex since that's the guarantee we
148 schoenebeck 1560 // give to our callers.
149 senoner 1481 dmsg(7,("win32thread_cond_timedwait: before WaitForSingleObject (*external_mutex, dwMilliseconds)\n"));
150     res = WaitForSingleObject (*external_mutex, dwMilliseconds);
151     dmsg(7,("win32thread_cond_timedwait: after WaitForSingleObject (*external_mutex, dwMilliseconds) res=%d\n",res));
152     if(res == WAIT_TIMEOUT) {
153     dmsg(7,("win32thread_cond_timedwait: after WaitForSingleObject: WAIT_TIMEOUT ! returning -1\n"));
154     return -1;
155     }
156     }
157     dmsg(7,("win32thread_cond_timedwait: all OK. returning 0\n"));
158     return 0;
159     }
160    
161 schoenebeck 1560 static
162     int win32thread_cond_broadcast (Condition::win32thread_cond_t *cv)
163 senoner 1481 {
164     DWORD res;
165     dmsg(7,("win32thread_cond_broadcast: cv=%d\n",cv));
166     dmsg(7,("win32thread_cond_broadcast: before EnterCriticalSection (&cv->waiters_count_lock_)\n"));
167     // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
168     // consistent relative to each other.
169     EnterCriticalSection (&cv->waiters_count_lock_);
170     int have_waiters = 0;
171    
172     dmsg(7,("win32thread_cond_broadcast: cv->waiters_count_=%d\n",cv->waiters_count_));
173     if (cv->waiters_count_ > 0) {
174     dmsg(7,("win32thread_cond_broadcast: cv->waiters_count > 0 !\n"));
175     // We are broadcasting, even if there is just one waiter...
176     // Record that we are broadcasting, which helps optimize
177     // <pthread_cond_wait> for the non-broadcast case.
178     cv->was_broadcast_ = 1;
179     have_waiters = 1;
180     }
181     dmsg(7,("win32thread_cond_broadcast: cv->was_broadcast_=%d have_waiters=%d\n",cv->was_broadcast_,have_waiters));
182    
183     if (have_waiters) {
184     // Wake up all the waiters atomically.
185     dmsg(7,("win32thread_cond_broadcast: have_waiters ! before ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0);\n"));
186     ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0);
187    
188     LeaveCriticalSection (&cv->waiters_count_lock_);
189     dmsg(7,("win32thread_cond_broadcast: have_waiters ! after LeaveCriticalSection (&cv->waiters_count_lock_)\n"));
190    
191     // Wait for all the awakened threads to acquire the counting
192 schoenebeck 1560 // semaphore.
193 senoner 1481 dmsg(7,("win32thread_cond_broadcast: before WaitForSingleObject (cv->waiters_done_, INFINITE)\n"));
194     res = WaitForSingleObject (cv->waiters_done_, INFINITE);
195     dmsg(7,("win32thread_cond_broadcast: after WaitForSingleObject (cv->waiters_done_, INFINITE) res=%d\n",res));
196 schoenebeck 1560 // This assignment is okay, even without the <waiters_count_lock_> held
197 senoner 1481 // because no other waiter threads can wake up to access it.
198     cv->was_broadcast_ = 0;
199     }
200     else {
201     LeaveCriticalSection (&cv->waiters_count_lock_);
202     dmsg(7,("win32thread_cond_broadcast: after LeaveCriticalSection (&cv->waiters_count_lock_)\n"));
203     }
204 schoenebeck 1560 dmsg(7,("win32thread_cond_broadcast: all OK, returning 0.\n"));
205 senoner 1481 return 0;
206     }
207    
208 schoenebeck 1560 /* TODO: the following two functions are currently not used yet
209     static
210     int win32thread_cond_signal (Condition::win32thread_cond_t *cv)
211     {
212 senoner 1481
213 schoenebeck 1560 dmsg(7,("win32thread_cond_signal cv=%d\n",cv));
214     dmsg(7,("win32thread_cond_signal before EnterCriticalSection (&cv->waiters_count_lock_)\n"));
215     EnterCriticalSection (&cv->waiters_count_lock_);
216     int have_waiters = cv->waiters_count_ > 0;
217     LeaveCriticalSection (&cv->waiters_count_lock_);
218     dmsg(7,("win32thread_cond_signal after LeaveCriticalSection (&cv->waiters_count_lock_)\n"));
219 senoner 1481
220 schoenebeck 1560 dmsg(7,("win32thread_cond_signal have_waiters=%d\n",have_waiters));
221     // If there aren't any waiters, then this is a no-op.
222     if (have_waiters) {
223     dmsg(7,("win32thread_cond have_waiters is TRUE, before ReleaseSemaphore (cv->sema_, 1, 0)\n"));
224     ReleaseSemaphore (cv->sema_, 1, 0);
225     }
226     dmsg(7,("win32thread_cond_signal: all OK. returning 0\n"));
227     return 0;
228     }
229 senoner 1481
230 schoenebeck 1560 static
231     int win32thread_cond_wait (Condition::win32thread_cond_t *cv, win32thread_mutex_t *external_mutex) {
232     dmsg(7,("win32thread_cond_wait: (calls win32thread_cond_timedwait) cv=%d external_mutex=%d\n",cv, external_mutex));
233     win32_timespec timeout;
234     timeout.tv_sec = 0;
235     timeout.tv_nsec = 0;
236     return win32thread_cond_timedwait (cv, external_mutex, &timeout);
237     }
238     */
239 senoner 1481
240 schoenebeck 1560 }; // class ConditionInternal
241 schoenebeck 880
242 schoenebeck 1560 #endif // WIN32
243    
244    
245    
246     // *************** Condition ***************
247     // *
248    
249 schoenebeck 53 Condition::Condition(bool bInitialCondition) {
250 senoner 1481 dmsg(7,("Condition:: constructor, bInitialCondition=%d\n", bInitialCondition));
251     #if defined(WIN32)
252 schoenebeck 1560 ConditionInternal::win32thread_cond_init(&__win32_true_condition, NULL);
253     ConditionInternal::win32thread_cond_init(&__win32_false_condition, NULL);
254 senoner 1481 #else
255 schoenebeck 53 pthread_cond_init(&__posix_true_condition, NULL);
256     pthread_cond_init(&__posix_false_condition, NULL);
257 schoenebeck 1560 #endif
258 schoenebeck 53 bCondition = bInitialCondition;
259     }
260    
261     Condition::~Condition() {
262 senoner 1481 #if defined(WIN32)
263 schoenebeck 1560 ConditionInternal::win32thread_cond_destroy(&__win32_true_condition);
264     ConditionInternal::win32thread_cond_destroy(&__win32_false_condition);
265 senoner 1481 #else
266 schoenebeck 53 pthread_cond_destroy(&__posix_true_condition);
267     pthread_cond_destroy(&__posix_false_condition);
268 senoner 1481 #endif
269 schoenebeck 53 }
270    
271 persson 2324 #ifndef WIN32
272     namespace {
273     // If the thread is cancelled while waiting for the condition
274     // variable, the mutex will be locked. It needs to be unlocked so
275     // the Condition can be reused if the thread is restarted.
276     void condition_cleanup(void* c) {
277     static_cast<Condition*>(c)->Unlock();
278     }
279     }
280     #endif
281    
282 schoenebeck 53 int Condition::WaitIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
283 senoner 1481 dmsg(7,("Condition::WaitIf: bCondition=%d TimeoutSeconds=%d TimeoutNanoSeconds=%d\n",bCondition, TimeoutSeconds, TimeoutNanoSeconds));
284 schoenebeck 63 dmsg(7,("Condition::Waitif() -> LOCK()\n"));
285 schoenebeck 53 Lock();
286 schoenebeck 63 dmsg(7,("Condition::Waitif() -> LOCK() passed\n"));
287 schoenebeck 53 int res = 0;
288 persson 2324 #ifndef WIN32
289     pthread_cleanup_push(condition_cleanup, this);
290     #endif
291 schoenebeck 53 if (this->bCondition == bCondition) {
292 schoenebeck 63 if (bCondition) { // wait until condition turned 'false'
293 senoner 1481 #if defined(WIN32)
294     win32_timespec timeout;
295     timeout.tv_sec = TimeoutSeconds;
296     timeout.tv_nsec = TimeoutNanoSeconds;
297     dmsg(7,("Condition::Waitif() -> waiting for 'false' condition with timeout\n"));
298 schoenebeck 1560 res = ConditionInternal::win32thread_cond_timedwait(&__win32_false_condition, &hMutex, &timeout);
299 senoner 1481 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
300     #else
301 schoenebeck 63 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
302 persson 417 struct timeval now;
303     gettimeofday(&now, 0);
304 schoenebeck 53 timespec timeout;
305 persson 417 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
306     timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
307 schoenebeck 63 dmsg(7,("Condition::Waitif() -> waiting for 'false' condition with timeout\n"));
308 schoenebeck 53 res = pthread_cond_timedwait(&__posix_false_condition, &__posix_mutex, &timeout);
309 schoenebeck 63 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
310 schoenebeck 53 }
311 schoenebeck 63 else { // wait without timeout
312     dmsg(7,("Condition::Waitif() -> waiting for 'false' condition\n"));
313     pthread_cond_wait(&__posix_false_condition, &__posix_mutex);
314     dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
315     }
316 senoner 1481 #endif
317 schoenebeck 53 }
318 schoenebeck 63 else { // wait until condition turned 'true'
319 senoner 1481 #if defined(WIN32)
320     win32_timespec timeout;
321     timeout.tv_sec = TimeoutSeconds;
322     timeout.tv_nsec = TimeoutNanoSeconds;
323     dmsg(7,("Condition::Waitif() -> waiting for 'true' condition with timeout\n"));
324 schoenebeck 1560 res = ConditionInternal::win32thread_cond_timedwait(&__win32_true_condition, &hMutex, &timeout);
325 senoner 1481 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
326     #else
327 schoenebeck 63 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
328 persson 417 struct timeval now;
329     gettimeofday(&now, 0);
330 schoenebeck 53 timespec timeout;
331 persson 417 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
332     timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
333 schoenebeck 63 dmsg(7,("Condition::Waitif() -> waiting for 'true' condition with timeout\n"));
334 schoenebeck 53 res = pthread_cond_timedwait(&__posix_true_condition, &__posix_mutex, &timeout);
335 schoenebeck 63 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
336 schoenebeck 53 }
337 schoenebeck 63 else { // wait without timeout
338     dmsg(7,("Condition::Waitif() -> waiting for 'true' condition\n"));
339     pthread_cond_wait(&__posix_true_condition, &__posix_mutex);
340     dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
341     }
342 senoner 1481 #endif
343 schoenebeck 53 }
344     }
345 persson 2324 #ifndef WIN32
346     pthread_cleanup_pop(0);
347     #endif
348 schoenebeck 53 return res;
349     }
350    
351     int Condition::WaitAndUnlockIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
352     int res = WaitIf(bCondition, TimeoutSeconds, TimeoutNanoSeconds);
353 schoenebeck 63 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK()\n"));
354 schoenebeck 53 Unlock();
355 schoenebeck 63 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK() passed\n"));
356 schoenebeck 53 return res;
357     }
358    
359     void Condition::Set(bool bCondition) {
360 schoenebeck 63 dmsg(7,("Condition::Set() -> LOCK()\n"));
361 persson 2427 LockGuard lock(*this);
362 schoenebeck 63 dmsg(7,("Condition::Set() -> LOCK() passed\n"));
363 schoenebeck 53 if (this->bCondition != bCondition) {
364     this->bCondition = bCondition;
365 schoenebeck 63 if (bCondition) {
366     dmsg(7,("Condition::Set() -> broadcasting 'true' condition\n"));
367 senoner 1481 #if defined(WIN32)
368 senoner 1561 ConditionInternal::win32thread_cond_broadcast(&__win32_true_condition);
369 senoner 1481 #else
370 schoenebeck 63 pthread_cond_broadcast(&__posix_true_condition);
371 senoner 1481 #endif
372 schoenebeck 63 }
373     else {
374     dmsg(7,("Condition::Set() -> broadcasting 'false' condition\n"));
375 senoner 1481 #if defined(WIN32)
376 senoner 1561 ConditionInternal::win32thread_cond_broadcast(&__win32_false_condition);
377 senoner 1481 #else
378 schoenebeck 63 pthread_cond_broadcast(&__posix_false_condition);
379 senoner 1481 #endif
380 schoenebeck 63 }
381 schoenebeck 53 }
382     }
383 schoenebeck 880
384 schoenebeck 1221 bool Condition::GetUnsafe() {
385     return bCondition;
386     }
387    
388 persson 2316 #ifdef WIN32
389     void Condition::Reset() {
390     __win32_true_condition.waiters_count_ = 0;
391     __win32_true_condition.was_broadcast_ = 0;
392     __win32_false_condition.waiters_count_ = 0;
393     __win32_false_condition.was_broadcast_ = 0;
394     }
395     #endif
396    
397 schoenebeck 880 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC