X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9e84b84742248ef54a561b4937bbc039332c2c51..835165d576b66441987b78519e6ef1fe74ea795a:/include/wx/thrimpl.cpp diff --git a/include/wx/thrimpl.cpp b/include/wx/thrimpl.cpp index b01436a220..0874cd186c 100644 --- a/include/wx/thrimpl.cpp +++ b/include/wx/thrimpl.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: include/wx/thrimpl.cpp +// Name: wx/thrimpl.cpp // Purpose: common part of wxThread Implementations // Author: Vadim Zeitlin // Modified by: @@ -39,15 +39,23 @@ bool wxMutex::IsOk() const wxMutexError wxMutex::Lock() { wxCHECK_MSG( m_internal, wxMUTEX_INVALID, - _T("wxMutex::Lock(): not initialized") ); + wxT("wxMutex::Lock(): not initialized") ); return m_internal->Lock(); } +wxMutexError wxMutex::LockTimeout(unsigned long ms) +{ + wxCHECK_MSG( m_internal, wxMUTEX_INVALID, + wxT("wxMutex::Lock(): not initialized") ); + + return m_internal->Lock(ms); +} + wxMutexError wxMutex::TryLock() { wxCHECK_MSG( m_internal, wxMUTEX_INVALID, - _T("wxMutex::TryLock(): not initialized") ); + wxT("wxMutex::TryLock(): not initialized") ); return m_internal->TryLock(); } @@ -55,11 +63,168 @@ wxMutexError wxMutex::TryLock() wxMutexError wxMutex::Unlock() { wxCHECK_MSG( m_internal, wxMUTEX_INVALID, - _T("wxMutex::Unlock(): not initialized") ); + wxT("wxMutex::Unlock(): not initialized") ); return m_internal->Unlock(); } +// -------------------------------------------------------------------------- +// wxConditionInternal +// -------------------------------------------------------------------------- + +// Win32 and OS/2 don't have explicit support for the POSIX condition +// variables and their events/event semaphores have quite different semantics, +// so we reimplement the conditions from scratch using the mutexes and +// semaphores +#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__) + +class wxConditionInternal +{ +public: + wxConditionInternal(wxMutex& mutex); + + bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); } + + wxCondError Wait(); + wxCondError WaitTimeout(unsigned long milliseconds); + + wxCondError Signal(); + wxCondError Broadcast(); + +private: + // the number of threads currently waiting for this condition + LONG m_numWaiters; + + // the critical section protecting m_numWaiters + wxCriticalSection m_csWaiters; + + wxMutex& m_mutex; + wxSemaphore m_semaphore; + + wxDECLARE_NO_COPY_CLASS(wxConditionInternal); +}; + +wxConditionInternal::wxConditionInternal(wxMutex& mutex) + : m_mutex(mutex) +{ + // another thread can't access it until we return from ctor, so no need to + // protect access to m_numWaiters here + m_numWaiters = 0; +} + +wxCondError wxConditionInternal::Wait() +{ + // increment the number of waiters + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters++; + } + + m_mutex.Unlock(); + + // after unlocking the mutex other threads may Signal() us, but it is ok + // now as we had already incremented m_numWaiters so Signal() will post the + // semaphore and decrement m_numWaiters back even if it is called before we + // start to Wait() + const wxSemaError err = m_semaphore.Wait(); + + m_mutex.Lock(); + + if ( err == wxSEMA_NO_ERROR ) + { + // m_numWaiters was decremented by Signal() + return wxCOND_NO_ERROR; + } + + // but in case of an error we need to do it manually + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters--; + } + + return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR; +} + +wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds) +{ + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters++; + } + + m_mutex.Unlock(); + + wxSemaError err = m_semaphore.WaitTimeout(milliseconds); + + m_mutex.Lock(); + + if ( err == wxSEMA_NO_ERROR ) + return wxCOND_NO_ERROR; + + if ( err == wxSEMA_TIMEOUT ) + { + // a potential race condition exists here: it happens when a waiting + // thread times out but doesn't have time to decrement m_numWaiters yet + // before Signal() is called in another thread + // + // to handle this particular case, check the semaphore again after + // acquiring m_csWaiters lock -- this will catch the signals missed + // during this window + wxCriticalSectionLocker lock(m_csWaiters); + + err = m_semaphore.WaitTimeout(0); + if ( err == wxSEMA_NO_ERROR ) + return wxCOND_NO_ERROR; + + // we need to decrement m_numWaiters ourselves as it wasn't done by + // Signal() + m_numWaiters--; + + return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR; + } + + // undo m_numWaiters++ above in case of an error + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters--; + } + + return wxCOND_MISC_ERROR; +} + +wxCondError wxConditionInternal::Signal() +{ + wxCriticalSectionLocker lock(m_csWaiters); + + if ( m_numWaiters > 0 ) + { + // increment the semaphore by 1 + if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) + return wxCOND_MISC_ERROR; + + m_numWaiters--; + } + + return wxCOND_NO_ERROR; +} + +wxCondError wxConditionInternal::Broadcast() +{ + wxCriticalSectionLocker lock(m_csWaiters); + + while ( m_numWaiters > 0 ) + { + if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) + return wxCOND_MISC_ERROR; + + m_numWaiters--; + } + + return wxCOND_NO_ERROR; +} + +#endif // MSW or OS2 + // ---------------------------------------------------------------------------- // wxCondition // ---------------------------------------------------------------------------- @@ -88,7 +253,7 @@ bool wxCondition::IsOk() const wxCondError wxCondition::Wait() { wxCHECK_MSG( m_internal, wxCOND_INVALID, - _T("wxCondition::Wait(): not initialized") ); + wxT("wxCondition::Wait(): not initialized") ); return m_internal->Wait(); } @@ -96,7 +261,7 @@ wxCondError wxCondition::Wait() wxCondError wxCondition::WaitTimeout(unsigned long milliseconds) { wxCHECK_MSG( m_internal, wxCOND_INVALID, - _T("wxCondition::Wait(): not initialized") ); + wxT("wxCondition::Wait(): not initialized") ); return m_internal->WaitTimeout(milliseconds); } @@ -104,7 +269,7 @@ wxCondError wxCondition::WaitTimeout(unsigned long milliseconds) wxCondError wxCondition::Signal() { wxCHECK_MSG( m_internal, wxCOND_INVALID, - _T("wxCondition::Signal(): not initialized") ); + wxT("wxCondition::Signal(): not initialized") ); return m_internal->Signal(); } @@ -112,7 +277,7 @@ wxCondError wxCondition::Signal() wxCondError wxCondition::Broadcast() { wxCHECK_MSG( m_internal, wxCOND_INVALID, - _T("wxCondition::Broadcast(): not initialized") ); + wxT("wxCondition::Broadcast(): not initialized") ); return m_internal->Broadcast(); } @@ -144,7 +309,7 @@ bool wxSemaphore::IsOk() const wxSemaError wxSemaphore::Wait() { wxCHECK_MSG( m_internal, wxSEMA_INVALID, - _T("wxSemaphore::Wait(): not initialized") ); + wxT("wxSemaphore::Wait(): not initialized") ); return m_internal->Wait(); } @@ -152,7 +317,7 @@ wxSemaError wxSemaphore::Wait() wxSemaError wxSemaphore::TryWait() { wxCHECK_MSG( m_internal, wxSEMA_INVALID, - _T("wxSemaphore::TryWait(): not initialized") ); + wxT("wxSemaphore::TryWait(): not initialized") ); return m_internal->TryWait(); } @@ -160,7 +325,7 @@ wxSemaError wxSemaphore::TryWait() wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds) { wxCHECK_MSG( m_internal, wxSEMA_INVALID, - _T("wxSemaphore::WaitTimeout(): not initialized") ); + wxT("wxSemaphore::WaitTimeout(): not initialized") ); return m_internal->WaitTimeout(milliseconds); } @@ -168,8 +333,18 @@ wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds) wxSemaError wxSemaphore::Post() { wxCHECK_MSG( m_internal, wxSEMA_INVALID, - _T("wxSemaphore::Post(): not initialized") ); + wxT("wxSemaphore::Post(): not initialized") ); return m_internal->Post(); } +// ---------------------------------------------------------------------------- +// wxThread +// ---------------------------------------------------------------------------- + +#include "wx/utils.h" + +void wxThread::Sleep(unsigned long milliseconds) +{ + wxMilliSleep(milliseconds); +}