3f66f6a5b3
This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
350 lines
8.5 KiB
C++
350 lines
8.5 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: wx/thrimpl.cpp
|
|
// Purpose: common part of wxThread Implementations
|
|
// Author: Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 04.06.02 (extracted from src/*/thread.cpp files)
|
|
// Copyright: (c) Vadim Zeitlin (2002)
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// this file is supposed to be included only by the various thread.cpp
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxMutex
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxMutex::wxMutex(wxMutexType mutexType)
|
|
{
|
|
m_internal = new wxMutexInternal(mutexType);
|
|
|
|
if ( !m_internal->IsOk() )
|
|
{
|
|
delete m_internal;
|
|
m_internal = NULL;
|
|
}
|
|
}
|
|
|
|
wxMutex::~wxMutex()
|
|
{
|
|
delete m_internal;
|
|
}
|
|
|
|
bool wxMutex::IsOk() const
|
|
{
|
|
return m_internal != NULL;
|
|
}
|
|
|
|
wxMutexError wxMutex::Lock()
|
|
{
|
|
wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
|
|
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,
|
|
wxT("wxMutex::TryLock(): not initialized") );
|
|
|
|
return m_internal->TryLock();
|
|
}
|
|
|
|
wxMutexError wxMutex::Unlock()
|
|
{
|
|
wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
|
|
wxT("wxMutex::Unlock(): not initialized") );
|
|
|
|
return m_internal->Unlock();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// wxConditionInternal
|
|
// --------------------------------------------------------------------------
|
|
|
|
// 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(__WINDOWS__) || defined(__OS2__) || defined(__EMX__)
|
|
|
|
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;
|
|
|
|
wxDECLARE_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
|
|
{
|
|
wxCriticalSectionLocker lock(m_csWaiters);
|
|
m_numWaiters++;
|
|
}
|
|
|
|
m_mutex.Unlock();
|
|
|
|
// 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();
|
|
|
|
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)
|
|
{
|
|
{
|
|
wxCriticalSectionLocker lock(m_csWaiters);
|
|
m_numWaiters++;
|
|
}
|
|
|
|
m_mutex.Unlock();
|
|
|
|
wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
|
|
|
|
m_mutex.Lock();
|
|
|
|
if ( err == wxSEMA_NO_ERROR )
|
|
return wxCOND_NO_ERROR;
|
|
|
|
if ( err == wxSEMA_TIMEOUT )
|
|
{
|
|
// 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
|
|
//
|
|
// 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--;
|
|
|
|
return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
|
|
}
|
|
|
|
// undo m_numWaiters++ above in case of an error
|
|
{
|
|
wxCriticalSectionLocker lock(m_csWaiters);
|
|
m_numWaiters--;
|
|
}
|
|
|
|
return 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 // __WINDOWS__ || __OS2__ || __EMX__
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxCondition
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxCondition::wxCondition(wxMutex& mutex)
|
|
{
|
|
m_internal = new wxConditionInternal(mutex);
|
|
|
|
if ( !m_internal->IsOk() )
|
|
{
|
|
delete m_internal;
|
|
m_internal = NULL;
|
|
}
|
|
}
|
|
|
|
wxCondition::~wxCondition()
|
|
{
|
|
delete m_internal;
|
|
}
|
|
|
|
bool wxCondition::IsOk() const
|
|
{
|
|
return m_internal != NULL;
|
|
}
|
|
|
|
wxCondError wxCondition::Wait()
|
|
{
|
|
wxCHECK_MSG( m_internal, wxCOND_INVALID,
|
|
wxT("wxCondition::Wait(): not initialized") );
|
|
|
|
return m_internal->Wait();
|
|
}
|
|
|
|
wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
|
|
{
|
|
wxCHECK_MSG( m_internal, wxCOND_INVALID,
|
|
wxT("wxCondition::Wait(): not initialized") );
|
|
|
|
return m_internal->WaitTimeout(milliseconds);
|
|
}
|
|
|
|
wxCondError wxCondition::Signal()
|
|
{
|
|
wxCHECK_MSG( m_internal, wxCOND_INVALID,
|
|
wxT("wxCondition::Signal(): not initialized") );
|
|
|
|
return m_internal->Signal();
|
|
}
|
|
|
|
wxCondError wxCondition::Broadcast()
|
|
{
|
|
wxCHECK_MSG( m_internal, wxCOND_INVALID,
|
|
wxT("wxCondition::Broadcast(): not initialized") );
|
|
|
|
return m_internal->Broadcast();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// wxSemaphore
|
|
// --------------------------------------------------------------------------
|
|
|
|
wxSemaphore::wxSemaphore(int initialcount, int maxcount)
|
|
{
|
|
m_internal = new wxSemaphoreInternal( initialcount, maxcount );
|
|
if ( !m_internal->IsOk() )
|
|
{
|
|
delete m_internal;
|
|
m_internal = NULL;
|
|
}
|
|
}
|
|
|
|
wxSemaphore::~wxSemaphore()
|
|
{
|
|
delete m_internal;
|
|
}
|
|
|
|
bool wxSemaphore::IsOk() const
|
|
{
|
|
return m_internal != NULL;
|
|
}
|
|
|
|
wxSemaError wxSemaphore::Wait()
|
|
{
|
|
wxCHECK_MSG( m_internal, wxSEMA_INVALID,
|
|
wxT("wxSemaphore::Wait(): not initialized") );
|
|
|
|
return m_internal->Wait();
|
|
}
|
|
|
|
wxSemaError wxSemaphore::TryWait()
|
|
{
|
|
wxCHECK_MSG( m_internal, wxSEMA_INVALID,
|
|
wxT("wxSemaphore::TryWait(): not initialized") );
|
|
|
|
return m_internal->TryWait();
|
|
}
|
|
|
|
wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
|
|
{
|
|
wxCHECK_MSG( m_internal, wxSEMA_INVALID,
|
|
wxT("wxSemaphore::WaitTimeout(): not initialized") );
|
|
|
|
return m_internal->WaitTimeout(milliseconds);
|
|
}
|
|
|
|
wxSemaError wxSemaphore::Post()
|
|
{
|
|
wxCHECK_MSG( m_internal, wxSEMA_INVALID,
|
|
wxT("wxSemaphore::Post(): not initialized") );
|
|
|
|
return m_internal->Post();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxThread
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "wx/utils.h"
|
|
|
|
void wxThread::Sleep(unsigned long milliseconds)
|
|
{
|
|
wxMilliSleep(milliseconds);
|
|
}
|