/[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 1560 - (show 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 /***************************************************************************
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 namespace LinuxSampler {
31
32 // *************** Internal data types (for Windows only) ***************
33 // *
34
35 #if defined(WIN32)
36
37 typedef HANDLE win32thread_mutex_t;
38
39 //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 unsigned long tv_sec;
44 unsigned long tv_nsec;
45 } win32_timespec;
46
47
48
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 {
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 NULL); // unnamed
65 dmsg(7,("win32thread_cond_init: after CreateSemaphore retval=%d\n",cv->sema_));
66 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 dmsg(7,("win32thread_cond_init: after CreateEvent retval=%d\n",cv->waiters_done_));
72
73 return 0;
74 }
75
76 static
77 int win32thread_cond_destroy(Condition::win32thread_cond_t *cv) {
78 dmsg(7,("win32thread_cond_destroy ptr=%d\n",cv));
79 CloseHandle(cv->waiters_done_);
80 DeleteCriticalSection(&cv->waiters_count_lock_);
81 CloseHandle(cv->sema_);
82 return 0;
83 }
84
85 static
86 int win32thread_cond_timedwait (Condition::win32thread_cond_t *cv, win32thread_mutex_t *external_mutex, win32_timespec *timeout)
87 {
88 dmsg(7,("win32thread_cond_timedwait: external mutex=%d BEGIN!\n",external_mutex));
89 // 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
97 // 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
101 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 if(res == WAIT_TIMEOUT) return -1;
114
115 // Reacquire lock to avoid race conditions.
116 dmsg(7,("win32thread_cond_timedwait: before EnterCriticalSection (2) (&cv->waiters_count_lock_) cv->waiters_count=%d\n",cv->waiters_count_));
117 EnterCriticalSection (&cv->waiters_count_lock_);
118 dmsg(7,("win32thread_cond_timedwait: after EnterCriticalSection (2) (&cv->waiters_count_lock_) cv->waiters_count=%d\n",cv->waiters_count_));
119
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 dmsg(7,("win32thread_cond_timedwait: after LeaveCriticalSection (2) (&cv->waiters_count_lock_) last_waiter=%d\n",last_waiter));
128
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 // it can acquire the <external_mutex>. This is required to ensure fairness.
134 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 // give to our callers.
145 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 static
158 int win32thread_cond_broadcast (Condition::win32thread_cond_t *cv)
159 {
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 // semaphore.
189 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 // This assignment is okay, even without the <waiters_count_lock_> held
193 // 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 dmsg(7,("win32thread_cond_broadcast: all OK, returning 0.\n"));
201 return 0;
202 }
203
204 /* TODO: the following two functions are currently not used yet
205 static
206 int win32thread_cond_signal (Condition::win32thread_cond_t *cv)
207 {
208
209 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
216 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
226 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
236 }; // class ConditionInternal
237
238 #endif // WIN32
239
240
241
242 // *************** Condition ***************
243 // *
244
245 Condition::Condition(bool bInitialCondition) {
246 dmsg(7,("Condition:: constructor, bInitialCondition=%d\n", bInitialCondition));
247 #if defined(WIN32)
248 ConditionInternal::win32thread_cond_init(&__win32_true_condition, NULL);
249 ConditionInternal::win32thread_cond_init(&__win32_false_condition, NULL);
250 #else
251 pthread_cond_init(&__posix_true_condition, NULL);
252 pthread_cond_init(&__posix_false_condition, NULL);
253 #endif
254 bCondition = bInitialCondition;
255 }
256
257 Condition::~Condition() {
258 #if defined(WIN32)
259 ConditionInternal::win32thread_cond_destroy(&__win32_true_condition);
260 ConditionInternal::win32thread_cond_destroy(&__win32_false_condition);
261 #else
262 pthread_cond_destroy(&__posix_true_condition);
263 pthread_cond_destroy(&__posix_false_condition);
264 #endif
265 }
266
267 int Condition::WaitIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
268 dmsg(7,("Condition::WaitIf: bCondition=%d TimeoutSeconds=%d TimeoutNanoSeconds=%d\n",bCondition, TimeoutSeconds, TimeoutNanoSeconds));
269 dmsg(7,("Condition::Waitif() -> LOCK()\n"));
270 Lock();
271 dmsg(7,("Condition::Waitif() -> LOCK() passed\n"));
272 int res = 0;
273 if (this->bCondition == bCondition) {
274 if (bCondition) { // wait until condition turned 'false'
275 #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 res = ConditionInternal::win32thread_cond_timedwait(&__win32_false_condition, &hMutex, &timeout);
281 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
282 #else
283 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
284 struct timeval now;
285 gettimeofday(&now, 0);
286 timespec timeout;
287 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
288 timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
289 dmsg(7,("Condition::Waitif() -> waiting for 'false' condition with timeout\n"));
290 res = pthread_cond_timedwait(&__posix_false_condition, &__posix_mutex, &timeout);
291 dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
292 }
293 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 #endif
299 }
300 else { // wait until condition turned 'true'
301 #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 res = ConditionInternal::win32thread_cond_timedwait(&__win32_true_condition, &hMutex, &timeout);
307 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
308 #else
309 if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
310 struct timeval now;
311 gettimeofday(&now, 0);
312 timespec timeout;
313 timeout.tv_sec = now.tv_sec + TimeoutSeconds;
314 timeout.tv_nsec = now.tv_usec * 1000 + TimeoutNanoSeconds;
315 dmsg(7,("Condition::Waitif() -> waiting for 'true' condition with timeout\n"));
316 res = pthread_cond_timedwait(&__posix_true_condition, &__posix_mutex, &timeout);
317 dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
318 }
319 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 #endif
325 }
326 }
327 return res;
328 }
329
330 int Condition::WaitAndUnlockIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
331 int res = WaitIf(bCondition, TimeoutSeconds, TimeoutNanoSeconds);
332 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK()\n"));
333 Unlock();
334 dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK() passed\n"));
335 return res;
336 }
337
338 void Condition::Set(bool bCondition) {
339 dmsg(7,("Condition::Set() -> LOCK()\n"));
340 Lock();
341 dmsg(7,("Condition::Set() -> LOCK() passed\n"));
342 if (this->bCondition != bCondition) {
343 this->bCondition = bCondition;
344 if (bCondition) {
345 dmsg(7,("Condition::Set() -> broadcasting 'true' condition\n"));
346 #if defined(WIN32)
347 win32thread_cond_broadcast(&__win32_true_condition);
348 #else
349 pthread_cond_broadcast(&__posix_true_condition);
350 #endif
351 }
352 else {
353 dmsg(7,("Condition::Set() -> broadcasting 'false' condition\n"));
354 #if defined(WIN32)
355 win32thread_cond_broadcast(&__win32_false_condition);
356 #else
357 pthread_cond_broadcast(&__posix_false_condition);
358 #endif
359 }
360 }
361 Unlock();
362 }
363
364 bool Condition::GetUnsafe() {
365 return bCondition;
366 }
367
368 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC