wxMutex changes (explicitly specify the type), return values for all wxMutex/wxSemaphore/wxCondition methods and general cleanup

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15761 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2002-06-06 18:31:59 +00:00
parent b0e5c03934
commit 9e84b84742
4 changed files with 957 additions and 985 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Name: thread.h
// Name: wx/thread.h
// Purpose: Thread API
// Author: Guilhem Lavaux
// Modified by: Vadim Zeitlin (modifications partly inspired by omnithreads
@ -10,15 +10,15 @@
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef __THREADH__
#define __THREADH__
#ifndef _WX_THREAD_H_
#define _WX_THREAD_H_
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// get the value of wxUSE_THREADS configuration flag
#include "wx/setup.h"
#include "wx/defs.h"
#if wxUSE_THREADS
@ -40,11 +40,30 @@
enum wxMutexError
{
wxMUTEX_NO_ERROR = 0,
wxMUTEX_DEAD_LOCK, // Mutex has been already locked by THE CALLING thread
wxMUTEX_BUSY, // Mutex has been already locked by ONE thread
wxMUTEX_UNLOCKED,
wxMUTEX_MISC_ERROR
wxMUTEX_NO_ERROR = 0, // operation completed successfully
wxMUTEX_INVALID, // mutex hasn't been initialized
wxMUTEX_DEAD_LOCK, // mutex is already locked by the calling thread
wxMUTEX_BUSY, // mutex is already locked by another thread
wxMUTEX_UNLOCKED, // attempt to unlock a mutex which is not locked
wxMUTEX_MISC_ERROR // any other error
};
enum wxCondError
{
wxCOND_NO_ERROR = 0,
wxCOND_INVALID,
wxCOND_TIMEOUT, // WaitTimeout() has timed out
wxCOND_MISC_ERROR
};
enum wxSemaError
{
wxSEMA_NO_ERROR = 0,
wxSEMA_INVALID, // semaphore hasn't been initialized successfully
wxSEMA_BUSY, // returned by TryWait() if Wait() would block
wxSEMA_TIMEOUT, // returned by WaitTimeout()
wxSEMA_OVERFLOW, // Post() would increase counter past the max
wxSEMA_MISC_ERROR
};
enum wxThreadError
@ -71,6 +90,37 @@ enum
WXTHREAD_MAX_PRIORITY = 100u
};
// There are 2 types of mutexes: normal mutexes and recursive ones. The attempt
// to lock a normal mutex by a thread which already owns it results in
// undefined behaviour (it always works under Windows, it will almost always
// result in a deadlock under Unix). Locking a recursive mutex in such
// situation always succeeds and it must be unlocked as many times as it has
// been locked.
//
// However recursive mutexes have several important drawbacks: first, in the
// POSIX implementation, they're less efficient. Second, and more importantly,
// they CAN NOT BE USED WITH CONDITION VARIABLES under Unix! Using them with
// wxCondition will work under Windows and some Unices (notably Linux) but will
// deadlock under other Unix versions (e.g. Solaris). As it might be difficult
// to ensure that a recursive mutex is not used with wxCondition, it is a good
// idea to avoid using recursive mutexes at all. Also, the last problem with
// them is that some (older) Unix versions don't support this at all -- which
// results in a configure warning when building and a deadlock when using them.
enum wxMutexType
{
// normal mutex: try to always use this one
wxMUTEX_DEFAULT,
// recursive mutex: don't use these ones with wxCondition
wxMUTEX_RECURSIVE
};
// forward declarations
class WXDLLEXPORT wxConditionInternal;
class WXDLLEXPORT wxMutexInternal;
class WXDLLEXPORT wxSemaphoreInternal;
class WXDLLEXPORT wxThreadInternal;
// ----------------------------------------------------------------------------
// A mutex object is a synchronization object whose state is set to signaled
// when it is not owned by any thread, and nonsignaled when it is owned. Its
@ -80,34 +130,44 @@ enum
// you should consider wxMutexLocker whenever possible instead of directly
// working with wxMutex class - it is safer
class WXDLLEXPORT wxConditionInternal;
class WXDLLEXPORT wxMutexInternal;
class WXDLLEXPORT wxMutex
{
public:
// constructor & destructor
wxMutex();
// ------------------------
// create either default (always safe) or recursive mutex
wxMutex(wxMutexType mutexType = wxMUTEX_DEFAULT);
// destroys the mutex kernel object
~wxMutex();
// Lock the mutex.
// test if the mutex has been created successfully
bool IsOk() const;
// mutex operations
// ----------------
// Lock the mutex, blocking on it until it is unlocked by the other thread.
// The result of locking a mutex already locked by the current thread
// depend on the mutex type.
//
// The caller must call Unlock() later if Lock() returned wxMUTEX_NO_ERROR.
wxMutexError Lock();
// Try to lock the mutex: if it can't, returns immediately with an error.
// Try to lock the mutex: if it is currently locked, return immediately
// with an error. Otherwise the caller must call Unlock().
wxMutexError TryLock();
// Unlock the mutex.
// Unlock the mutex. It is an error to unlock an already unlocked mutex
wxMutexError Unlock();
// Returns true if the mutex is locked.
bool IsLocked() const { return (m_locked > 0); }
protected:
// no assignment operator nor copy ctor
wxMutex(const wxMutex&);
wxMutex& operator=(const wxMutex&);
int m_locked;
wxMutexInternal *m_internal;
friend class wxConditionInternal;
DECLARE_NO_COPY_CLASS(wxMutex)
};
// a helper class which locks the mutex in the ctor and unlocks it in the dtor:
@ -148,17 +208,11 @@ private:
// which makes it possible to have static globals of this class
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxCriticalSectionInternal;
// in order to avoid any overhead under platforms where critical sections are
// just mutexes make all wxCriticalSection class functions inline
#if !defined(__WXMSW__) && !defined(__WXPM__)
#define WXCRITICAL_INLINE inline
#define wxCRITSECT_IS_MUTEX 1
#else // MSW || OS2
#define WXCRITICAL_INLINE
#define wxCRITSECT_IS_MUTEX 0
#endif // MSW/!MSW
@ -168,50 +222,62 @@ class WXDLLEXPORT wxCriticalSection
{
public:
// ctor & dtor
WXCRITICAL_INLINE wxCriticalSection();
WXCRITICAL_INLINE ~wxCriticalSection();
inline wxCriticalSection();
inline ~wxCriticalSection();
// enter the section (the same as locking a mutex)
WXCRITICAL_INLINE void Enter();
inline void Enter();
// leave the critical section (same as unlocking a mutex)
WXCRITICAL_INLINE void Leave();
inline void Leave();
private:
// no assignment operator nor copy ctor
wxCriticalSection(const wxCriticalSection&);
wxCriticalSection& operator=(const wxCriticalSection&);
#if wxCRITSECT_IS_MUTEX
wxMutex m_mutex;
#elif defined(__WXMSW__)
// we can't allocate any memory in the ctor, so use placement new -
// unfortunately, we have to hardcode the sizeof() here because we can't
// include windows.h from this public header
//
// if CRITICAL_SECTION size changes in Windows, you'll get an assert from
// thread.cpp and will need to increase the buffer size
char m_buffer[24];
#elif !defined(__WXPM__)
wxCriticalSectionInternal *m_critsect;
#else
// nothing for OS/2
#endif // !Unix/Unix
#endif // Unix/Win32/OS2
DECLARE_NO_COPY_CLASS(wxCriticalSection)
};
// keep your preprocessor name space clean
#undef WXCRITICAL_INLINE
#if wxCRITSECT_IS_MUTEX
// implement wxCriticalSection using mutexes
inline wxCriticalSection::wxCriticalSection() { }
inline wxCriticalSection::~wxCriticalSection() { }
inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
#endif // wxCRITSECT_IS_MUTEX
// wxCriticalSectionLocker is the same to critical sections as wxMutexLocker is
// to th mutexes
class WXDLLEXPORT wxCriticalSectionLocker
{
public:
inline wxCriticalSectionLocker(wxCriticalSection& critsect);
inline ~wxCriticalSectionLocker();
wxCriticalSectionLocker(wxCriticalSection& cs)
: m_critsect(cs)
{
m_critsect.Enter();
}
~wxCriticalSectionLocker()
{
m_critsect.Leave();
}
private:
// no assignment operator nor copy ctor
wxCriticalSectionLocker(const wxCriticalSectionLocker&);
wxCriticalSectionLocker& operator=(const wxCriticalSectionLocker&);
wxCriticalSection& m_critsect;
DECLARE_NO_COPY_CLASS(wxCriticalSectionLocker)
};
// ----------------------------------------------------------------------------
@ -221,25 +287,24 @@ private:
class WXDLLEXPORT wxCondition
{
DECLARE_NO_COPY_CLASS(wxCondition)
public:
// constructor and destructor
// Each wxCondition object is associated with with a wxMutex object The
// mutex object MUST be locked before calling Wait()
// Each wxCondition object is associated with a (single) wxMutex object.
// The mutex object MUST be locked before calling Wait()
wxCondition(wxMutex& mutex);
// dtor is not virtual, don't use this class polymorphically
~wxCondition();
// return TRUE if the condition has been created successfully
bool IsOk() const;
// NB: the associated mutex MUST be locked beforehand by the calling thread
//
// it atomically releases the lock on the associated mutex
// and starts waiting to be woken up by a Signal()/Broadcast()
// once its signaled, then it will wait until it can reacquire
// the lock on the associated mutex object, before returning.
void Wait();
wxCondError Wait();
// exactly as Wait() except that it may also return if the specified
// timeout ellapses even if the condition hasn't been signalled: in this
@ -248,7 +313,7 @@ public:
//
// the timeeout parameter specifies a interval that needs to be waited in
// milliseconds
bool Wait( unsigned long timeout_millis );
wxCondError WaitTimeout(unsigned long milliseconds);
// NB: the associated mutex may or may not be locked by the calling thread
//
@ -256,7 +321,7 @@ public:
// if no thread is blocking in Wait(), then the signal is NOT remembered
// The thread which was blocking on Wait(), will then reacquire the lock
// on the associated mutex object before returning
void Signal();
wxCondError Signal();
// NB: the associated mutex may or may not be locked by the calling thread
//
@ -264,10 +329,17 @@ public:
// if no thread is blocking in Wait(), then the signal is NOT remembered
// The threads which were blocking on Wait(), will then reacquire the lock
// on the associated mutex object before returning.
void Broadcast();
wxCondError Broadcast();
// deprecated version, don't use
bool Wait(unsigned long milliseconds)
{ return WaitTimeout(milliseconds) == wxCOND_NO_ERROR; }
private:
wxConditionInternal *m_internal;
DECLARE_NO_COPY_CLASS(wxCondition)
};
// ----------------------------------------------------------------------------
@ -275,11 +347,8 @@ private:
// a shared resource
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxSemaphoreInternal;
class WXDLLEXPORT wxSemaphore
{
DECLARE_NO_COPY_CLASS(wxSemaphore)
public:
// specifying a maxcount of 0 actually makes wxSemaphore behave as if there
// is no upper limit, if maxcount is 1 the semaphore behaves as a mutex
@ -288,24 +357,29 @@ public:
// dtor is not virtual, don't use this class polymorphically
~wxSemaphore();
// return TRUE if the semaphore has been created successfully
bool IsOk() const;
// wait indefinitely, until the semaphore count goes beyond 0
// and then decrement it and return (this method might have been called
// Acquire())
void Wait();
wxSemaError Wait();
// same as Wait(), but does not block, returns TRUE if successful and
// FALSE if the count is zero
bool TryWait();
// same as Wait(), but does not block, returns wxSEMA_NO_ERROR if
// successful and wxSEMA_BUSY if the count is currently zero
wxSemaError TryWait();
// same as Wait(), but as a timeout limit, returns TRUE if the semaphore
// was acquired and FALSE if the timeout has ellapsed
bool Wait( unsigned long timeout_millis );
// same as Wait(), but as a timeout limit, returns wxSEMA_NO_ERROR if the
// semaphore was acquired and wxSEMA_TIMEOUT if the timeout has ellapsed
wxSemaError WaitTimeout(unsigned long milliseconds);
// increments the semaphore count and signals one of the waiting threads
void Post();
wxSemaError Post();
private:
wxSemaphoreInternal *m_internal;
DECLARE_NO_COPY_CLASS(wxSemaphore)
};
// ----------------------------------------------------------------------------
@ -328,7 +402,6 @@ private:
typedef unsigned long wxThreadIdType;
#endif
class wxThreadInternal;
class WXDLLEXPORT wxThread
{
public:
@ -508,8 +581,6 @@ void WXDLLEXPORT wxMutexGuiLeave();
#else // !wxUSE_THREADS
#include "wx/defs.h" // for WXDLLEXPORT
// no thread support
inline void WXDLLEXPORT wxMutexGuiEnter() { }
inline void WXDLLEXPORT wxMutexGuiLeave() { }
@ -521,9 +592,9 @@ inline void WXDLLEXPORT wxMutexGuiLeave() { }
#define wxCRIT_SECT_DECLARE(cs)
#define wxCRIT_SECT_LOCKER(name, cs)
#endif // wxUSE_THREADS
#endif // wxUSE_THREADS/!wxUSE_THREADS
// automatically unlock GUI mutex in dtor
// automatically lock GUI mutex in ctor and unlock it in dtor
class WXDLLEXPORT wxMutexGuiLocker
{
public:
@ -537,7 +608,7 @@ public:
#if wxUSE_THREADS
#if defined(__WXMSW__)
#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXPM__)
// unlock GUI if there are threads waiting for and lock it back when
// there are no more of them - should be called periodically by the main
// thread
@ -546,61 +617,17 @@ public:
// returns TRUE if the main thread has GUI lock
extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
#ifndef __WXPM__
// wakes up the main thread if it's sleeping inside ::GetMessage()
extern void WXDLLEXPORT wxWakeUpMainThread();
#endif // !OS/2
// return TRUE if the main thread is waiting for some other to terminate:
// wxApp then should block all "dangerous" messages
extern bool WXDLLEXPORT wxIsWaitingForThread();
#elif defined(__WXMAC__)
extern void WXDLLEXPORT wxMutexGuiLeaveOrEnter();
#endif // MSW, Mac, OS/2
// returns TRUE if the main thread has GUI lock
extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
// wakes up the main thread if it's sleeping inside ::GetMessage()
extern void WXDLLEXPORT wxWakeUpMainThread();
// return TRUE if the main thread is waiting for some other to terminate:
// wxApp then should block all "dangerous" messages
extern bool WXDLLEXPORT wxIsWaitingForThread();
// implement wxCriticalSection using mutexes
inline wxCriticalSection::wxCriticalSection() : m_mutex() { }
inline wxCriticalSection::~wxCriticalSection() { }
inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
#elif defined(__WXPM__)
// unlock GUI if there are threads waiting for and lock it back when
// there are no more of them - should be called periodically by the main
// thread
extern void WXDLLEXPORT wxMutexGuiLeaveOrEnter();
// returns TRUE if the main thread has GUI lock
extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
// return TRUE if the main thread is waiting for some other to terminate:
// wxApp then should block all "dangerous" messages
extern bool WXDLLEXPORT wxIsWaitingForThread();
#else // !MSW && !PM
// implement wxCriticalSection using mutexes
inline wxCriticalSection::wxCriticalSection() { }
inline wxCriticalSection::~wxCriticalSection() { }
inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
#endif // MSW/!MSW
// we can define these inline functions now (they should be defined after
// wxCriticalSection::Enter/Leave)
inline
wxCriticalSectionLocker:: wxCriticalSectionLocker(wxCriticalSection& cs)
: m_critsect(cs) { m_critsect.Enter(); }
inline
wxCriticalSectionLocker::~wxCriticalSectionLocker() { m_critsect.Leave(); }
#endif // wxUSE_THREADS
#endif // __THREADH__
#endif // _WX_THREAD_H_

175
include/wx/thrimpl.cpp Normal file
View File

@ -0,0 +1,175 @@
/////////////////////////////////////////////////////////////////////////////
// Name: include/wx/thrimpl.cpp
// Purpose: common part of wxThread Implementations
// Author: Vadim Zeitlin
// Modified by:
// Created: 04.06.02 (extracted from src/*/thread.cpp files)
// RCS-ID: $Id$
// 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,
_T("wxMutex::Lock(): not initialized") );
return m_internal->Lock();
}
wxMutexError wxMutex::TryLock()
{
wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
_T("wxMutex::TryLock(): not initialized") );
return m_internal->TryLock();
}
wxMutexError wxMutex::Unlock()
{
wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
_T("wxMutex::Unlock(): not initialized") );
return m_internal->Unlock();
}
// ----------------------------------------------------------------------------
// 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,
_T("wxCondition::Wait(): not initialized") );
return m_internal->Wait();
}
wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
{
wxCHECK_MSG( m_internal, wxCOND_INVALID,
_T("wxCondition::Wait(): not initialized") );
return m_internal->WaitTimeout(milliseconds);
}
wxCondError wxCondition::Signal()
{
wxCHECK_MSG( m_internal, wxCOND_INVALID,
_T("wxCondition::Signal(): not initialized") );
return m_internal->Signal();
}
wxCondError wxCondition::Broadcast()
{
wxCHECK_MSG( m_internal, wxCOND_INVALID,
_T("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,
_T("wxSemaphore::Wait(): not initialized") );
return m_internal->Wait();
}
wxSemaError wxSemaphore::TryWait()
{
wxCHECK_MSG( m_internal, wxSEMA_INVALID,
_T("wxSemaphore::TryWait(): not initialized") );
return m_internal->TryWait();
}
wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
{
wxCHECK_MSG( m_internal, wxSEMA_INVALID,
_T("wxSemaphore::WaitTimeout(): not initialized") );
return m_internal->WaitTimeout(milliseconds);
}
wxSemaError wxSemaphore::Post()
{
wxCHECK_MSG( m_internal, wxSEMA_INVALID,
_T("wxSemaphore::Post(): not initialized") );
return m_internal->Post();
}

View File

@ -1,12 +1,12 @@
/////////////////////////////////////////////////////////////////////////////
// Name: thread.cpp
// Name: src/msw/thread.cpp
// Purpose: wxThread Implementation
// Author: Original from Wolfram Gloger/Guilhem Lavaux
// Modified by: Vadim Zeitlin to make it work :-)
// Created: 04/22/98
// RCS-ID: $Id$
// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
// Vadim Zeitlin (1999)
// Copyright: (c) Wolfram Gloger (1996, 1997), Guilhem Lavaux (1998);
// Vadim Zeitlin (1999-2002)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@ -36,10 +36,6 @@
#include "wx/module.h"
#include "wx/thread.h"
#ifdef Yield
# undef Yield
#endif
// must have this symbol defined to get _beginthread/_endthread declarations
#ifndef _MT
#define _MT
@ -127,409 +123,17 @@ static size_t gs_nWaitingForGui = 0;
static bool gs_waitingForThread = FALSE;
// ============================================================================
// Windows implementation of thread classes
// Windows implementation of thread and related classes
// ============================================================================
// ----------------------------------------------------------------------------
// wxMutex implementation
// ----------------------------------------------------------------------------
class wxMutexInternal
{
public:
wxMutexInternal()
{
m_mutex = ::CreateMutex(NULL, FALSE, NULL);
if ( !m_mutex )
{
wxLogSysError(_("Can not create mutex"));
}
}
~wxMutexInternal() { if ( m_mutex ) ::CloseHandle(m_mutex); }
public:
HANDLE m_mutex;
};
wxMutex::wxMutex()
{
m_internal = new wxMutexInternal;
m_locked = 0;
}
wxMutex::~wxMutex()
{
if ( m_locked > 0 )
{
wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked);
}
delete m_internal;
}
wxMutexError wxMutex::Lock()
{
DWORD ret;
ret = WaitForSingleObject(m_internal->m_mutex, INFINITE);
switch ( ret )
{
case WAIT_ABANDONED:
return wxMUTEX_BUSY;
case WAIT_OBJECT_0:
// ok
break;
case WAIT_FAILED:
wxLogSysError(_("Couldn't acquire a mutex lock"));
return wxMUTEX_MISC_ERROR;
case WAIT_TIMEOUT:
default:
wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
}
m_locked++;
return wxMUTEX_NO_ERROR;
}
wxMutexError wxMutex::TryLock()
{
DWORD ret;
ret = WaitForSingleObject(m_internal->m_mutex, 0);
if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
return wxMUTEX_BUSY;
m_locked++;
return wxMUTEX_NO_ERROR;
}
wxMutexError wxMutex::Unlock()
{
if (m_locked > 0)
m_locked--;
BOOL ret = ReleaseMutex(m_internal->m_mutex);
if ( ret == 0 )
{
wxLogSysError(_("Couldn't release a mutex"));
return wxMUTEX_MISC_ERROR;
}
return wxMUTEX_NO_ERROR;
}
// ==========================================================================
// wxSemaphore
// ==========================================================================
// --------------------------------------------------------------------------
// wxSemaphoreInternal
// --------------------------------------------------------------------------
class wxSemaphoreInternal
{
public:
wxSemaphoreInternal( int initialcount = 0, int maxcount = 0 );
~wxSemaphoreInternal();
void Wait();
bool TryWait();
bool Wait( unsigned long timeout_millis );
void Post();
private:
HANDLE m_semaphore;
};
wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount )
{
if ( maxcount == 0 )
{
// make it practically infinite
maxcount = INT_MAX;
}
m_semaphore = ::CreateSemaphore( NULL, initialcount, maxcount, NULL );
if ( !m_semaphore )
{
wxLogLastError(_T("CreateSemaphore()"));
}
}
wxSemaphoreInternal::~wxSemaphoreInternal()
{
CloseHandle( m_semaphore );
}
void wxSemaphoreInternal::Wait()
{
if ( ::WaitForSingleObject( m_semaphore, INFINITE ) != WAIT_OBJECT_0 )
{
wxLogLastError(_T("WaitForSingleObject"));
}
}
bool wxSemaphoreInternal::TryWait()
{
return Wait(0);
}
bool wxSemaphoreInternal::Wait( unsigned long timeout_millis )
{
DWORD result = ::WaitForSingleObject( m_semaphore, timeout_millis );
switch ( result )
{
case WAIT_OBJECT_0:
return TRUE;
case WAIT_TIMEOUT:
break;
default:
wxLogLastError(_T("WaitForSingleObject()"));
}
return FALSE;
}
void wxSemaphoreInternal::Post()
{
if ( !::ReleaseSemaphore( m_semaphore, 1, NULL ) )
{
wxLogLastError(_T("ReleaseSemaphore"));
}
}
// --------------------------------------------------------------------------
// wxSemaphore
// --------------------------------------------------------------------------
wxSemaphore::wxSemaphore( int initialcount, int maxcount )
{
m_internal = new wxSemaphoreInternal( initialcount, maxcount );
}
wxSemaphore::~wxSemaphore()
{
delete m_internal;
}
void wxSemaphore::Wait()
{
m_internal->Wait();
}
bool wxSemaphore::TryWait()
{
return m_internal->TryWait();
}
bool wxSemaphore::Wait( unsigned long timeout_millis )
{
return m_internal->Wait( timeout_millis );
}
void wxSemaphore::Post()
{
m_internal->Post();
}
// ==========================================================================
// wxCondition
// ==========================================================================
// --------------------------------------------------------------------------
// wxConditionInternal
// --------------------------------------------------------------------------
class wxConditionInternal
{
public:
wxConditionInternal(wxMutex& mutex);
void Wait();
bool Wait( unsigned long timeout_millis );
void Signal();
void Broadcast();
private:
int m_numWaiters;
wxMutex m_mutexNumWaiters;
wxMutex& m_mutex;
wxSemaphore m_semaphore;
DECLARE_NO_COPY_CLASS(wxConditionInternal)
};
wxConditionInternal::wxConditionInternal(wxMutex& mutex)
: m_mutex(mutex)
{
m_numWaiters = 0;
}
void wxConditionInternal::Wait()
{
// increment the number of waiters
m_mutexNumWaiters.Lock();
m_numWaiters++;
m_mutexNumWaiters.Unlock();
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
m_semaphore.Wait();
m_mutex.Lock();
}
bool wxConditionInternal::Wait( unsigned long timeout_millis )
{
m_mutexNumWaiters.Lock();
m_numWaiters++;
m_mutexNumWaiters.Unlock();
m_mutex.Unlock();
// a race condition can occur at this point in the code
//
// please see the comments in Wait(), for details
bool success = TRUE;
bool result = m_semaphore.Wait( timeout_millis );
if ( !result )
{
// 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.
m_mutexNumWaiters.Lock();
result = m_semaphore.Wait( 0 );
if ( !result )
{
m_numWaiters--;
success = FALSE;
}
m_mutexNumWaiters.Unlock();
}
m_mutex.Lock();
return success;
}
void wxConditionInternal::Signal()
{
m_mutexNumWaiters.Lock();
if ( m_numWaiters > 0 )
{
// increment the semaphore by 1
m_semaphore.Post();
m_numWaiters--;
}
m_mutexNumWaiters.Unlock();
}
void wxConditionInternal::Broadcast()
{
m_mutexNumWaiters.Lock();
while ( m_numWaiters > 0 )
{
m_semaphore.Post();
m_numWaiters--;
}
m_mutexNumWaiters.Unlock();
}
// ----------------------------------------------------------------------------
// wxCondition implementation
// ----------------------------------------------------------------------------
wxCondition::wxCondition(wxMutex& mutex)
{
m_internal = new wxConditionInternal( mutex );
}
wxCondition::~wxCondition()
{
delete m_internal;
}
void wxCondition::Wait()
{
m_internal->Wait();
}
bool wxCondition::Wait( unsigned long timeout_millis )
{
return m_internal->Wait(timeout_millis);
}
void wxCondition::Signal()
{
m_internal->Signal();
}
void wxCondition::Broadcast()
{
m_internal->Broadcast();
}
// ----------------------------------------------------------------------------
// wxCriticalSection implementation
// wxCriticalSection
// ----------------------------------------------------------------------------
wxCriticalSection::wxCriticalSection()
{
#ifdef __WXDEBUG__
// Done this way to stop warnings during compilation about statement
// always being FALSE
int csSize = sizeof(CRITICAL_SECTION);
int bSize = sizeof(m_buffer);
wxASSERT_MSG( csSize <= bSize,
_T("must increase buffer size in wx/thread.h") );
#endif
wxCOMPILE_TIME_ASSERT( sizeof(CRITICAL_SECTION) <= sizeof(m_buffer),
wxCriticalSectionBufferTooSmall );
::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
}
@ -549,6 +153,325 @@ void wxCriticalSection::Leave()
::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
}
// ----------------------------------------------------------------------------
// wxMutex
// ----------------------------------------------------------------------------
class wxMutexInternal
{
public:
wxMutexInternal(wxMutexType mutexType);
~wxMutexInternal();
bool IsOk() const { return m_mutex != NULL; }
wxMutexError Lock() { return LockTimeout(INFINITE); }
wxMutexError TryLock() { return LockTimeout(0); }
wxMutexError Unlock();
private:
wxMutexError LockTimeout(DWORD milliseconds);
HANDLE m_mutex;
};
// all mutexes are recursive under Win32 so we don't use mutexType
wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(mutexType))
{
// create a nameless (hence intra process and always private) mutex
m_mutex = ::CreateMutex
(
NULL, // default secutiry attributes
FALSE, // not initially locked
NULL // no name
);
if ( !m_mutex )
{
wxLogLastError(_T("CreateMutex()"));
}
}
wxMutexInternal::~wxMutexInternal()
{
if ( m_mutex )
{
if ( !::CloseHandle(m_mutex) )
{
wxLogLastError(_T("CloseHandle(mutex)"));
}
}
}
wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds)
{
DWORD rc = ::WaitForSingleObject(m_mutex, milliseconds);
if ( rc == WAIT_ABANDONED )
{
// the previous caller died without releasing the mutex, but now we can
// really lock it
wxLogDebug(_T("WaitForSingleObject() returned WAIT_ABANDONED"));
// use 0 timeout, normally we should always get it
rc = ::WaitForSingleObject(m_mutex, 0);
}
switch ( rc )
{
case WAIT_OBJECT_0:
// ok
break;
case WAIT_TIMEOUT:
return wxMUTEX_BUSY;
case WAIT_ABANDONED: // checked for above
default:
wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
// fall through
case WAIT_FAILED:
wxLogLastError(_T("WaitForSingleObject(mutex)"));
return wxMUTEX_MISC_ERROR;
}
return wxMUTEX_NO_ERROR;
}
wxMutexError wxMutexInternal::Unlock()
{
if ( !::ReleaseMutex(m_mutex) )
{
wxLogLastError(_("ReleaseMutex()"));
return wxMUTEX_MISC_ERROR;
}
return wxMUTEX_NO_ERROR;
}
// --------------------------------------------------------------------------
// wxSemaphore
// --------------------------------------------------------------------------
// a trivial wrapper around Win32 semaphore
class wxSemaphoreInternal
{
public:
wxSemaphoreInternal(int initialcount, int maxcount);
~wxSemaphoreInternal();
bool IsOk() const { return m_semaphore != NULL; }
wxSemaError Wait() { return WaitTimeout(INFINITE); }
wxSemaError TryWait() { return WaitTimeout(0); }
wxSemaError WaitTimeout(unsigned long milliseconds);
wxSemaError Post();
private:
HANDLE m_semaphore;
};
wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
{
if ( maxcount == 0 )
{
// make it practically infinite
maxcount = INT_MAX;
}
m_semaphore = ::CreateSemaphore
(
NULL, // default security attributes
initialcount,
maxcount,
NULL // no name
);
if ( !m_semaphore )
{
wxLogLastError(_T("CreateSemaphore()"));
}
}
wxSemaphoreInternal::~wxSemaphoreInternal()
{
if ( m_semaphore )
{
if ( !::CloseHandle(m_semaphore) )
{
wxLogLastError(_T("CloseHandle(semaphore)"));
}
}
}
wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
{
DWORD rc = ::WaitForSingleObject( m_semaphore, milliseconds );
switch ( rc )
{
case WAIT_OBJECT_0:
return wxSEMA_NO_ERROR;
case WAIT_TIMEOUT:
return wxSEMA_BUSY;
default:
wxLogLastError(_T("WaitForSingleObject(semaphore)"));
}
return wxSEMA_MISC_ERROR;
}
wxSemaError wxSemaphoreInternal::Post()
{
if ( !::ReleaseSemaphore(m_semaphore, 1, NULL /* ptr to previous count */) )
{
wxLogLastError(_T("ReleaseSemaphore"));
return wxSEMA_MISC_ERROR;
}
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
// ----------------------------------------------------------------------------
@ -1429,6 +1352,11 @@ bool WXDLLEXPORT wxIsWaitingForThread()
return gs_waitingForThread;
}
// ----------------------------------------------------------------------------
// include common implementation code
// ----------------------------------------------------------------------------
#include "wx/thrimpl.cpp"
#endif // wxUSE_THREADS
// vi:sts=4:sw=4:et

File diff suppressed because it is too large Load Diff