/[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 1649 - (show annotations) (download)
Fri Jan 25 15:06:02 2008 UTC (16 years, 2 months ago) by nagata
File size: 16570 byte(s)
* added a new config option --enable-pthread-testcancel, which uses
pthread_testcancel() instead of asynchronous canceling (needed for OSX)

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2007 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 int Condition::WaitIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
272 dmsg(7,("Condition::WaitIf: bCondition=%d TimeoutSeconds=%d TimeoutNanoSeconds=%d\n",bCondition, TimeoutSeconds, TimeoutNanoSeconds));
273 dmsg(7,("Condition::Waitif() -> LOCK()\n"));
274 Lock();
275 dmsg(7,("Condition::Waitif() -> LOCK() passed\n"));
276 int res = 0;
277 if (this->bCondition == bCondition) {
278 if (bCondition) { // wait until condition turned 'false'
279 #if defined(WIN32)
280 win32_timespec timeout;
281 timeout.tv_sec = TimeoutSeconds;
282 timeout.tv_nsec = TimeoutNanoSeconds;
283 dmsg(7,("Condition::Waitif() -> waiting for 'false' condition with timeout\n"));
284 res = ConditionInternal::win32thread_cond_timedwait(&__win32_false_condition, &hMutex, &timeout);
285 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
286 #else
287 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
288 struct timeval now;
289 gettimeofday(&now, 0);
290 timespec timeout;
291 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
292 timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
293 dmsg(7,("Condition::Waitif() -> waiting for 'false' condition with timeout\n"));
294 res = pthread_cond_timedwait(&__posix_false_condition, &__posix_mutex, &timeout);
295 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
296 }
297 else { // wait without timeout
298 dmsg(7,("Condition::Waitif() -> waiting for 'false' condition\n"));
299 pthread_cond_wait(&__posix_false_condition, &__posix_mutex);
300 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
301 }
302 #endif
303 }
304 else { // wait until condition turned 'true'
305 #if defined(WIN32)
306 win32_timespec timeout;
307 timeout.tv_sec = TimeoutSeconds;
308 timeout.tv_nsec = TimeoutNanoSeconds;
309 dmsg(7,("Condition::Waitif() -> waiting for 'true' condition with timeout\n"));
310 res = ConditionInternal::win32thread_cond_timedwait(&__win32_true_condition, &hMutex, &timeout);
311 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
312 #else
313 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
314 struct timeval now;
315 gettimeofday(&now, 0);
316 timespec timeout;
317 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
318 timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
319 dmsg(7,("Condition::Waitif() -> waiting for 'true' condition with timeout\n"));
320 res = pthread_cond_timedwait(&__posix_true_condition, &__posix_mutex, &timeout);
321 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
322 }
323 else { // wait without timeout
324 dmsg(7,("Condition::Waitif() -> waiting for 'true' condition\n"));
325 pthread_cond_wait(&__posix_true_condition, &__posix_mutex);
326 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
327 }
328 #endif
329 }
330 }
331 return res;
332 }
333
334 int Condition::WaitAndUnlockIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
335 int res = WaitIf(bCondition, TimeoutSeconds, TimeoutNanoSeconds);
336 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK()\n"));
337 Unlock();
338 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK() passed\n"));
339 return res;
340 }
341
342 void Condition::Set(bool bCondition) {
343 dmsg(7,("Condition::Set() -> LOCK()\n"));
344 Lock();
345 dmsg(7,("Condition::Set() -> LOCK() passed\n"));
346 if (this->bCondition != bCondition) {
347 this->bCondition = bCondition;
348 if (bCondition) {
349 dmsg(7,("Condition::Set() -> broadcasting 'true' condition\n"));
350 #if defined(WIN32)
351 ConditionInternal::win32thread_cond_broadcast(&__win32_true_condition);
352 #else
353 pthread_cond_broadcast(&__posix_true_condition);
354 #endif
355 }
356 else {
357 dmsg(7,("Condition::Set() -> broadcasting 'false' condition\n"));
358 #if defined(WIN32)
359 ConditionInternal::win32thread_cond_broadcast(&__win32_false_condition);
360 #else
361 pthread_cond_broadcast(&__posix_false_condition);
362 #endif
363 }
364 }
365 Unlock();
366 }
367
368 bool Condition::GetUnsafe() {
369 return bCondition;
370 }
371
372 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC