]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/thrimpl.cpp
support SDK < 10.6, fixes #14902
[wxWidgets.git] / include / wx / thrimpl.cpp
index b01436a220a8a847e1b348be26475bff8903ed9e..585367d5e98392d54457f56448e9eff35b772dd3 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
-// Name:        include/wx/thrimpl.cpp
+// Name:        wx/thrimpl.cpp
 // Purpose:     common part of wxThread Implementations
 // Author:      Vadim Zeitlin
 // Modified by:
 // Purpose:     common part of wxThread Implementations
 // Author:      Vadim Zeitlin
 // Modified by:
@@ -39,15 +39,23 @@ bool wxMutex::IsOk() const
 wxMutexError wxMutex::Lock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
 wxMutexError wxMutex::Lock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
-                 _T("wxMutex::Lock(): not initialized") );
+                 wxT("wxMutex::Lock(): not initialized") );
 
     return m_internal->Lock();
 }
 
 
     return m_internal->Lock();
 }
 
+wxMutexError wxMutex::LockTimeout(unsigned long ms)
+{
+    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
+                 wxT("wxMutex::Lock(): not initialized") );
+
+    return m_internal->Lock(ms);
+}
+
 wxMutexError wxMutex::TryLock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
 wxMutexError wxMutex::TryLock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
-                 _T("wxMutex::TryLock(): not initialized") );
+                 wxT("wxMutex::TryLock(): not initialized") );
 
     return m_internal->TryLock();
 }
 
     return m_internal->TryLock();
 }
@@ -55,11 +63,168 @@ wxMutexError wxMutex::TryLock()
 wxMutexError wxMutex::Unlock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
 wxMutexError wxMutex::Unlock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
-                 _T("wxMutex::Unlock(): not initialized") );
+                 wxT("wxMutex::Unlock(): not initialized") );
 
     return m_internal->Unlock();
 }
 
 
     return m_internal->Unlock();
 }
 
+// --------------------------------------------------------------------------
+// wxConditionInternal
+// --------------------------------------------------------------------------
+
+// Win32 and OS/2 don't have explicit support for the POSIX condition
+// variables and their events/event semaphores have quite different semantics,
+// so we reimplement the conditions from scratch using the mutexes and
+// semaphores
+#if defined(__WINDOWS__) || defined(__OS2__) || defined(__EMX__)
+
+class wxConditionInternal
+{
+public:
+    wxConditionInternal(wxMutex& mutex);
+
+    bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); }
+
+    wxCondError Wait();
+    wxCondError WaitTimeout(unsigned long milliseconds);
+
+    wxCondError Signal();
+    wxCondError Broadcast();
+
+private:
+    // the number of threads currently waiting for this condition
+    LONG m_numWaiters;
+
+    // the critical section protecting m_numWaiters
+    wxCriticalSection m_csWaiters;
+
+    wxMutex& m_mutex;
+    wxSemaphore m_semaphore;
+
+    wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
+};
+
+wxConditionInternal::wxConditionInternal(wxMutex& mutex)
+                   : m_mutex(mutex)
+{
+    // another thread can't access it until we return from ctor, so no need to
+    // protect access to m_numWaiters here
+    m_numWaiters = 0;
+}
+
+wxCondError wxConditionInternal::Wait()
+{
+    // increment the number of waiters
+    {
+        wxCriticalSectionLocker lock(m_csWaiters);
+        m_numWaiters++;
+    }
+
+    m_mutex.Unlock();
+
+    // after unlocking the mutex other threads may Signal() us, but it is ok
+    // now as we had already incremented m_numWaiters so Signal() will post the
+    // semaphore and decrement m_numWaiters back even if it is called before we
+    // start to Wait()
+    const wxSemaError err = m_semaphore.Wait();
+
+    m_mutex.Lock();
+
+    if ( err == wxSEMA_NO_ERROR )
+    {
+        // m_numWaiters was decremented by Signal()
+        return wxCOND_NO_ERROR;
+    }
+
+    // but in case of an error we need to do it manually
+    {
+        wxCriticalSectionLocker lock(m_csWaiters);
+        m_numWaiters--;
+    }
+
+    return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
+}
+
+wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
+{
+    {
+        wxCriticalSectionLocker lock(m_csWaiters);
+        m_numWaiters++;
+    }
+
+    m_mutex.Unlock();
+
+    wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
+
+    m_mutex.Lock();
+
+    if ( err == wxSEMA_NO_ERROR )
+        return wxCOND_NO_ERROR;
+
+    if ( err == wxSEMA_TIMEOUT )
+    {
+        // a potential race condition exists here: it happens when a waiting
+        // thread times out but doesn't have time to decrement m_numWaiters yet
+        // before Signal() is called in another thread
+        //
+        // to handle this particular case, check the semaphore again after
+        // acquiring m_csWaiters lock -- this will catch the signals missed
+        // during this window
+        wxCriticalSectionLocker lock(m_csWaiters);
+
+        err = m_semaphore.WaitTimeout(0);
+        if ( err == wxSEMA_NO_ERROR )
+            return wxCOND_NO_ERROR;
+
+        // we need to decrement m_numWaiters ourselves as it wasn't done by
+        // Signal()
+        m_numWaiters--;
+
+        return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
+    }
+
+    // undo m_numWaiters++ above in case of an error
+    {
+        wxCriticalSectionLocker lock(m_csWaiters);
+        m_numWaiters--;
+    }
+
+    return wxCOND_MISC_ERROR;
+}
+
+wxCondError wxConditionInternal::Signal()
+{
+    wxCriticalSectionLocker lock(m_csWaiters);
+
+    if ( m_numWaiters > 0 )
+    {
+        // increment the semaphore by 1
+        if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
+            return wxCOND_MISC_ERROR;
+
+        m_numWaiters--;
+    }
+
+    return wxCOND_NO_ERROR;
+}
+
+wxCondError wxConditionInternal::Broadcast()
+{
+    wxCriticalSectionLocker lock(m_csWaiters);
+
+    while ( m_numWaiters > 0 )
+    {
+        if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
+            return wxCOND_MISC_ERROR;
+
+        m_numWaiters--;
+    }
+
+    return wxCOND_NO_ERROR;
+}
+
+#endif // __WINDOWS__ || __OS2__ || __EMX__
+
 // ----------------------------------------------------------------------------
 // wxCondition
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // wxCondition
 // ----------------------------------------------------------------------------
