/[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 1221 by schoenebeck, Wed Jun 6 18:50:03 2007 UTC revision 1560 by schoenebeck, Thu Dec 6 17:19:16 2007 UTC
# Line 25  Line 25 
25    
26  #include "Condition.h"  #include "Condition.h"
27    
28  #include "global.h"  #include "global_private.h"
29    
30  namespace LinuxSampler {  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) {  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);      pthread_cond_init(&__posix_true_condition, NULL);
252      pthread_cond_init(&__posix_false_condition, NULL);      pthread_cond_init(&__posix_false_condition, NULL);
253    #endif
254      bCondition = bInitialCondition;      bCondition = bInitialCondition;
255  }  }
256    
257  Condition::~Condition() {  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);      pthread_cond_destroy(&__posix_true_condition);
263      pthread_cond_destroy(&__posix_false_condition);      pthread_cond_destroy(&__posix_false_condition);
264    #endif
265  }  }
266    
267  int Condition::WaitIf(bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds) {  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"));      dmsg(7,("Condition::Waitif() -> LOCK()\n"));
270      Lock();      Lock();
271      dmsg(7,("Condition::Waitif() -> LOCK() passed\n"));      dmsg(7,("Condition::Waitif() -> LOCK() passed\n"));
272      int res = 0;      int res = 0;
273      if (this->bCondition == bCondition) {      if (this->bCondition == bCondition) {
274          if (bCondition) { // wait until condition turned 'false'          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              if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
284                  struct timeval now;                  struct timeval now;
285                  gettimeofday(&now, 0);                  gettimeofday(&now, 0);
# Line 62  int Condition::WaitIf(bool bCondition, l Line 295  int Condition::WaitIf(bool bCondition, l
295                  pthread_cond_wait(&__posix_false_condition, &__posix_mutex);                  pthread_cond_wait(&__posix_false_condition, &__posix_mutex);
296                  dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));                  dmsg(7,("Condition::Waitif() -> awakened from 'false' condition waiting\n"));
297              }              }
298                #endif
299          }          }
300          else { // wait until condition turned 'true'          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              if (TimeoutSeconds || TimeoutNanoSeconds) { // wait with timeout
310                  struct timeval now;                  struct timeval now;
311                  gettimeofday(&now, 0);                  gettimeofday(&now, 0);
# Line 79  int Condition::WaitIf(bool bCondition, l Line 321  int Condition::WaitIf(bool bCondition, l
321                  pthread_cond_wait(&__posix_true_condition, &__posix_mutex);                  pthread_cond_wait(&__posix_true_condition, &__posix_mutex);
322                  dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));                  dmsg(7,("Condition::Waitif() -> awakened from 'true' condition waiting\n"));
323              }              }
324                #endif
325          }          }
326      }      }
327      return res;      return res;
# Line 100  void Condition::Set(bool bCondition) { Line 343  void Condition::Set(bool bCondition) {
343          this->bCondition = bCondition;          this->bCondition = bCondition;
344          if (bCondition) {          if (bCondition) {
345              dmsg(7,("Condition::Set() -> broadcasting 'true' condition\n"));              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);              pthread_cond_broadcast(&__posix_true_condition);
350                #endif
351          }          }
352          else {          else {
353              dmsg(7,("Condition::Set() -> broadcasting 'false' condition\n"));              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);              pthread_cond_broadcast(&__posix_false_condition);
358                #endif
359          }          }
360      }      }
361      Unlock();      Unlock();

Legend:
Removed from v.1221  
changed lines
  Added in v.1560

  ViewVC Help
Powered by ViewVC