X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8d5eff606ae62a36ea2ccecc017a810081cdc22d..3a0a5ada86913e591479c1150d23135b0fe5e7e6:/src/unix/threadpsx.cpp diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp index f097dd3af2..72be919335 100644 --- a/src/unix/threadpsx.cpp +++ b/src/unix/threadpsx.cpp @@ -2,13 +2,14 @@ // Name: threadpsx.cpp // Purpose: wxThread (Posix) Implementation // Author: Original from Wolfram Gloger/Guilhem Lavaux -// Modified by: +// Modified by: K. S. Sreeram (2002): POSIXified wxCondition, added wxSemaphore // Created: 04/22/98 // RCS-ID: $Id$ // Copyright: (c) Wolfram Gloger (1996, 1997) // Guilhem Lavaux (1998) // Vadim Zeitlin (1999-2002) // Robert Roebling (1999) +// K. S. Sreeram (2002) // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -34,6 +35,7 @@ #include "wx/log.h" #include "wx/intl.h" #include "wx/dynarray.h" +#include "wx/timer.h" #include #include @@ -72,15 +74,6 @@ static const wxThread::ExitCode EXITCODE_CANCELLED = (wxThread::ExitCode)-1; // our trace mask #define TRACE_THREADS _T("thread") -// ---------------------------------------------------------------------------- -// pseudo template types -// ---------------------------------------------------------------------------- - -WX_DECLARE_LIST(pthread_mutex_t, wxMutexList); - -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxMutexList); - // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- @@ -88,35 +81,6 @@ WX_DEFINE_LIST(wxMutexList); static void ScheduleThreadForDeletion(); static void DeleteThread(wxThread *This); -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// same as wxMutexLocker but for "native" mutex -class MutexLock -{ -public: - MutexLock(pthread_mutex_t& mutex) - { - m_mutex = &mutex; - if ( pthread_mutex_lock(m_mutex) != 0 ) - { - wxLogDebug(_T("pthread_mutex_lock() failed")); - } - } - - ~MutexLock() - { - if ( pthread_mutex_unlock(m_mutex) != 0 ) - { - wxLogDebug(_T("pthread_mutex_unlock() failed")); - } - } - -private: - pthread_mutex_t *m_mutex; -}; - // ---------------------------------------------------------------------------- // types // ---------------------------------------------------------------------------- @@ -143,7 +107,7 @@ static pthread_key_t gs_keySelf; static size_t gs_nThreadsBeingDeleted = 0; // a mutex to protect gs_nThreadsBeingDeleted -static pthread_mutex_t gs_mutexDeleteThread; +static wxMutex *gs_mutexDeleteThread = (wxMutex *)NULL; // and a condition variable which will be signaled when all // gs_nThreadsBeingDeleted will have been deleted @@ -174,6 +138,8 @@ public: private: pthread_mutex_t m_mutex; + + friend class wxConditionInternal; }; wxMutexInternal::wxMutexInternal() @@ -342,291 +308,368 @@ wxMutexError wxMutex::Unlock() return m_internal->Unlock(); } -// ============================================================================ +// =========================================================================== // wxCondition implementation -// ============================================================================ +// =========================================================================== -// ---------------------------------------------------------------------------- +// --------------------------------------------------------------------------- // wxConditionInternal -// ---------------------------------------------------------------------------- +// --------------------------------------------------------------------------- -// The native POSIX condition variables are dumb: if the condition is signaled -// before another thread starts to wait on it, the signal is lost and so this -// other thread will be never woken up. It's much more convenient to us to -// remember that the condition was signaled and to return from Wait() -// immediately in this case (this is more like Win32 automatic event objects) class wxConditionInternal { public: - wxConditionInternal(); + wxConditionInternal(wxMutex& mutex); ~wxConditionInternal(); - // wait with the given timeout or indefinitely if NULL - bool Wait(const timespec* ts = NULL); + void Wait(); - void Signal(bool all = FALSE); + bool Wait( const timespec *ts ); -private: - // the number of Signal() calls queued - // - // changed by Signal(), accessed by Wait() - // - // protected by m_mutexSignalCount - size_t m_nSignalsMissed; - - // protects access to m_nSignalsMissed - pthread_mutex_t m_mutexSignalCount; + void Signal(); - // serializes Broadcast() and/or Signal() calls - // - // TODO: I'm not sure if this is really needed but it shouldn't harm - // neither (except for efficiency condierations). However MSW doesn't - // do this so maybe we shouldn't do it here neither? (VZ) - pthread_mutex_t m_mutexSignal; + void Broadcast(); - // a condition variable must be always used with a mutex and so we maintain - // a list of mutexes - one for each thread that calls Wait(). - // - // access to this list must be protected by m_mutexListContents - wxMutexList m_mutexes; - - // the condition itself - pthread_cond_t m_condition; +private: + // get the POSIX mutex associated with us + pthread_mutex_t *GetMutex() const { return &m_mutex.m_internal->m_mutex; } - // protects all accesses to m_mutexes list - pthread_mutex_t m_mutexListContents; + wxMutex& m_mutex; + pthread_cond_t m_cond; }; -wxConditionInternal::wxConditionInternal() +wxConditionInternal::wxConditionInternal(wxMutex& mutex) + : m_mutex(mutex) { - m_nSignalsMissed = 0; - - if ( pthread_cond_init(&m_condition, (pthread_condattr_t *)NULL) != 0 ) - { - // this is supposed to never happen - wxFAIL_MSG( _T("pthread_cond_init() failed") ); - } - - if ( pthread_mutex_init(&m_mutexSignalCount, NULL) != 0 || - pthread_mutex_init(&m_mutexListContents, NULL) != 0 || - pthread_mutex_init(&m_mutexSignal, NULL) != 0 ) + if ( pthread_cond_init( &m_cond, NULL ) != 0 ) { - // neither this - wxFAIL_MSG( _T("wxCondition: pthread_mutex_init() failed") ); + wxLogDebug(_T("pthread_cond_init() failed")); } } wxConditionInternal::~wxConditionInternal() { - if ( pthread_cond_destroy( &m_condition ) != 0 ) + if ( pthread_cond_destroy( &m_cond ) != 0 ) { - wxLogDebug(_T("Failed to destroy condition variable (some " - "threads are probably still waiting on it?)")); + wxLogDebug(_T("pthread_cond_destroy() failed")); } +} - // the list of waiters mutexes must be empty by now - wxASSERT_MSG( !m_mutexes.GetFirst(), - _T("deleting condition someone is still waiting on?") ); - - if ( pthread_mutex_destroy( &m_mutexSignalCount ) != 0 || - pthread_mutex_destroy( &m_mutexListContents ) != 0 || - pthread_mutex_destroy( &m_mutexSignal ) != 0 ) +void wxConditionInternal::Wait() +{ + if ( pthread_cond_wait( &m_cond, GetMutex() ) != 0 ) { - wxLogDebug(_T("Failed to destroy mutex (it is probably locked)")); + wxLogDebug(_T("pthread_cond_wait() failed")); } } -bool wxConditionInternal::Wait(const timespec* ts) +bool wxConditionInternal::Wait( const timespec *ts ) { - { - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Wait: about to lock missed signal counter"), - this); - - MutexLock lock(m_mutexSignalCount); + int result = pthread_cond_timedwait( &m_cond, GetMutex(), ts ); + if ( result == ETIMEDOUT ) + return FALSE; - if ( m_nSignalsMissed ) - { - // the condition was signaled before we started to wait, just - // decrease the number of queued signals and return - m_nSignalsMissed--; + if ( result != 0 ) + { + wxLogDebug(_T("pthread_cond_timedwait() failed")); + } - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Wait: not waiting at all, count = %u"), - this, m_nSignalsMissed); + return TRUE; +} - return TRUE; - } +void wxConditionInternal::Signal() +{ + int result = pthread_cond_signal( &m_cond ); + if ( result != 0 ) +{ + wxFAIL_MSG( _T("pthread_cond_signal() failed") ); } +} - // we need to really wait, create a new mutex for this - pthread_mutex_t *mutex = new pthread_mutex_t; - if ( pthread_mutex_init(mutex, (pthread_mutexattr_t *)NULL) != 0 ) - { - // not supposed to happen - wxFAIL_MSG( _T("pthread_mutex_init() failed when starting waiting") ); +void wxConditionInternal::Broadcast() +{ + int result = pthread_cond_broadcast( &m_cond ); + if ( result != 0 ) +{ + wxFAIL_MSG( _T("pthread_cond_broadcast() failed") ); } +} - // lock the mutex before starting to wait on it - pthread_mutex_lock(mutex); - // lock the list before modifying it - wxMutexList::Node *mutexNode; - { - MutexLock lockList(m_mutexListContents); +// --------------------------------------------------------------------------- +// wxCondition +// --------------------------------------------------------------------------- - mutexNode = m_mutexes.Append(mutex); - } +wxCondition::wxCondition(wxMutex& mutex) +{ + m_internal = new wxConditionInternal( mutex ); +} - // calling wait function below unlocks the mutex and Signal() or - // Broadcast() will be able to continue to run now if they were - // blocking for it in the loop locking all mutexes) - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Wait(): starting to wait"), this); - int err = ts ? pthread_cond_timedwait(&m_condition, mutex, ts) - : pthread_cond_wait(&m_condition, mutex); - switch ( err ) - { - case 0: - // condition was signaled - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Wait(): ok"), this); - break; +wxCondition::~wxCondition() +{ + delete m_internal; +} - default: - wxLogDebug(_T("unexpected pthread_cond_[timed]wait() return")); - // fall through +void wxCondition::Wait() +{ + m_internal->Wait(); +} - case ETIMEDOUT: - case EINTR: - // wait interrupted or timeout elapsed - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Wait(): timeout/intr"), this); - } +bool wxCondition::Wait( unsigned long timeout_millis ) +{ + wxLongLong curtime = wxGetLocalTimeMillis(); + curtime += timeout_millis; + wxLongLong temp = curtime / 1000; + int sec = temp.GetLo(); + temp = temp * 1000; + temp = curtime - temp; + int millis = temp.GetLo(); - // delete the mutex we had used for waiting - { - MutexLock lock(m_mutexListContents); + timespec tspec; - pthread_mutex_t *m = mutexNode->GetData(); - pthread_mutex_unlock(m); - pthread_mutex_destroy(m); - delete m; + tspec.tv_sec = sec; + tspec.tv_nsec = millis * 1000L * 1000L; - m_mutexes.DeleteNode(mutexNode); - } + return m_internal->Wait(&tspec); +} - return err == 0; +void wxCondition::Signal() +{ + m_internal->Signal(); } -void wxConditionInternal::Signal(bool all) +void wxCondition::Broadcast() { - // make sure that only one Signal() or Broadcast() is in progress - MutexLock lock(m_mutexSignal); + m_internal->Broadcast(); +} - // this mutex has to be locked as well, so that during the entire Signal() - // call, no new Wait() is going to wreak havoc (it will block in the very - // beginning on this mutex instead) - MutexLock lockSignalCount(m_mutexSignalCount); +// =========================================================================== +// wxSemaphore implementation +// =========================================================================== - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Signal(): got signal count mutex"), - this); +// --------------------------------------------------------------------------- +// wxSemaphoreInternal +// --------------------------------------------------------------------------- - { - MutexLock lockList(m_mutexListContents); +class wxSemaphoreInternal +{ +public: + wxSemaphoreInternal( int initialcount, int maxcount ); - if ( !m_mutexes.GetFirst() ) - { - // nobody is waiting for us, just remember that the condition was - // signaled and don't do anything else for now - m_nSignalsMissed++; + void Wait(); + bool TryWait(); - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Signal(): no waiters, count = %u"), - this, m_nSignalsMissed); + bool Wait( unsigned long timeout_millis ); - return; - } + void Post(); + +private: + wxMutex m_mutex; + wxCondition m_cond; + + int count, + maxcount; +}; + +wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount ) + : m_cond(m_mutex) +{ + + if ( (initialcount < 0) || ((maxcount > 0) && (initialcount > maxcount)) ) + { + wxFAIL_MSG( _T("wxSemaphore: invalid initial count") ); } - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Signal(): acquiring all mutexes"), this); + maxcount = maxcount; + count = initialcount; +} - // All mutexes on the list have to be locked. This means that execution of - // Signal() goes on as soon as all pending Wait() calls have called - // pthread_cond_wait() (where the mutex gets unlocked internally) - wxMutexList::Node *node; - for ( node = m_mutexes.GetFirst(); node; node = node->GetNext() ) +void wxSemaphoreInternal::Wait() +{ + wxMutexLocker locker(m_mutex); + + while ( count <= 0 ) { - pthread_mutex_lock(node->GetData()); + m_cond.Wait(); } - // now we can finally signal it - wxLogTrace(TRACE_THREADS, _T("wxCondition(%08x)::Signal(): preparing to %s"), - this, all ? _T("broadcast") : _T("signal")); + count--; +} + +bool wxSemaphoreInternal::TryWait() +{ + wxMutexLocker locker(m_mutex); + + if ( count <= 0 ) + return FALSE; + + count--; + + return TRUE; +} + +bool wxSemaphoreInternal::Wait( unsigned long timeout_millis ) +{ + wxMutexLocker locker(m_mutex); + + wxLongLong startTime = wxGetLocalTimeMillis(); - int err = all ? pthread_cond_broadcast(&m_condition) - : pthread_cond_signal(&m_condition); - if ( err ) + while ( count <= 0 ) { - // shouldn't ever happen - wxFAIL_MSG(_T("pthread_cond_{broadcast|signal}() failed")); + wxLongLong elapsed = wxGetLocalTimeMillis() - startTime; + long remainingTime = (long)timeout_millis - (long)elapsed.GetLo(); + if ( remainingTime <= 0 ) + return FALSE; + + bool result = m_cond.Wait( remainingTime ); + if ( !result ) + return FALSE; } - // unlock all mutexes so that the threads blocking in their Wait()s could - // continue running - for ( node = m_mutexes.GetFirst(); node; node = node->GetNext() ) + count--; + + return TRUE; +} + +void wxSemaphoreInternal::Post() +{ + wxMutexLocker locker(m_mutex); + + if ( maxcount > 0 && count == maxcount ) { - pthread_mutex_unlock(node->GetData()); + wxFAIL_MSG( _T("wxSemaphore::Post() overflow") ); } - wxLogTrace(TRACE_THREADS, - _T("wxCondition(%08x)::Signal(): exiting"), this); + count++; + + m_cond.Signal(); } -// ---------------------------------------------------------------------------- -// wxCondition -// ---------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +// wxSemaphore +// -------------------------------------------------------------------------- -wxCondition::wxCondition() +wxSemaphore::wxSemaphore( int initialcount, int maxcount ) { - m_internal = new wxConditionInternal; + m_internal = new wxSemaphoreInternal( initialcount, maxcount ); } -wxCondition::~wxCondition() +wxSemaphore::~wxSemaphore() { delete m_internal; } -void wxCondition::Wait() +void wxSemaphore::Wait() { - (void)m_internal->Wait(); + m_internal->Wait(); } -bool wxCondition::Wait(unsigned long sec, unsigned long nsec) +bool wxSemaphore::TryWait() { - timespec tspec; - - tspec.tv_sec = time(0L) + sec; // FIXME is time(0) correct here? - tspec.tv_nsec = nsec; - - return m_internal->Wait(&tspec); + return m_internal->TryWait(); } -void wxCondition::Signal() +bool wxSemaphore::Wait( unsigned long timeout_millis ) { - m_internal->Signal(); + return m_internal->Wait( timeout_millis ); } -void wxCondition::Broadcast() +void wxSemaphore::Post() { - m_internal->Signal(TRUE /* all */); + m_internal->Post(); } -// ============================================================================ +// This class is used by wxThreadInternal to support Delete() on +// a detached thread +class wxRefCountedCondition +{ +public: + // start with a initial reference count of 1 + wxRefCountedCondition() + { + m_refCount = 1; + m_signaled = FALSE; + + m_mutex = new wxMutex(); + m_cond = new wxCondition( *m_mutex ); + } + + // increment the reference count + void AddRef() + { + wxMutexLocker locker( *m_mutex ); + + m_refCount++; + } + + // decrement the reference count if reference count is zero then delete the + // object + void DeleteRef() + { + bool shouldDelete = FALSE; + + m_mutex->Lock(); + + if ( --m_refCount == 0 ) + { + shouldDelete = TRUE; + } + + m_mutex->Unlock(); + + if ( shouldDelete ) + { + delete this; + } + } + + + // sets the object to signaled this signal will be a persistent signal all + // further Wait()s on the object will return without blocking + void SetSignaled() + { + wxMutexLocker locker( *m_mutex ); + + m_signaled = TRUE; + + m_cond->Broadcast(); + } + + // wait till the object is signaled if the object was already signaled then + // return immediately + void Wait() + { + wxMutexLocker locker( *m_mutex ); + + if ( !m_signaled ) + { + m_cond->Wait(); + } + } + +private: + int m_refCount; + + wxMutex *m_mutex; + wxCondition *m_cond; + + bool m_signaled; + + // Cannot delete this object directly, call DeleteRef() instead + ~wxRefCountedCondition() + { + delete m_cond; + delete m_mutex; + } + + // suppress gcc warning about the class having private dtor and not having + // friend (so what??) + friend class wxDummyFriend; +}; + +// =========================================================================== // wxThread implementation -// ============================================================================ +// =========================================================================== // the thread callback functions must have the C linkage extern "C" @@ -662,7 +705,7 @@ public: // wake up threads waiting for our termination void SignalExit(); // wake up threads waiting for our start - void SignalRun() { m_condRun.Signal(); } + void SignalRun() { m_semRun.Post(); } // go to sleep until Resume() is called void Pause(); // resume the thread @@ -712,7 +755,7 @@ private: // this flag is set when the thread should terminate bool m_cancelled; - // this flag is set when the thread is blocking on m_condSuspend + // this flag is set when the thread is blocking on m_semSuspend bool m_isPaused; // the thread exit code - only used for joinable (!detached) threads and @@ -726,22 +769,18 @@ private: bool m_shouldBroadcast; bool m_isDetached; - // VZ: it's possible that we might do with less than three different - // condition objects - for example, m_condRun and m_condEnd a priori - // won't be used in the same time. But for now I prefer this may be a - // bit less efficient but safer solution of having distinct condition - // variables for each purpose. - - // this condition is signaled by Run() and the threads Entry() is not + // this semaphore is posted by Run() and the threads Entry() is not // called before it is done - wxCondition m_condRun; + wxSemaphore m_semRun; // this one is signaled when the thread should resume after having been // Pause()d - wxCondition m_condSuspend; + wxSemaphore m_semSuspend; // finally this one is signalled when the thread exits - wxCondition m_condEnd; + // we are using a reference counted condition to support + // Delete() for a detached thread + wxRefCountedCondition *m_condEnd; }; // ---------------------------------------------------------------------------- @@ -779,8 +818,8 @@ void *wxThreadInternal::PthreadStart(wxThread *thread) pthread_cleanup_push(wxPthreadCleanup, thread); #endif // HAVE_THREAD_CLEANUP_FUNCTIONS - // wait for the condition to be signaled from Run() - pthread->m_condRun.Wait(); + // wait for the semaphore to be posted from Run() + pthread->m_semRun.Wait(); // test whether we should run the run at all - may be it was deleted // before it started to Run()? @@ -874,17 +913,20 @@ wxThreadInternal::wxThreadInternal() m_threadId = 0; m_exitcode = 0; - // set to TRUE only when the thread starts waiting on m_condSuspend + // set to TRUE only when the thread starts waiting on m_semSuspend m_isPaused = FALSE; // defaults for joinable threads m_shouldBeJoined = TRUE; m_shouldBroadcast = TRUE; m_isDetached = FALSE; + + m_condEnd = new wxRefCountedCondition(); } wxThreadInternal::~wxThreadInternal() { + m_condEnd->DeleteRef(); } wxThreadError wxThreadInternal::Run() @@ -907,14 +949,22 @@ void wxThreadInternal::Wait() wxMutexGuiLeave(); bool isDetached = m_isDetached; - wxThreadIdType id = GetId(); + wxThreadIdType id = (wxThreadIdType) GetId(); wxLogTrace(TRACE_THREADS, _T("Starting to wait for thread %ld to exit."), id); // wait until the thread terminates (we're blocking in _another_ thread, // of course) - m_condEnd.Wait(); + + // a reference counting condition is used to handle the + // case where a detached thread deletes itself + // before m_condEnd->Wait() returns + // in this case the deletion of the condition object is deferred until + // all Wait()ing threads have finished calling DeleteRef() + m_condEnd->AddRef(); + m_condEnd->Wait(); + m_condEnd->DeleteRef(); wxLogTrace(TRACE_THREADS, _T("Finished waiting for thread %ld."), id); @@ -959,7 +1009,7 @@ void wxThreadInternal::SignalExit() wxLogTrace(TRACE_THREADS, _T("Thread %ld signals end condition."), GetId()); - m_condEnd.Broadcast(); + m_condEnd->SetSignaled(); } } @@ -972,8 +1022,8 @@ void wxThreadInternal::Pause() wxLogTrace(TRACE_THREADS, _T("Thread %ld goes to sleep."), GetId()); - // wait until the condition is signaled from Resume() - m_condSuspend.Wait(); + // wait until the semaphore is Post()ed from Resume() + m_semSuspend.Wait(); } void wxThreadInternal::Resume() @@ -988,7 +1038,7 @@ void wxThreadInternal::Resume() wxLogTrace(TRACE_THREADS, _T("Waking up thread %ld"), GetId()); // wake up Pause() - m_condSuspend.Signal(); + m_semSuspend.Post(); // reset the flag SetReallyPaused(FALSE); @@ -1285,7 +1335,7 @@ unsigned int wxThread::GetPriority() const wxThreadIdType wxThread::GetId() const { - return m_internal->GetId(); + return (wxThreadIdType) m_internal->GetId(); } // ----------------------------------------------------------------------------- @@ -1389,7 +1439,7 @@ wxThreadError wxThread::Delete(ExitCode *rc) { case STATE_NEW: // we need to wake up the thread so that PthreadStart() will - // terminate - right now it's blocking on m_condRun + // terminate - right now it's blocking on m_semRun m_internal->SignalRun(); // fall through @@ -1572,7 +1622,8 @@ wxThread::~wxThread() // is not called for the joinable threads, so do it here if ( !m_isDetached ) { - MutexLock lock(gs_mutexDeleteThread); + wxMutexLocker lock( *gs_mutexDeleteThread ); + gs_nThreadsBeingDeleted--; wxLogTrace(TRACE_THREADS, _T("%u scheduled for deletion threads left."), @@ -1648,9 +1699,8 @@ bool wxThreadModule::OnInit() gs_mutexGui->Lock(); #endif // wxUSE_GUI - // under Solaris we get a warning from CC when using - // PTHREAD_MUTEX_INITIALIZER, so do it dynamically - pthread_mutex_init(&gs_mutexDeleteThread, NULL); + gs_mutexDeleteThread = new wxMutex(); + gs_condAllDeleted = new wxCondition( *gs_mutexDeleteThread ); return TRUE; } @@ -1661,18 +1711,19 @@ void wxThreadModule::OnExit() // are there any threads left which are being deleted right now? size_t nThreadsBeingDeleted; + { - MutexLock lock(gs_mutexDeleteThread); + wxMutexLocker lock( *gs_mutexDeleteThread ); nThreadsBeingDeleted = gs_nThreadsBeingDeleted; - } - if ( nThreadsBeingDeleted > 0 ) - { - wxLogTrace(TRACE_THREADS, _T("Waiting for %u threads to disappear"), - nThreadsBeingDeleted); + if ( nThreadsBeingDeleted > 0 ) +{ + wxLogTrace(TRACE_THREADS, _T("Waiting for %u threads to disappear"), + nThreadsBeingDeleted); - // have to wait until all of them disappear - gs_condAllDeleted->Wait(); + // have to wait until all of them disappear + gs_condAllDeleted->Wait(); + } } // terminate any threads left @@ -1699,6 +1750,9 @@ void wxThreadModule::OnExit() // and free TLD slot (void)pthread_key_delete(gs_keySelf); + + delete gs_condAllDeleted; + delete gs_mutexDeleteThread; } // ---------------------------------------------------------------------------- @@ -1707,12 +1761,7 @@ void wxThreadModule::OnExit() static void ScheduleThreadForDeletion() { - MutexLock lock(gs_mutexDeleteThread); - - if ( gs_nThreadsBeingDeleted == 0 ) - { - gs_condAllDeleted = new wxCondition; - } + wxMutexLocker lock( *gs_mutexDeleteThread ); gs_nThreadsBeingDeleted++; @@ -1725,17 +1774,15 @@ static void DeleteThread(wxThread *This) { // gs_mutexDeleteThread should be unlocked before signalling the condition // or wxThreadModule::OnExit() would deadlock - { - MutexLock lock(gs_mutexDeleteThread); + wxMutexLocker locker( *gs_mutexDeleteThread ); - wxLogTrace(TRACE_THREADS, _T("Thread %ld auto deletes."), This->GetId()); + wxLogTrace(TRACE_THREADS, _T("Thread %ld auto deletes."), This->GetId()); - delete This; + delete This; - wxCHECK_RET( gs_nThreadsBeingDeleted > 0, + wxCHECK_RET( gs_nThreadsBeingDeleted > 0, _T("no threads scheduled for deletion, yet we delete " "one?") ); - } wxLogTrace(TRACE_THREADS, _T("%u scheduled for deletion threads left."), gs_nThreadsBeingDeleted - 1); @@ -1744,9 +1791,6 @@ static void DeleteThread(wxThread *This) { // no more threads left, signal it gs_condAllDeleted->Signal(); - - delete gs_condAllDeleted; - gs_condAllDeleted = (wxCondition *)NULL; } }