Completely reworked OS/2 thread implementation.
Moved wxConditionInternal from src/msw/thread.cpp to include/wx/thrimpl.cpp to give OS/2 the possibility to reuse the code. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@22982 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -60,6 +60,153 @@ wxMutexError wxMutex::Unlock()
|
||||
return m_internal->Unlock();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// wxConditionInternal
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if defined(__WXMSW__) || defined(__WXPM__)
|
||||
// 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
|
||||
#ifdef __WXPM__
|
||||
void InterlockedIncrement(LONG *num)
|
||||
{
|
||||
::DosEnterCritSec();
|
||||
(*num)++;
|
||||
::DosExitCritSec();
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxCondition
|
||||
// ----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user