/[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 1481 - (show annotations) (download)
Wed Nov 14 23:42:15 2007 UTC (16 years, 5 months ago) by senoner
File size: 15961 byte(s)
* win32 port work in progress:
* - implemented win32 support in the following classes:
* Thread, Condition, Mutex, Path, LscpServer
* - lscp.y use DONTCARE instead of VOID
*  (a win32 symbol defined)
* - completed win32 editor plugin loader

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

  ViewVC Help
Powered by ViewVC