X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/655719367ac5e131d9642e5783f3ecf64d1a3385..0a12e013f55022e684508316ad0079511e3b4fe7:/include/wx/thrimpl.cpp?ds=inline diff --git a/include/wx/thrimpl.cpp b/include/wx/thrimpl.cpp index 60ead20789..3e3cb3cea8 100644 --- a/include/wx/thrimpl.cpp +++ b/include/wx/thrimpl.cpp @@ -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,7 +63,7 @@ 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(); } @@ -64,19 +72,11 @@ wxMutexError wxMutex::Unlock() // wxConditionInternal // -------------------------------------------------------------------------- -#if defined(__WXMSW__) || defined(__WXPM__) || defined(__EMX__) // 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(__WXPM__) || defined(__EMX__) -void InterlockedIncrement(LONG *num) -{ - ::DosEnterCritSec(); - (*num)++; - ::DosExitCritSec(); -} -#endif +#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__) class wxConditionInternal { @@ -101,7 +101,7 @@ private: wxMutex& m_mutex; wxSemaphore m_semaphore; - DECLARE_NO_COPY_CLASS(wxConditionInternal) + wxDECLARE_NO_COPY_CLASS(wxConditionInternal); }; wxConditionInternal::wxConditionInternal(wxMutex& mutex) @@ -115,66 +115,81 @@ wxConditionInternal::wxConditionInternal(wxMutex& mutex) wxCondError wxConditionInternal::Wait() { // increment the number of waiters - ::InterlockedIncrement(&m_numWaiters); + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters++; + } m_mutex.Unlock(); - // a potential race condition can occur here - // - // after a thread increments nwaiters, and unlocks the mutex and before the - // semaphore.Wait() is called, if another thread can cause a signal to be - // generated - // - // this race condition is handled by using a semaphore and incrementing the - // semaphore only if 'nwaiters' is greater that zero since the semaphore, - // can 'remember' signals the race condition will not occur - - // wait ( if necessary ) and decrement semaphore - wxSemaError err = m_semaphore.Wait(); + // 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(); - return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR; + 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) { - ::InterlockedIncrement(&m_numWaiters); + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters++; + } m_mutex.Unlock(); - // a race condition can occur at this point in the code - // - // please see the comments in Wait(), for details - wxSemaError err = m_semaphore.WaitTimeout(milliseconds); - if ( err == wxSEMA_BUSY ) + m_mutex.Lock(); + + if ( err == wxSEMA_NO_ERROR ) + return wxCOND_NO_ERROR; + + if ( err == wxSEMA_TIMEOUT ) { - // another potential race condition exists here it is caused when a - // 'waiting' thread timesout, and returns from WaitForSingleObject, but - // has not yet decremented 'nwaiters'. + // 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 // - // at this point if another thread calls signal() then the semaphore - // will be incremented, but the waiting thread will miss it. - // - // to handle this particular case, the waiting thread calls - // WaitForSingleObject again with a timeout of 0, after locking - // 'nwaiters_mutex'. this call does not block because of the zero - // timeout, but will allow the waiting thread to catch the missed - // signals. + // 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--; - if ( err != wxSEMA_NO_ERROR ) - { - m_numWaiters--; - } + return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR; } - m_mutex.Lock(); + // undo m_numWaiters++ above in case of an error + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters--; + } - return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR; + return wxCOND_MISC_ERROR; } wxCondError wxConditionInternal::Signal() @@ -207,7 +222,8 @@ wxCondError wxConditionInternal::Broadcast() return wxCOND_NO_ERROR; } -#endif + +#endif // MSW or OS2 // ---------------------------------------------------------------------------- // wxCondition @@ -237,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(); } @@ -245,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); } @@ -253,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(); } @@ -261,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(); } @@ -293,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(); } @@ -301,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(); } @@ -309,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); } @@ -317,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); +}