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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 53 by schoenebeck, Mon Apr 26 17:15:51 2004 UTC revision 2316 by persson, Sat Feb 18 13:51:38 2012 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck         *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 - 2012 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 20  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
24    #include <sys/time.h>
25    
26  #include "Condition.h"  #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) {  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);      pthread_cond_init(&__posix_true_condition, NULL);
256      pthread_cond_init(&__posix_false_condition, NULL);      pthread_cond_init(&__posix_false_condition, NULL);
257    #endif
258      bCondition = bInitialCondition;      bCondition = bInitialCondition;
259  }  }
260    
261  Condition::~Condition() {  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);      pthread_cond_destroy(&__posix_true_condition);
267      pthread_cond_destroy(&__posix_false_condition);      pthread_cond_destroy(&__posix_false_condition);
268    #endif
269  }  }
270    
271  int Condition::WaitIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {  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();      Lock();
275        dmsg(7,("Condition::Waitif() -> LOCK() passed\n"));
276      int res = 0;      int res = 0;
277      if (this->bCondition == bCondition) {      if (this->bCondition == bCondition) {
278          if (bCondition) {          if (bCondition) { // wait until condition turned 'false'
279              if (TimeoutSeconds || TimeoutNanoSeconds) {              #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;                  timespec timeout;
291                  timeout.tv_sec  = TimeoutSeconds;                  timeout.tv_sec  = now.tv_sec + TimeoutSeconds;
292                  timeout.tv_nsec = TimeoutNanoSeconds;                  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);                  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              else pthread_cond_wait(&__posix_false_condition, &__posix_mutex);              #endif
303          }          }
304          else {          else { // wait until condition turned 'true'
305              if (TimeoutSeconds || TimeoutNanoSeconds) {              #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;                  timespec timeout;
317                  timeout.tv_sec  = TimeoutSeconds;                  timeout.tv_sec  = now.tv_sec + TimeoutSeconds;
318                  timeout.tv_nsec = TimeoutNanoSeconds;                  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);                  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              else pthread_cond_wait(&__posix_true_condition, &__posix_mutex);              #endif
329          }          }
330      }      }
331      return res;      return res;
# Line 61  int Condition::WaitIf(bool bCondition, l Line 333  int Condition::WaitIf(bool bCondition, l
333    
334  int Condition::WaitAndUnlockIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {  int Condition::WaitAndUnlockIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {
335      int res = WaitIf(bCondition, TimeoutSeconds, TimeoutNanoSeconds);      int res = WaitIf(bCondition, TimeoutSeconds, TimeoutNanoSeconds);
336        dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK()\n"));
337      Unlock();      Unlock();
338        dmsg(7,("Condition::WaitAndUnlockIf() -> UNLOCK() passed\n"));
339      return res;      return res;
340  }  }
341    
342  void Condition::Set(bool bCondition) {  void Condition::Set(bool bCondition) {
343        dmsg(7,("Condition::Set() -> LOCK()\n"));
344      Lock();      Lock();
345        dmsg(7,("Condition::Set() -> LOCK() passed\n"));
346      if (this->bCondition != bCondition) {      if (this->bCondition != bCondition) {
347          this->bCondition = bCondition;          this->bCondition = bCondition;
348          if (bCondition) pthread_cond_broadcast(&__posix_true_condition);          if (bCondition) {
349          else            pthread_cond_broadcast(&__posix_false_condition);              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      else Unlock();      Unlock();
366    }
367    
368    bool Condition::GetUnsafe() {
369        return bCondition;
370    }
371    
372    #ifdef WIN32
373    void Condition::Reset() {
374        __win32_true_condition.waiters_count_ = 0;
375        __win32_true_condition.was_broadcast_ = 0;
376        __win32_false_condition.waiters_count_ = 0;
377        __win32_false_condition.was_broadcast_ = 0;
378  }  }
379    #endif
380    
381    } // namespace LinuxSampler

Legend:
Removed from v.53  
changed lines
  Added in v.2316

  ViewVC Help
Powered by ViewVC