// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "thread.h"
#endif
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;
-
- DECLARE_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
- ::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
// ----------------------------------------------------------------------------
if ( shouldResume )
Resume();
- // does is still run?
+ // is it still running?
if ( isRunning || m_state == STATE_RUNNING )
{
if ( wxThread::IsMain() )
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
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;
}
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
(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()