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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2837 - (show annotations) (download)
Sun Aug 23 06:14:00 2015 UTC (8 years, 8 months ago) by persson
File size: 17274 byte(s)
* fixed printf type errors (mostly in debug messages)


1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2015 Christian Schoenebeck *
7 * *
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 #include <sys/time.h>
25
26 #include "Condition.h"
27
28 #include "global_private.h"
29
30 #if CONFIG_PTHREAD_TESTCANCEL
31 #include "Thread.h"
32 #endif
33
34 namespace LinuxSampler {
35
36 // *************** Internal data types (for Windows only) ***************
37 // *
38
39 #if defined(WIN32)
40
41 typedef HANDLE win32thread_mutex_t;
42
43 //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 unsigned long tv_sec;
48 unsigned long tv_nsec;
49 } win32_timespec;
50
51
52
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 {
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 NULL); // unnamed
69 dmsg(7,("win32thread_cond_init: after CreateSemaphore retval=%d\n",cv->sema_));
70 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 dmsg(7,("win32thread_cond_init: after CreateEvent retval=%d\n",cv->waiters_done_));
76
77 return 0;
78 }
79
80 static
81 int win32thread_cond_destroy(Condition::win32thread_cond_t *cv) {
82 dmsg(7,("win32thread_cond_destroy ptr=%d\n",cv));
83 CloseHandle(cv->waiters_done_);
84 DeleteCriticalSection(&cv->waiters_count_lock_);
85 CloseHandle(cv->sema_);
86 return 0;
87 }
88
89 static
90 int win32thread_cond_timedwait (Condition::win32thread_cond_t *cv, win32thread_mutex_t *external_mutex, win32_timespec *timeout)
91 {
92 dmsg(7,("win32thread_cond_timedwait: external mutex=%d BEGIN!\n",external_mutex));
93 // 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
101 // 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
105 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 if(res == WAIT_TIMEOUT) return -1;
118
119 // Reacquire lock to avoid race conditions.
120 dmsg(7,("win32thread_cond_timedwait: before EnterCriticalSection (2) (&cv->waiters_count_lock_) cv->waiters_count=%d\n",cv->waiters_count_));
121 EnterCriticalSection (&cv->waiters_count_lock_);
122 dmsg(7,("win32thread_cond_timedwait: after EnterCriticalSection (2) (&cv->waiters_count_lock_) cv->waiters_count=%d\n",cv->waiters_count_));
123
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 dmsg(7,("win32thread_cond_timedwait: after LeaveCriticalSection (2) (&cv->waiters_count_lock_) last_waiter=%d\n",last_waiter));
132
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 // it can acquire the <external_mutex>. This is required to ensure fairness.
138 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 // give to our callers.
149 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 static
162 int win32thread_cond_broadcast (Condition::win32thread_cond_t *cv)
163 {
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 // semaphore.
193 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 // This assignment is okay, even without the <waiters_count_lock_> held
197 // 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 dmsg(7,("win32thread_cond_broadcast: all OK, returning 0.\n"));
205 return 0;
206 }
207
208 /* TODO: the following two functions are currently not used yet
209 static
210 int win32thread_cond_signal (Condition::win32thread_cond_t *cv)
211 {
212
213 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
220 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
230 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
240 }; // class ConditionInternal
241
242 #endif // WIN32
243
244
245
246 // *************** Condition ***************
247 // *
248
249 Condition::Condition(bool bInitialCondition) {
250 dmsg(7,("Condition:: constructor, bInitialCondition=%d\n", bInitialCondition));
251 #if defined(WIN32)
252 ConditionInternal::win32thread_cond_init(&__win32_true_condition, NULL);
253 ConditionInternal::win32thread_cond_init(&__win32_false_condition, NULL);
254 #else
255 pthread_cond_init(&__posix_true_condition, NULL);
256 pthread_cond_init(&__posix_false_condition, NULL);
257 #endif
258 bCondition = bInitialCondition;
259 }
260
261 Condition::~Condition() {
262 #if defined(WIN32)
263 ConditionInternal::win32thread_cond_destroy(&__win32_true_condition);
264 ConditionInternal::win32thread_cond_destroy(&__win32_false_condition);
265 #else
266 pthread_cond_destroy(&__posix_true_condition);
267 pthread_cond_destroy(&__posix_false_condition);
268 #endif
269 }
270
271 #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 int Condition::WaitIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
283 dmsg(7,("Condition::WaitIf: bCondition=%d TimeoutSeconds=%ld TimeoutNanoSeconds=%ld\n",bCondition, TimeoutSeconds, TimeoutNanoSeconds));
284 dmsg(7,("Condition::Waitif() -> LOCK()\n"));
285 Lock();
286 dmsg(7,("Condition::Waitif() -> LOCK() passed\n"));
287 int res = 0;
288 #ifndef WIN32
289 pthread_cleanup_push(condition_cleanup, this);
290 #endif
291 if (this->bCondition == bCondition) {
292 if (bCondition) { // wait until condition turned 'false'
293 #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 res = ConditionInternal::win32thread_cond_timedwait(&__win32_false_condition, &hMutex, &timeout);
299 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
300 #else
301 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
302 struct timeval now;
303 gettimeofday(&now, 0);
304 timespec timeout;
305 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
306 timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
307 dmsg(7,("Condition::Waitif() -> waiting for 'false' condition with timeout\n"));
308 res = pthread_cond_timedwait(&__posix_false_condition, &__posix_mutex, &timeout);
309 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
310 }
311 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 #endif
317 }
318 else { // wait until condition turned 'true'
319 #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 res = ConditionInternal::win32thread_cond_timedwait(&__win32_true_condition, &hMutex, &timeout);
325 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
326 #else
327 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
328 struct timeval now;
329 gettimeofday(&now, 0);
330 timespec timeout;
331 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
332 timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
333 dmsg(7,("Condition::Waitif() -> waiting for 'true' condition with timeout\n"));
334 res = pthread_cond_timedwait(&__posix_true_condition, &__posix_mutex, &timeout);
335 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
336 }
337 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 #endif
343 }
344 }
345 #ifndef WIN32
346 pthread_cleanup_pop(0);
347 #endif
348 return res;
349 }
350
351 int Condition::WaitAndUnlockIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
352 int res = WaitIf(bCondition, TimeoutSeconds, TimeoutNanoSeconds);
353 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK()\n"));
354 Unlock();
355 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK() passed\n"));
356 return res;
357 }
358
359 void Condition::Set(bool bCondition) {
360 dmsg(7,("Condition::Set() -> LOCK()\n"));
361 LockGuard lock(*this);
362 dmsg(7,("Condition::Set() -> LOCK() passed\n"));
363 if (this->bCondition != bCondition) {
364 this->bCondition = bCondition;
365 if (bCondition) {
366 dmsg(7,("Condition::Set() -> broadcasting 'true' condition\n"));
367 #if defined(WIN32)
368 ConditionInternal::win32thread_cond_broadcast(&__win32_true_condition);
369 #else
370 pthread_cond_broadcast(&__posix_true_condition);
371 #endif
372 }
373 else {
374 dmsg(7,("Condition::Set() -> broadcasting 'false' condition\n"));
375 #if defined(WIN32)
376 ConditionInternal::win32thread_cond_broadcast(&__win32_false_condition);
377 #else
378 pthread_cond_broadcast(&__posix_false_condition);
379 #endif
380 }
381 }
382 }
383
384 bool Condition::GetUnsafe() {
385 return bCondition;
386 }
387
388 #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 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC