using non-sleep version for GUI mutex, solves #12411

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65473 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Stefan Csomor 2010-09-06 13:50:12 +00:00
parent d377e9fe75
commit a94c4b8529
3 changed files with 160 additions and 4 deletions

View File

@ -811,7 +811,7 @@ public:
#if wxUSE_THREADS
#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__)
#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__) || defined(__WXOSX__)
// 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
@ -823,9 +823,11 @@ public:
// wakes up the main thread if it's sleeping inside ::GetMessage()
extern void WXDLLIMPEXP_BASE wxWakeUpMainThread();
#ifndef __WXOSX__
// return true if the main thread is waiting for some other to terminate:
// wxApp then should block all "dangerous" messages
extern bool WXDLLIMPEXP_BASE wxIsWaitingForThread();
#endif
#endif // MSW, OS/2
#endif // wxUSE_THREADS

View File

@ -38,6 +38,7 @@
#include "wx/osx/private.h"
#include "wx/osx/core/cfref.h"
#include "wx/thread.h"
#if wxUSE_GUI
#include "wx/nonownedwnd.h"
@ -178,9 +179,7 @@ void wxCFEventLoop::ObserverCallBack(CFRunLoopObserverRef WXUNUSED(observer), in
else
{
#if wxUSE_THREADS
wxMutexGuiLeave();
wxMilliSleep(20);
wxMutexGuiEnter();
wxMutexGuiLeaveOrEnter();
#endif
}
}
@ -420,3 +419,139 @@ void wxCFEventLoop::Exit(int rc)
m_shouldExit = true;
DoStop();
}
// TODO Move to thread_osx.cpp
#if wxUSE_THREADS
// ----------------------------------------------------------------------------
// GUI Serialization copied from MSW implementation
// ----------------------------------------------------------------------------
// if it's false, some secondary thread is holding the GUI lock
static bool gs_bGuiOwnedByMainThread = true;
// critical section which controls access to all GUI functions: any secondary
// thread (i.e. except the main one) must enter this crit section before doing
// any GUI calls
static wxCriticalSection *gs_critsectGui = NULL;
// critical section which protects gs_nWaitingForGui variable
static wxCriticalSection *gs_critsectWaitingForGui = NULL;
// number of threads waiting for GUI in wxMutexGuiEnter()
static size_t gs_nWaitingForGui = 0;
void wxOSXThreadModuleOnInit()
{
gs_critsectWaitingForGui = new wxCriticalSection();
gs_critsectGui = new wxCriticalSection();
gs_critsectGui->Enter();
}
void wxOSXThreadModuleOnExit()
{
if ( gs_critsectGui )
{
if ( !wxGuiOwnedByMainThread() )
{
gs_critsectGui->Enter();
gs_bGuiOwnedByMainThread = true;
}
gs_critsectGui->Leave();
wxDELETE(gs_critsectGui);
}
wxDELETE(gs_critsectWaitingForGui);
}
// wake up the main thread
void WXDLLIMPEXP_BASE wxWakeUpMainThread()
{
wxMacWakeUp();
}
void wxMutexGuiEnterImpl()
{
// this would dead lock everything...
wxASSERT_MSG( !wxThread::IsMain(),
wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
// the order in which we enter the critical sections here is crucial!!
// set the flag telling to the main thread that we want to do some GUI
{
wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
gs_nWaitingForGui++;
}
wxWakeUpMainThread();
// now we may block here because the main thread will soon let us in
// (during the next iteration of OnIdle())
gs_critsectGui->Enter();
}
void wxMutexGuiLeaveImpl()
{
wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
if ( wxThread::IsMain() )
{
gs_bGuiOwnedByMainThread = false;
}
else
{
// decrement the number of threads waiting for GUI access now
wxASSERT_MSG( gs_nWaitingForGui > 0,
wxT("calling wxMutexGuiLeave() without entering it first?") );
gs_nWaitingForGui--;
wxWakeUpMainThread();
}
gs_critsectGui->Leave();
}
void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter()
{
wxASSERT_MSG( wxThread::IsMain(),
wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
if ( !gs_critsectWaitingForGui )
return;
wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
if ( gs_nWaitingForGui == 0 )
{
// no threads are waiting for GUI - so we may acquire the lock without
// any danger (but only if we don't already have it)
if ( !wxGuiOwnedByMainThread() )
{
gs_critsectGui->Enter();
gs_bGuiOwnedByMainThread = true;
}
//else: already have it, nothing to do
}
else
{
// some threads are waiting, release the GUI lock if we have it
if ( wxGuiOwnedByMainThread() )
wxMutexGuiLeave();
//else: some other worker thread is doing GUI
}
}
bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread()
{
return gs_bGuiOwnedByMainThread;
}
#endif

View File

@ -134,10 +134,12 @@ static wxMutex *gs_mutexDeleteThread = NULL;
// gs_nThreadsBeingDeleted will have been deleted
static wxCondition *gs_condAllDeleted = NULL;
#ifndef __WXOSX__
// this mutex must be acquired before any call to a GUI function
// (it's not inside #if wxUSE_GUI because this file is compiled as part
// of wxBase)
static wxMutex *gs_mutexGui = NULL;
#endif
// when we wait for a thread to exit, we're blocking on a condition which the
// thread signals in its SignalExit() method -- but this condition can't be a
@ -1671,6 +1673,11 @@ bool wxThread::IsPaused() const
// wxThreadModule
//--------------------------------------------------------------------
#ifdef __WXOSX__
void wxOSXThreadModuleOnInit();
void wxOSXThreadModuleOnExit();
#endif
class wxThreadModule : public wxModule
{
public:
@ -1697,8 +1704,12 @@ bool wxThreadModule::OnInit()
gs_mutexAllThreads = new wxMutex();
#ifdef __WXOSX__
wxOSXThreadModuleOnInit();
#else
gs_mutexGui = new wxMutex();
gs_mutexGui->Lock();
#endif
gs_mutexDeleteThread = new wxMutex();
gs_condAllDeleted = new wxCondition(*gs_mutexDeleteThread);
@ -1751,9 +1762,13 @@ void wxThreadModule::OnExit()
delete gs_mutexAllThreads;
#ifdef __WXOSX__
wxOSXThreadModuleOnExit();
#else
// destroy GUI mutex
gs_mutexGui->Unlock();
delete gs_mutexGui;
#endif
// and free TLD slot
(void)pthread_key_delete(gs_keySelf);
@ -1801,6 +1816,8 @@ static void DeleteThread(wxThread *This)
}
}
#ifndef __WXOSX__
void wxMutexGuiEnterImpl()
{
gs_mutexGui->Lock();
@ -1811,6 +1828,8 @@ void wxMutexGuiLeaveImpl()
gs_mutexGui->Unlock();
}
#endif
// ----------------------------------------------------------------------------
// include common implementation code
// ----------------------------------------------------------------------------