X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4676948b6814c97b93c431a8cbcd8c0352c87ba9..1e52188741389278cd99abf79218162c87024ba3:/src/msw/thread.cpp diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp index 976c7412d6..3f273a4600 100644 --- a/src/msw/thread.cpp +++ b/src/msw/thread.cpp @@ -10,7 +10,7 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "thread.h" #endif @@ -360,141 +360,6 @@ wxSemaError wxSemaphoreInternal::Post() return wxSEMA_NO_ERROR; } -// -------------------------------------------------------------------------- -// wxCondition -// -------------------------------------------------------------------------- - -// Win32 doesn't have explicit support for the POSIX condition variables and -// the Win32 events have quite different semantics, so we reimplement the -// conditions from scratch using the mutexes and semaphores -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; -}; - -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 - ::InterlockedIncrement(&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(); - m_mutex.Lock(); - - return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR; -} - -wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds) -{ - ::InterlockedIncrement(&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 ) - { - // another potential race condition exists here it is caused when a - // 'waiting' thread timesout, and returns from WaitForSingleObject, but - // has not yet decremented 'nwaiters'. - // - // 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. - wxCriticalSectionLocker lock(m_csWaiters); - - err = m_semaphore.WaitTimeout(0); - - if ( err != wxSEMA_NO_ERROR ) - { - m_numWaiters--; - } - } - - m_mutex.Lock(); - - return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : 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; -} - // ---------------------------------------------------------------------------- // wxThread implementation // ---------------------------------------------------------------------------- @@ -758,7 +623,7 @@ wxThreadInternal::WaitForTerminate(bool shouldCancel, if ( shouldResume ) Resume(); - // does is still run? + // is it still running? if ( isRunning || m_state == STATE_RUNNING ) { if ( wxThread::IsMain() ) @@ -816,7 +681,15 @@ wxThreadInternal::WaitForTerminate(bool shouldCancel, break; case WAIT_OBJECT_0 + 1: - // new message arrived, process it + // new message arrived, process it -- but only if we're the + // main thread as we don't support processing messages in + // the other ones + // + // NB: we still must include QS_ALLINPUT even when waiting + // in a secondary thread because if it had created some + // window somehow (possible not even using wxWindows) + // the system might dead lock then + if ( wxThread::IsMain() ) { // it looks that sometimes WAIT_OBJECT_0 + 1 is // returned but there are no messages in the thread @@ -864,6 +737,12 @@ wxThreadInternal::WaitForTerminate(bool shouldCancel, if ( pRc ) *pRc = rc; + // we don't need the thread handle any more + Free(); + + wxCriticalSectionLocker lock(cs); + SetState(STATE_EXITED); + return rc == (wxThread::ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR; } @@ -927,10 +806,6 @@ bool wxThread::IsMain() return ::GetCurrentThreadId() == gs_idMainThread; } -#ifdef Yield -#undef Yield -#endif - void wxThread::Yield() { // 0 argument to Sleep() is special and means to just give away the rest of @@ -1125,30 +1000,12 @@ wxThread::ExitCode wxThread::Wait() (void)m_internal->WaitForTerminate(false, m_critsect, &rc); - m_internal->Free(); - - wxCriticalSectionLocker lock(m_critsect); - m_internal->SetState(STATE_EXITED); - return rc; } wxThreadError wxThread::Delete(ExitCode *pRc) { - wxThreadError rc = m_internal->WaitForTerminate(true, m_critsect, pRc); - - if ( IsDetached() ) - { - delete this; - } - else // joinable - { - // update the status of the joinable thread - wxCriticalSectionLocker lock(m_critsect); - m_internal->SetState(STATE_EXITED); - } - - return rc; + return m_internal->WaitForTerminate(true, m_critsect, pRc); } wxThreadError wxThread::Kill()