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:
Stefan Neis
2003-08-17 22:57:26 +00:00
parent 4d831c9265
commit 0ae780c7c3
4 changed files with 515 additions and 376 deletions

View File

@@ -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
// ----------------------------------------------------------------------------