+
+ wxConditionInternal(wxMutex& mutex)
+ : m_mutex( mutex),
+ m_semaphore( 0, 1),
+ m_gate( 1, 1)
+ {
+ m_waiters = 0;
+ m_signals = 0;
+ m_canceled = 0;
+ }
+
+ ~wxConditionInternal()
+ {
+ }
+
+ bool IsOk() const { return m_mutex.IsOk() ; }
+
+ wxCondError Wait()
+ {
+ return WaitTimeout( kDurationForever);
+ }
+
+ wxCondError WaitTimeout(unsigned long msectimeout);
+
+ wxCondError Signal()
+ {
+ return DoSignal( false);
+ }
+
+ wxCondError Broadcast()
+ {
+ return DoSignal( true);
+ }
+
+private:
+
+ wxCondError DoSignal( bool signalAll);
+
+ wxMutex& m_mutex;
+ wxSemaphoreInternal m_semaphore; // Signals the waiting threads.
+ wxSemaphoreInternal m_gate;
+ wxCriticalSection m_varSection;
+ size_t m_waiters; // Number of threads waiting for a signal.
+ size_t m_signals; // Number of signals to send.
+ size_t m_canceled; // Number of canceled waiters in m_waiters.
+};
+
+
+wxCondError wxConditionInternal::WaitTimeout(unsigned long msectimeout)
+{
+ m_gate.Wait();
+ if ( ++ m_waiters == INT_MAX)
+ {
+ m_varSection.Enter();
+ m_waiters -= m_canceled;
+ m_signals -= m_canceled;
+ m_canceled = 0;
+ m_varSection.Leave();
+ }
+ m_gate.Post();
+
+ m_mutex.Unlock();
+
+ wxSemaError err = m_semaphore.WaitTimeout( msectimeout);
+ wxASSERT( err == wxSEMA_NO_ERROR || err == wxSEMA_TIMEOUT);
+
+ m_varSection.Enter();
+ if ( err != wxSEMA_NO_ERROR)
+ {
+ if ( m_signals > m_canceled)
+ {
+ // A signal is being sent after we timed out.
+
+ if ( m_waiters == m_signals)
+ {
+ // There are no excess waiters to catch the signal, so
+ // we must throw it away.
+
+ wxSemaError err2 = m_semaphore.Wait();
+ if ( err2 != wxSEMA_NO_ERROR)
+ {
+ wxLogSysError(_("Error while waiting on semaphore"));
+ }
+ wxASSERT( err2 == wxSEMA_NO_ERROR);
+ -- m_waiters;
+ if ( -- m_signals == m_canceled)
+ {
+ // This was the last signal. open the gate.
+ wxASSERT( m_waiters == m_canceled);
+ m_gate.Post();
+ }
+ }
+ else
+ {
+ // There are excess waiters to catch the signal, leave
+ // it be.
+ -- m_waiters;
+ }
+ }
+ else
+ {
+ // No signals is being sent.
+ // The gate may be open or closed, so we can't touch m_waiters.
+ ++ m_canceled;
+ ++ m_signals;
+ }
+ }
+ else