@@ -88,7 +253,7 @@ bool wxCondition::IsOk() const
 wxCondError wxCondition::Wait()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
 wxCondError wxCondition::Wait()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
-                 _T("wxCondition::Wait(): not initialized") );
+                 wxT("wxCondition::Wait(): not initialized") );
 
     return m_internal->Wait();
 }
 
     return m_internal->Wait();
 }
@@ -96,7 +261,7 @@ wxCondError wxCondition::Wait()
 wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
 wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
-                 _T("wxCondition::Wait(): not initialized") );
+                 wxT("wxCondition::Wait(): not initialized") );
 
     return m_internal->WaitTimeout(milliseconds);
 }
 
     return m_internal->WaitTimeout(milliseconds);
 }
@@ -104,7 +269,7 @@ wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
 wxCondError wxCondition::Signal()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
 wxCondError wxCondition::Signal()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
-                 _T("wxCondition::Signal(): not initialized") );
+                 wxT("wxCondition::Signal(): not initialized") );
 
     return m_internal->Signal();
 }
 
     return m_internal->Signal();
 }
@@ -112,7 +277,7 @@ wxCondError wxCondition::Signal()
 wxCondError wxCondition::Broadcast()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
 wxCondError wxCondition::Broadcast()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
-                 _T("wxCondition::Broadcast(): not initialized") );
+                 wxT("wxCondition::Broadcast(): not initialized") );
 
     return m_internal->Broadcast();
 }
 
     return m_internal->Broadcast();
 }
@@ -144,7 +309,7 @@ bool wxSemaphore::IsOk() const
 wxSemaError wxSemaphore::Wait()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
 wxSemaError wxSemaphore::Wait()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
-                 _T("wxSemaphore::Wait(): not initialized") );
+                 wxT("wxSemaphore::Wait(): not initialized") );
 
     return m_internal->Wait();
 }
 
     return m_internal->Wait();
 }
@@ -152,7 +317,7 @@ wxSemaError wxSemaphore::Wait()
 wxSemaError wxSemaphore::TryWait()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
 wxSemaError wxSemaphore::TryWait()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
-                 _T("wxSemaphore::TryWait(): not initialized") );
+                 wxT("wxSemaphore::TryWait(): not initialized") );
 
     return m_internal->TryWait();
 }
 
     return m_internal->TryWait();
 }
@@ -160,7 +325,7 @@ wxSemaError wxSemaphore::TryWait()
 wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
 wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
-                 _T("wxSemaphore::WaitTimeout(): not initialized") );
+                 wxT("wxSemaphore::WaitTimeout(): not initialized") );
 
     return m_internal->WaitTimeout(milliseconds);
 }
 
     return m_internal->WaitTimeout(milliseconds);
 }
@@ -168,8 +333,18 @@ wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
 wxSemaError wxSemaphore::Post()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
 wxSemaError wxSemaphore::Post()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
-                 _T("wxSemaphore::Post(): not initialized") );
+                 wxT("wxSemaphore::Post(): not initialized") );
 
     return m_internal->Post();
 }
 
 
     return m_internal->Post();
 }
 
+// ----------------------------------------------------------------------------
+// wxThread
+// ----------------------------------------------------------------------------
+
+#include "wx/utils.h"
+
+void wxThread::Sleep(unsigned long milliseconds)
+{
+    wxMilliSleep(milliseconds);
+}