]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/thrimpl.cpp
Make storing non-trivial data in wxThreadSpecificInfo possible.
[wxWidgets.git] / include / wx / thrimpl.cpp
index c1f13ec3d9f1998b97a93bd9ac3c65eb6cb6394b..737ff85fa1328b96113335aea3a5af74c35f447c 100644 (file)
@@ -1,10 +1,9 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        include/wx/thrimpl.cpp
+// Name:        wx/thrimpl.cpp
 // Purpose:     common part of wxThread Implementations
 // Author:      Vadim Zeitlin
 // Modified by:
 // Created:     04.06.02 (extracted from src/*/thread.cpp files)
-// RCS-ID:      $Id$
 // Copyright:   (c) Vadim Zeitlin (2002)
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -39,15 +38,23 @@ bool wxMutex::IsOk() const
 wxMutexError wxMutex::Lock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
-                 _T("wxMutex::Lock(): not initialized") );
+                 wxT("wxMutex::Lock(): not initialized") );
 
     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,
-                 _T("wxMutex::TryLock(): not initialized") );
+                 wxT("wxMutex::TryLock(): not initialized") );
 
     return m_internal->TryLock();
 }
@@ -55,7 +62,7 @@ wxMutexError wxMutex::TryLock()
 wxMutexError wxMutex::Unlock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
-                 _T("wxMutex::Unlock(): not initialized") );
+                 wxT("wxMutex::Unlock(): not initialized") );
 
     return m_internal->Unlock();
 }
@@ -64,19 +71,11 @@ wxMutexError wxMutex::Unlock()
 // wxConditionInternal
 // --------------------------------------------------------------------------
 
-#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__)
 // 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(__OS2__) || defined(__EMX__)
-void InterlockedIncrement(LONG *num)
-{
-  ::DosEnterCritSec();
-  (*num)++;
-  ::DosExitCritSec();
-}
-#endif
+#if defined(__WINDOWS__) || defined(__OS2__) || defined(__EMX__)
 
 class wxConditionInternal
 {
@@ -101,7 +100,7 @@ private:
     wxMutex& m_mutex;
     wxSemaphore m_semaphore;
 
-    DECLARE_NO_COPY_CLASS(wxConditionInternal)
+    wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
 };
 
 wxConditionInternal::wxConditionInternal(wxMutex& mutex)
@@ -115,73 +114,81 @@ wxConditionInternal::wxConditionInternal(wxMutex& mutex)
 wxCondError wxConditionInternal::Wait()
 {
     // increment the number of waiters
-    ::InterlockedIncrement(&m_numWaiters);
+    {
+        wxCriticalSectionLocker lock(m_csWaiters);
+        m_numWaiters++;
+    }
 
     m_mutex.Unlock();
 
-    // a potential race condition can occur here
-    //
-    // after a thread increments nwaiters, and unlocks the mutex and before the
-    // semaphore.Wait() is called, if another thread can cause a signal to be
-    // generated
-    //
-    // this race condition is handled by using a semaphore and incrementing the
-    // semaphore only if 'nwaiters' is greater that zero since the semaphore,
-    // can 'remember' signals the race condition will not occur
-
-    // wait ( if necessary ) and decrement semaphore
-    wxSemaError err = m_semaphore.Wait();
+    // 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;
-    else if ( err == wxSEMA_TIMEOUT )
-        return wxCOND_TIMEOUT;
-    else
-        return wxCOND_MISC_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)
 {
-    ::InterlockedIncrement(&m_numWaiters);
+    {
+        wxCriticalSectionLocker lock(m_csWaiters);
+        m_numWaiters++;
+    }
 
     m_mutex.Unlock();
 
-    // a race condition can occur at this point in the code
-    //
-    // please see the comments in Wait(), for details
-
     wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
 
+    m_mutex.Lock();
+
+    if ( err == wxSEMA_NO_ERROR )
+        return wxCOND_NO_ERROR;
+
     if ( err == wxSEMA_TIMEOUT )
     {
-        // another potential race condition exists here it is caused when a
-        // 'waiting' thread timesout, and returns from WaitForSingleObject, but
-        // has not yet decremented 'nwaiters'.
+        // 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
         //
-        // at this point if another thread calls signal() then the semaphore
-        // will be incremented, but the waiting thread will miss it.
-        //
-        // to handle this particular case, the waiting thread calls
-        // WaitForSingleObject again with a timeout of 0, after locking
-        // 'nwaiters_mutex'. this call does not block because of the zero
-        // timeout, but will allow the waiting thread to catch the missed
-        // signals.
+        // 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--;
 
-        if ( err != wxSEMA_NO_ERROR )
-        {
-            m_numWaiters--;
-        }
+        return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
     }
 
-    m_mutex.Lock();
+    // undo m_numWaiters++ above in case of an error
+    {
+        wxCriticalSectionLocker lock(m_csWaiters);
+        m_numWaiters--;
+    }
 
-    return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR
-                                  : err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT
-                                                          : wxCOND_MISC_ERROR;
+    return wxCOND_MISC_ERROR;
 }
 
 wxCondError wxConditionInternal::Signal()
