]> git.saurik.com Git - wxWidgets.git/commitdiff
using non-sleep version for GUI mutex, solves #12411
authorStefan Csomor <csomor@advancedconcepts.ch>
Mon, 6 Sep 2010 13:50:12 +0000 (13:50 +0000)
committerStefan Csomor <csomor@advancedconcepts.ch>
Mon, 6 Sep 2010 13:50:12 +0000 (13:50 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65473 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/thread.h
src/osx/core/evtloop_cf.cpp
src/unix/threadpsx.cpp

index 7e85ae23149f227d8786f027fb12ccfc5b5fe9be..ed9efa05bfef4daee6be941c543c31253155244d 100644 (file)
@@ -811,7 +811,7 @@ public:
 
 #if wxUSE_THREADS
 
 
 #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
     // 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();
 
     // 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();
     // 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
 #endif // MSW, OS/2
 
 #endif // wxUSE_THREADS
index 6dc470f8174d0d0ef5830b135d367f628991acbc..a28ccf4fda79782bbe4867920461286e793b5a77 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "wx/osx/private.h"
 #include "wx/osx/core/cfref.h"
 
 #include "wx/osx/private.h"
 #include "wx/osx/core/cfref.h"
+#include "wx/thread.h"
 
 #if wxUSE_GUI
     #include "wx/nonownedwnd.h"
 
 #if wxUSE_GUI
     #include "wx/nonownedwnd.h"
@@ -178,9 +179,7 @@ void wxCFEventLoop::ObserverCallBack(CFRunLoopObserverRef WXUNUSED(observer), in
         else
         {
 #if wxUSE_THREADS
         else
         {
 #if wxUSE_THREADS
-            wxMutexGuiLeave();
-            wxMilliSleep(20);
-            wxMutexGuiEnter();
+            wxMutexGuiLeaveOrEnter();
 #endif
         }
     }
 #endif
         }
     }
@@ -420,3 +419,139 @@ void wxCFEventLoop::Exit(int rc)
     m_shouldExit = true;
     DoStop();
 }
     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
index 031ade47b59acc933be89711ef0a8a22c331813e..13ad80722e991bd2ffe95087d7caf4eee451e863 100644 (file)
@@ -134,10 +134,12 @@ static wxMutex *gs_mutexDeleteThread = NULL;
 // gs_nThreadsBeingDeleted will have been deleted
 static wxCondition *gs_condAllDeleted = 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;
 // 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
 
 // 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
 //--------------------------------------------------------------------
 
 // wxThreadModule
 //--------------------------------------------------------------------
 
+#ifdef __WXOSX__
+void wxOSXThreadModuleOnInit();
+void wxOSXThreadModuleOnExit();
+#endif
+
 class wxThreadModule : public wxModule
 {
 public:
 class wxThreadModule : public wxModule
 {
 public:
@@ -1697,8 +1704,12 @@ bool wxThreadModule::OnInit()
 
     gs_mutexAllThreads = new wxMutex();
 
 
     gs_mutexAllThreads = new wxMutex();
 
+#ifdef __WXOSX__
+    wxOSXThreadModuleOnInit();
+#else
     gs_mutexGui = new wxMutex();
     gs_mutexGui->Lock();
     gs_mutexGui = new wxMutex();
     gs_mutexGui->Lock();
+#endif
 
     gs_mutexDeleteThread = new wxMutex();
     gs_condAllDeleted = new wxCondition(*gs_mutexDeleteThread);
 
     gs_mutexDeleteThread = new wxMutex();
     gs_condAllDeleted = new wxCondition(*gs_mutexDeleteThread);
@@ -1751,9 +1762,13 @@ void wxThreadModule::OnExit()
 
     delete gs_mutexAllThreads;
 
 
     delete gs_mutexAllThreads;
 
+#ifdef __WXOSX__
+    wxOSXThreadModuleOnExit();
+#else
     // destroy GUI mutex
     gs_mutexGui->Unlock();
     delete gs_mutexGui;
     // destroy GUI mutex
     gs_mutexGui->Unlock();
     delete gs_mutexGui;
+#endif
 
     // and free TLD slot
     (void)pthread_key_delete(gs_keySelf);
 
     // 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();
 void wxMutexGuiEnterImpl()
 {
     gs_mutexGui->Lock();
@@ -1811,6 +1828,8 @@ void wxMutexGuiLeaveImpl()
     gs_mutexGui->Unlock();
 }
 
     gs_mutexGui->Unlock();
 }
 
+#endif
+
 // ----------------------------------------------------------------------------
 // include common implementation code
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // include common implementation code
 // ----------------------------------------------------------------------------