From 547b93ab0418dac65dec147df08922d76ce351f9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 29 Jan 2002 22:49:13 +0000 Subject: [PATCH] attempts to make wxCondition::Broadcast() work - it still doesn't git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@13919 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/thread.h | 24 +++---- src/unix/threadpsx.cpp | 158 ++++++++++++++++++++++++++--------------- 2 files changed, 113 insertions(+), 69 deletions(-) diff --git a/include/wx/thread.h b/include/wx/thread.h index 72c708e51f..1b7717fc6c 100644 --- a/include/wx/thread.h +++ b/include/wx/thread.h @@ -234,7 +234,7 @@ public: // signal the condition // wakes up one (and only one) of the waiting threads void Signal(); - // wakes up all threads waiting onthis condition + // wakes up all threads waiting on this condition void Broadcast(); private: @@ -254,6 +254,13 @@ private: // created by the wxThread object while "main thread" is the thread created // during the process initialization (a.k.a. the GUI thread) +// On VMS thread pointers are 64 bits (also needed for other systems??? +#ifdef __VMS + typedef unsigned long long wxThreadIdType; +#else + typedef unsigned long wxThreadIdType; +#endif + class wxThreadInternal; class WXDLLEXPORT wxThread { @@ -289,13 +296,8 @@ public: // Get the platform specific thread ID and return as a long. This // can be used to uniquely identify threads, even if they are not // wxThreads. This is used by wxPython. - // On VMS thread pointers are 64 bits (also needed for other systems??? -#ifdef __VMS - static unsigned long long GetCurrentId(); -#else - static unsigned long GetCurrentId(); -#endif - + static wxThreadIdType GetCurrentId(); + // sets the concurrency level: this is, roughly, the number of threads // the system tries to schedule to run in parallel. 0 means the // default value (usually acceptable, but may not yield the best @@ -381,11 +383,7 @@ public: // Get the thread ID - a platform dependent number which uniquely // identifies a thread inside a process -#ifdef __VMS - unsigned long long GetId() const; -#else - unsigned long GetId() const; -#endif + wxThreadIdType GetId() const; // called when the thread exits - in the context of this thread // diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp index e10fe97e82..7054897738 100644 --- a/src/unix/threadpsx.cpp +++ b/src/unix/threadpsx.cpp @@ -34,13 +34,13 @@ #include "wx/log.h" #include "wx/intl.h" #include "wx/dynarray.h" +#include "wx/listimpl.cpp" #include #include #include #include #include - #if HAVE_SCHED_H #include #endif @@ -257,6 +257,8 @@ wxMutexError wxMutex::Unlock() // remember that the condition was signaled and to return from Wait() // immediately in this case (this is more like Win32 automatic event objects) +WX_DECLARE_LIST(pthread_mutex_t, wxMutexList); + class wxConditionInternal { public: @@ -269,25 +271,32 @@ public: void Signal(); void Broadcast(); - void WaitDone(); - bool ShouldWait(); + void WaitDone(wxMutexList::Node *mutexnode); + wxMutexList::Node *ShouldWait(); bool HasWaiters(); private: - bool m_wasSignaled; // TRUE if condition was signaled while - // nobody waited for it - size_t m_nWaiters; // TRUE if someone already waits for us + void LockAllMutexes(); // locks all mutexes on the list + void UnlockAllMutexes(); // unlocks mutexes after signaling / broadcasting + + // TRUE if condition was signaled while nobody waited for it + bool m_wasSignaled; + + // protects access to vars above + pthread_mutex_t m_mutexProtect; - pthread_mutex_t m_mutexProtect; // protects access to vars above + // the mutexes which are used for the condition variable + wxMutexList m_mutexes; - pthread_mutex_t m_mutex; // the mutex used with the condition - pthread_cond_t m_condition; // the condition itself + // the condition itself + pthread_cond_t m_condition; }; +WX_DEFINE_LIST(wxMutexList); + wxConditionInternal::wxConditionInternal() { m_wasSignaled = FALSE; - m_nWaiters = 0; if ( pthread_cond_init(&m_condition, (pthread_condattr_t *)NULL) != 0 ) { @@ -295,19 +304,12 @@ wxConditionInternal::wxConditionInternal() wxFAIL_MSG( _T("pthread_cond_init() failed") ); } - if ( pthread_mutex_init(&m_mutex, (pthread_mutexattr_t *)NULL) != 0 || - pthread_mutex_init(&m_mutexProtect, NULL) != 0 ) + if ( pthread_mutex_init(&m_mutexProtect, NULL) != 0 ) { // neither this wxFAIL_MSG( _T("wxCondition: pthread_mutex_init() failed") ); } - // initially the mutex is locked, so no thread can Signal() or Broadcast() - // until another thread starts to Wait() - if ( pthread_mutex_lock(&m_mutex) != 0 ) - { - wxFAIL_MSG( _T("wxCondition: pthread_mutex_lock() failed") ); - } } wxConditionInternal::~wxConditionInternal() @@ -318,27 +320,40 @@ wxConditionInternal::~wxConditionInternal() "threads are probably still waiting on it?)")); } - if ( pthread_mutex_unlock( &m_mutex ) != 0 ) + for ( wxMutexList::Node *node = m_mutexes.GetFirst(); + node; + node = node->GetNext() ) { - wxLogDebug(_T("wxCondition: failed to unlock the mutex")); + pthread_mutex_t *currentmutex = node->GetData(); + if ( pthread_mutex_unlock( currentmutex ) != 0 ) + { + wxLogDebug(_T("wxCondition: failed to unlock the mutex")); + } else { + delete currentmutex; + } } - if ( pthread_mutex_destroy( &m_mutex ) != 0 || - pthread_mutex_destroy( &m_mutexProtect ) != 0 ) + m_mutexes.DeleteContents(TRUE); + + if ( pthread_mutex_destroy( &m_mutexProtect ) != 0 ) { wxLogDebug(_T("Failed to destroy mutex (it is probably locked)")); } } -void wxConditionInternal::WaitDone() +void wxConditionInternal::WaitDone(wxMutexList::Node *mutexnode) { MutexLock lock(m_mutexProtect); - m_wasSignaled = FALSE; - m_nWaiters--; + pthread_mutex_unlock(mutexnode->GetData()); + pthread_mutex_destroy(mutexnode->GetData()); + delete mutexnode->GetData(); + + m_mutexes.DeleteNode(mutexnode); + } -bool wxConditionInternal::ShouldWait() +wxMutexList::Node *wxConditionInternal::ShouldWait() { MutexLock lock(m_mutexProtect); @@ -348,20 +363,26 @@ bool wxConditionInternal::ShouldWait() // flag and return m_wasSignaled = FALSE; - return FALSE; + return NULL; } // we start to wait for it - m_nWaiters++; - return TRUE; + pthread_mutex_t *waitmutex = new pthread_mutex_t; + if ( pthread_mutex_init(waitmutex, (pthread_mutexattr_t *)NULL) != 0 ) + { + // neither this + wxFAIL_MSG( _T("wxCondition: pthread_mutex_init() failed when starting waiting") ); + } + + pthread_mutex_lock(waitmutex); + + return ( m_mutexes.Append(waitmutex) ); } bool wxConditionInternal::HasWaiters() { - MutexLock lock(m_mutexProtect); - - if ( m_nWaiters ) + if ( m_mutexes.GetCount() ) { // someone waits for us, signal the condition normally return TRUE; @@ -376,25 +397,29 @@ bool wxConditionInternal::HasWaiters() void wxConditionInternal::Wait() { - if ( ShouldWait() ) + wxMutexList::Node *ownmutexnode = ShouldWait(); + + if ( ownmutexnode ) { - if ( pthread_cond_wait( &m_condition, &m_mutex ) != 0 ) + if ( pthread_cond_wait( &m_condition, ownmutexnode->GetData() ) != 0 ) { // not supposed to ever happen wxFAIL_MSG( _T("pthread_cond_wait() failed") ); } - } - WaitDone(); + WaitDone(ownmutexnode); + } } bool wxConditionInternal::WaitWithTimeout(const timespec* ts) { bool ok; - if ( ShouldWait() ) + wxMutexList::Node *ownmutexnode = ShouldWait(); + + if ( ownmutexnode ) { - switch ( pthread_cond_timedwait( &m_condition, &m_mutex, ts ) ) + switch ( pthread_cond_timedwait( &m_condition, ownmutexnode->GetData(), ts ) ) { case 0: // condition signaled @@ -411,6 +436,7 @@ bool wxConditionInternal::WaitWithTimeout(const timespec* ts) // wait interrupted or timeout elapsed ok = FALSE; } + WaitDone(ownmutexnode); } else { @@ -418,36 +444,65 @@ bool wxConditionInternal::WaitWithTimeout(const timespec* ts) ok = TRUE; } - WaitDone(); return ok; } +void wxConditionInternal::LockAllMutexes() +{ + wxMutexList::Node *mutexnode = m_mutexes.GetFirst(); + while ( mutexnode ) + { + pthread_mutex_lock(mutexnode->GetData()); + mutexnode = mutexnode->GetNext(); + } +} + +void wxConditionInternal::UnlockAllMutexes() +{ + wxMutexList::Node *mutexnode = m_mutexes.GetFirst(); + while ( mutexnode ) + { + pthread_mutex_unlock(mutexnode->GetData()); + mutexnode = mutexnode->GetNext(); + } +} + void wxConditionInternal::Signal() { + // calls to HasWaiters() must be serialized + MutexLock lock(m_mutexProtect); + if ( HasWaiters() ) { - MutexLock lock(m_mutex); + // wait + LockAllMutexes(); if ( pthread_cond_signal( &m_condition ) != 0 ) { // shouldn't ever happen wxFAIL_MSG(_T("pthread_cond_signal() failed")); } + + UnlockAllMutexes(); } } void wxConditionInternal::Broadcast() { + MutexLock lock(m_mutexProtect); + if ( HasWaiters() ) { - MutexLock lock(m_mutex); + LockAllMutexes(); if ( pthread_cond_broadcast( &m_condition ) != 0 ) { // shouldn't ever happen wxFAIL_MSG(_T("pthread_cond_broadcast() failed")); } + + UnlockAllMutexes(); } } @@ -763,13 +818,10 @@ void wxThreadInternal::Wait() wxMutexGuiLeave(); bool isDetached = m_isDetached; -#ifdef __VMS - long long id = (long long)GetId(); -#else - long id = (long)GetId(); -#endif - wxLogTrace(TRACE_THREADS, _T("Starting to wait for thread %ld to exit."), - id); + wxThreadIdType id = 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) @@ -1142,15 +1194,9 @@ unsigned int wxThread::GetPriority() const return m_internal->GetPriority(); } -#ifdef __VMS -unsigned long long wxThread::GetId() const +wxThreadIdType wxThread::GetId() const { - return (unsigned long long)m_internal->GetId(); -#else -unsigned long wxThread::GetId() const -{ - return (unsigned long)m_internal->GetId(); -#endif + return m_internal->GetId(); } // ----------------------------------------------------------------------------- -- 2.47.2