@@ -214,7 +221,8 @@ wxCondError wxConditionInternal::Broadcast()
 
     return wxCOND_NO_ERROR;
 }
-#endif
+
+#endif // __WINDOWS__ || __OS2__ || __EMX__
 
 // ----------------------------------------------------------------------------
 // wxCondition
@@ -244,7 +252,7 @@ bool wxCondition::IsOk() const
 wxCondError wxCondition::Wait()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
-                 _T("wxCondition::Wait(): not initialized") );
+                 wxT("wxCondition::Wait(): not initialized") );
 
     return m_internal->Wait();
 }
@@ -252,7 +260,7 @@ wxCondError wxCondition::Wait()
 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);
 }
@@ -260,7 +268,7 @@ wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
 wxCondError wxCondition::Signal()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
-                 _T("wxCondition::Signal(): not initialized") );
+                 wxT("wxCondition::Signal(): not initialized") );
 
     return m_internal->Signal();
 }
@@ -268,7 +276,7 @@ wxCondError wxCondition::Signal()
 wxCondError wxCondition::Broadcast()
 {
     wxCHECK_MSG( m_internal, wxCOND_INVALID,
-                 _T("wxCondition::Broadcast(): not initialized") );
+                 wxT("wxCondition::Broadcast(): not initialized") );
 
     return m_internal->Broadcast();
 }
@@ -300,7 +308,7 @@ bool wxSemaphore::IsOk() const
 wxSemaError wxSemaphore::Wait()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
-                 _T("wxSemaphore::Wait(): not initialized") );
+                 wxT("wxSemaphore::Wait(): not initialized") );
 
     return m_internal->Wait();
 }
@@ -308,7 +316,7 @@ wxSemaError wxSemaphore::Wait()
 wxSemaError wxSemaphore::TryWait()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
-                 _T("wxSemaphore::TryWait(): not initialized") );
+                 wxT("wxSemaphore::TryWait(): not initialized") );
 
     return m_internal->TryWait();
 }
@@ -316,7 +324,7 @@ wxSemaError wxSemaphore::TryWait()
 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);
 }
@@ -324,8 +332,18 @@ wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
 wxSemaError wxSemaphore::Post()
 {
     wxCHECK_MSG( m_internal, wxSEMA_INVALID,
-                 _T("wxSemaphore::Post(): not initialized") );
+                 wxT("wxSemaphore::Post(): not initialized") );
 
     return m_internal->Post();
 }
 
+// ----------------------------------------------------------------------------
+// wxThread
+// ----------------------------------------------------------------------------
+
+#include "wx/utils.h"
+
+void wxThread::Sleep(unsigned long milliseconds)
+{
+    wxMilliSleep(milliseconds);
+}