#include "wx/osx/private.h"
#include "wx/osx/core/cfref.h"
+#include "wx/thread.h"
#if wxUSE_GUI
#include "wx/nonownedwnd.h"
else
{
#if wxUSE_THREADS
- wxMutexGuiLeave();
- wxMilliSleep(20);
- wxMutexGuiEnter();
+ wxMutexGuiLeaveOrEnter();
#endif
}
}
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
// 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
// wxThreadModule
//--------------------------------------------------------------------
+#ifdef __WXOSX__
+void wxOSXThreadModuleOnInit();
+void wxOSXThreadModuleOnExit();
+#endif
+
class wxThreadModule : public wxModule
{
public:
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);
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);
}
}
+#ifndef __WXOSX__
+
void wxMutexGuiEnterImpl()
{
gs_mutexGui->Lock();
gs_mutexGui->Unlock();
}
+#endif
+
// ----------------------------------------------------------------------------
// include common implementation code
// ----------------------------------------------------------------------------