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:
parent
d377e9fe75
commit
a94c4b8529
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user