]> git.saurik.com Git - wxWidgets.git/commitdiff
wxMutex changes (explicitly specify the type), return values for all wxMutex/wxSemaph...
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 6 Jun 2002 18:31:59 +0000 (18:31 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 6 Jun 2002 18:31:59 +0000 (18:31 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15761 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/thread.h
include/wx/thrimpl.cpp [new file with mode: 0644]
src/msw/thread.cpp
src/unix/threadpsx.cpp

index 319829ba71f509e6b1ba8f0e805bdd26111370f7..9917e594df689cd9cfb81df265b77061966455a3 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        thread.h
+// Name:        wx/thread.h
 // Purpose:     Thread API
 // Author:      Guilhem Lavaux
 // Modified by: Vadim Zeitlin (modifications partly inspired by omnithreads
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifndef __THREADH__
-#define __THREADH__
+#ifndef _WX_THREAD_H_
+#define _WX_THREAD_H_
 
 // ----------------------------------------------------------------------------
 // headers
 // ----------------------------------------------------------------------------
 
 // get the value of wxUSE_THREADS configuration flag
-#include "wx/setup.h"
+#include "wx/defs.h"
 
 #if wxUSE_THREADS
 
 
 enum wxMutexError
 {
-    wxMUTEX_NO_ERROR = 0,
-    wxMUTEX_DEAD_LOCK,      // Mutex has been already locked by THE CALLING thread
-    wxMUTEX_BUSY,           // Mutex has been already locked by ONE thread
-    wxMUTEX_UNLOCKED,
-    wxMUTEX_MISC_ERROR
+    wxMUTEX_NO_ERROR = 0,   // operation completed successfully
+    wxMUTEX_INVALID,        // mutex hasn't been initialized
+    wxMUTEX_DEAD_LOCK,      // mutex is already locked by the calling thread
+    wxMUTEX_BUSY,           // mutex is already locked by another thread
+    wxMUTEX_UNLOCKED,       // attempt to unlock a mutex which is not locked
+    wxMUTEX_MISC_ERROR      // any other error
+};
+
+enum wxCondError
+{
+    wxCOND_NO_ERROR = 0,
+    wxCOND_INVALID,
+    wxCOND_TIMEOUT,         // WaitTimeout() has timed out
+    wxCOND_MISC_ERROR
+};
+
+enum wxSemaError
+{
+    wxSEMA_NO_ERROR = 0,
+    wxSEMA_INVALID,         // semaphore hasn't been initialized successfully
+    wxSEMA_BUSY,            // returned by TryWait() if Wait() would block
+    wxSEMA_TIMEOUT,         // returned by WaitTimeout()
+    wxSEMA_OVERFLOW,        // Post() would increase counter past the max
+    wxSEMA_MISC_ERROR
 };
 
 enum wxThreadError
@@ -71,6 +90,37 @@ enum
     WXTHREAD_MAX_PRIORITY      = 100u
 };
 
+// There are 2 types of mutexes: normal mutexes and recursive ones. The attempt
+// to lock a normal mutex by a thread which already owns it results in
+// undefined behaviour (it always works under Windows, it will almost always
+// result in a deadlock under Unix). Locking a recursive mutex in such
+// situation always succeeds and it must be unlocked as many times as it has
+// been locked.
+//
+// However recursive mutexes have several important drawbacks: first, in the
+// POSIX implementation, they're less efficient. Second, and more importantly,
+// they CAN NOT BE USED WITH CONDITION VARIABLES under Unix! Using them with
+// wxCondition will work under Windows and some Unices (notably Linux) but will
+// deadlock under other Unix versions (e.g. Solaris). As it might be difficult
+// to ensure that a recursive mutex is not used with wxCondition, it is a good
+// idea to avoid using recursive mutexes at all. Also, the last problem with
+// them is that some (older) Unix versions don't support this at all -- which
+// results in a configure warning when building and a deadlock when using them.
+enum wxMutexType
+{
+    // normal mutex: try to always use this one
+    wxMUTEX_DEFAULT,
+
+    // recursive mutex: don't use these ones with wxCondition
+    wxMUTEX_RECURSIVE
+};
+
+// forward declarations
+class WXDLLEXPORT wxConditionInternal;
+class WXDLLEXPORT wxMutexInternal;
+class WXDLLEXPORT wxSemaphoreInternal;
+class WXDLLEXPORT wxThreadInternal;
+
 // ----------------------------------------------------------------------------
 // A mutex object is a synchronization object whose state is set to signaled
 // when it is not owned by any thread, and nonsignaled when it is owned. Its
@@ -80,34 +130,44 @@ enum
 
 // you should consider wxMutexLocker whenever possible instead of directly
 // working with wxMutex class - it is safer
-class WXDLLEXPORT wxConditionInternal;
-class WXDLLEXPORT wxMutexInternal;
 class WXDLLEXPORT wxMutex
 {
 public:
     // constructor & destructor
-    wxMutex();
+    // ------------------------
+
+    // create either default (always safe) or recursive mutex
+    wxMutex(wxMutexType mutexType = wxMUTEX_DEFAULT);
+
+    // destroys the mutex kernel object
     ~wxMutex();
 
-    // Lock the mutex.
+    // test if the mutex has been created successfully
+    bool IsOk() const;
+
+    // mutex operations
+    // ----------------
+
+    // Lock the mutex, blocking on it until it is unlocked by the other thread.
+    // The result of locking a mutex already locked by the current thread
+    // depend on the mutex type.
+    //
+    // The caller must call Unlock() later if Lock() returned wxMUTEX_NO_ERROR.
     wxMutexError Lock();
-    // Try to lock the mutex: if it can't, returns immediately with an error.
+
+    // Try to lock the mutex: if it is currently locked, return immediately
+    // with an error. Otherwise the caller must call Unlock().
     wxMutexError TryLock();
-    // Unlock the mutex.
-    wxMutexError Unlock();
 
-    // Returns true if the mutex is locked.
-    bool IsLocked() const { return (m_locked > 0); }
+    // Unlock the mutex. It is an error to unlock an already unlocked mutex
+    wxMutexError Unlock();
 
 protected:
-    // no assignment operator nor copy ctor
-    wxMutex(const wxMutex&);
-    wxMutex& operator=(const wxMutex&);
-
-    int m_locked;
     wxMutexInternal *m_internal;
 
     friend class wxConditionInternal;
+
+    DECLARE_NO_COPY_CLASS(wxMutex)
 };
 
 // a helper class which locks the mutex in the ctor and unlocks it in the dtor:
@@ -148,17 +208,11 @@ private:
 //     which makes it possible to have static globals of this class
 // ----------------------------------------------------------------------------
 
-class WXDLLEXPORT wxCriticalSectionInternal;
-
 // in order to avoid any overhead under platforms where critical sections are
 // just mutexes make all wxCriticalSection class functions inline
 #if !defined(__WXMSW__) && !defined(__WXPM__)
-    #define WXCRITICAL_INLINE   inline
-
     #define wxCRITSECT_IS_MUTEX 1
 #else // MSW || OS2
-    #define WXCRITICAL_INLINE
-
     #define wxCRITSECT_IS_MUTEX 0
 #endif // MSW/!MSW
 
@@ -168,50 +222,62 @@ class WXDLLEXPORT wxCriticalSection
 {
 public:
     // ctor & dtor
-    WXCRITICAL_INLINE wxCriticalSection();
-    WXCRITICAL_INLINE ~wxCriticalSection();
+    inline wxCriticalSection();
+    inline ~wxCriticalSection();
 
     // enter the section (the same as locking a mutex)
-    WXCRITICAL_INLINE void Enter();
+    inline void Enter();
+
     // leave the critical section (same as unlocking a mutex)
-    WXCRITICAL_INLINE void Leave();
+    inline void Leave();
 
 private:
-    // no assignment operator nor copy ctor
-    wxCriticalSection(const wxCriticalSection&);
-    wxCriticalSection& operator=(const wxCriticalSection&);
-
 #if wxCRITSECT_IS_MUTEX
     wxMutex m_mutex;
 #elif defined(__WXMSW__)
     // we can't allocate any memory in the ctor, so use placement new -
     // unfortunately, we have to hardcode the sizeof() here because we can't
     // include windows.h from this public header
+    //
+    // if CRITICAL_SECTION size changes in Windows, you'll get an assert from
+    // thread.cpp and will need to increase the buffer size
     char m_buffer[24];
-#elif !defined(__WXPM__)
-    wxCriticalSectionInternal *m_critsect;
 #else
     // nothing for OS/2
-#endif // !Unix/Unix
+#endif // Unix/Win32/OS2
+
+    DECLARE_NO_COPY_CLASS(wxCriticalSection)
 };
 
-// keep your preprocessor name space clean
-#undef WXCRITICAL_INLINE
+#if wxCRITSECT_IS_MUTEX
+    // implement wxCriticalSection using mutexes
+    inline wxCriticalSection::wxCriticalSection() { }
+    inline wxCriticalSection::~wxCriticalSection() { }
+
+    inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
+    inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
+#endif // wxCRITSECT_IS_MUTEX
 
 // wxCriticalSectionLocker is the same to critical sections as wxMutexLocker is
 // to th mutexes
 class WXDLLEXPORT wxCriticalSectionLocker
 {
 public:
-    inline wxCriticalSectionLocker(wxCriticalSection& critsect);
-    inline ~wxCriticalSectionLocker();
+    wxCriticalSectionLocker(wxCriticalSection& cs)
+        : m_critsect(cs)
+    {
+        m_critsect.Enter();
+    }
 
-private:
-    // no assignment operator nor copy ctor
-    wxCriticalSectionLocker(const wxCriticalSectionLocker&);
-    wxCriticalSectionLocker& operator=(const wxCriticalSectionLocker&);
+    ~wxCriticalSectionLocker()
+    {
+        m_critsect.Leave();
+    }
 
+private:
     wxCriticalSection& m_critsect;
+
+    DECLARE_NO_COPY_CLASS(wxCriticalSectionLocker)
 };
 
 // ----------------------------------------------------------------------------
@@ -221,25 +287,24 @@ private:
 
 class WXDLLEXPORT wxCondition
 {
-    DECLARE_NO_COPY_CLASS(wxCondition)
-        
 public:
-    // constructor and destructor
-
-    // Each wxCondition object is associated with with a wxMutex object The
-    // mutex object MUST be locked before calling Wait()
+    // Each wxCondition object is associated with a (single) wxMutex object.
+    // The mutex object MUST be locked before calling Wait()
     wxCondition(wxMutex& mutex);
 
     // dtor is not virtual, don't use this class polymorphically
     ~wxCondition();
 
+    // return TRUE if the condition has been created successfully
+    bool IsOk() const;
+
     // NB: the associated mutex MUST be locked beforehand by the calling thread
     // 
     // it atomically releases the lock on the associated mutex
     // and starts waiting to be woken up by a Signal()/Broadcast()
     // once its signaled, then it will wait until it can reacquire
     // the lock on the associated mutex object, before returning.
-    void Wait();
+    wxCondError Wait();
 
     // exactly as Wait() except that it may also return if the specified
     // timeout ellapses even if the condition hasn't been signalled: in this
@@ -248,7 +313,7 @@ public:
     // 
     // the timeeout parameter specifies a interval that needs to be waited in
     // milliseconds
-    bool Wait( unsigned long timeout_millis );
+    wxCondError WaitTimeout(unsigned long milliseconds);
 
     // NB: the associated mutex may or may not be locked by the calling thread
     //
@@ -256,7 +321,7 @@ public:
     // if no thread is blocking in Wait(), then the signal is NOT remembered
     // The thread which was blocking on Wait(), will then reacquire the lock
     // on the associated mutex object before returning
-    void Signal();
+    wxCondError Signal();
 
     // NB: the associated mutex may or may not be locked by the calling thread
     //
@@ -264,10 +329,17 @@ public:
     // if no thread is blocking in Wait(), then the signal is NOT remembered
     // The threads which were blocking on Wait(), will then reacquire the lock
     // on the associated mutex object before returning.
-    void Broadcast();
+    wxCondError Broadcast();
+
+
+    // deprecated version, don't use
+    bool Wait(unsigned long milliseconds)
+        { return WaitTimeout(milliseconds) == wxCOND_NO_ERROR; }
 
 private:
     wxConditionInternal *m_internal;
+
+    DECLARE_NO_COPY_CLASS(wxCondition)
 };
 
 // ----------------------------------------------------------------------------
@@ -275,11 +347,8 @@ private:
 //              a shared resource
 // ----------------------------------------------------------------------------
 
-class WXDLLEXPORT wxSemaphoreInternal;
 class WXDLLEXPORT wxSemaphore
 {
-    DECLARE_NO_COPY_CLASS(wxSemaphore)
-        
 public:
     // specifying a maxcount of 0 actually makes wxSemaphore behave as if there
     // is no upper limit, if maxcount is 1 the semaphore behaves as a mutex
@@ -288,24 +357,29 @@ public:
     // dtor is not virtual, don't use this class polymorphically
     ~wxSemaphore();
 
+    // return TRUE if the semaphore has been created successfully
+    bool IsOk() const;
+
     // wait indefinitely, until the semaphore count goes beyond 0
     // and then decrement it and return (this method might have been called
     // Acquire())
-    void Wait();
+    wxSemaError Wait();
 
-    // same as Wait(), but does not block, returns TRUE if successful and
-    // FALSE if the count is zero
-    bool TryWait();
+    // same as Wait(), but does not block, returns wxSEMA_NO_ERROR if
+    // successful and wxSEMA_BUSY if the count is currently zero
+    wxSemaError TryWait();
 
-    // same as Wait(), but as a timeout limit, returns TRUE if the semaphore
-    // was acquired and FALSE if the timeout has ellapsed
-    bool Wait( unsigned long timeout_millis );
+    // same as Wait(), but as a timeout limit, returns wxSEMA_NO_ERROR if the
+    // semaphore was acquired and wxSEMA_TIMEOUT if the timeout has ellapsed
+    wxSemaError WaitTimeout(unsigned long milliseconds);
 
     // increments the semaphore count and signals one of the waiting threads
-    void Post();
+    wxSemaError Post();
 
 private:
     wxSemaphoreInternal *m_internal;
+
+    DECLARE_NO_COPY_CLASS(wxSemaphore)
 };
 
 // ----------------------------------------------------------------------------
@@ -328,7 +402,6 @@ private:
    typedef unsigned long wxThreadIdType;
 #endif
 
-class wxThreadInternal;
 class WXDLLEXPORT wxThread
 {
 public:
@@ -508,8 +581,6 @@ void WXDLLEXPORT wxMutexGuiLeave();
 
 #else // !wxUSE_THREADS
 
-#include "wx/defs.h" // for WXDLLEXPORT
-
 // no thread support
 inline void WXDLLEXPORT wxMutexGuiEnter() { }
 inline void WXDLLEXPORT wxMutexGuiLeave() { }
@@ -521,9 +592,9 @@ inline void WXDLLEXPORT wxMutexGuiLeave() { }
 #define wxCRIT_SECT_DECLARE(cs)
 #define wxCRIT_SECT_LOCKER(name, cs)
 
-#endif // wxUSE_THREADS
+#endif // wxUSE_THREADS/!wxUSE_THREADS
 
-// automatically unlock GUI mutex in dtor
+// automatically lock GUI mutex in ctor and unlock it in dtor
 class WXDLLEXPORT wxMutexGuiLocker
 {
 public:
@@ -537,7 +608,7 @@ public:
 
 #if wxUSE_THREADS
 
-#if defined(__WXMSW__)
+#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXPM__)
     // 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
@@ -546,61 +617,17 @@ public:
     // returns TRUE if the main thread has GUI lock
     extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
 
+#ifndef __WXPM__
     // wakes up the main thread if it's sleeping inside ::GetMessage()
     extern void WXDLLEXPORT wxWakeUpMainThread();
+#endif // !OS/2
 
     // return TRUE if the main thread is waiting for some other to terminate:
     // wxApp then should block all "dangerous" messages
     extern bool WXDLLEXPORT wxIsWaitingForThread();
-#elif defined(__WXMAC__)
-    extern void WXDLLEXPORT wxMutexGuiLeaveOrEnter();
-
-    // returns TRUE if the main thread has GUI lock
-    extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
-
-    // wakes up the main thread if it's sleeping inside ::GetMessage()
-    extern void WXDLLEXPORT wxWakeUpMainThread();
-
-    // return TRUE if the main thread is waiting for some other to terminate:
-    // wxApp then should block all "dangerous" messages
-    extern bool WXDLLEXPORT wxIsWaitingForThread();
-
-    // implement wxCriticalSection using mutexes
-    inline wxCriticalSection::wxCriticalSection() : m_mutex() { }
-    inline wxCriticalSection::~wxCriticalSection() { }
-
-    inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
-    inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
-#elif defined(__WXPM__)
-    // 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
-    extern void WXDLLEXPORT wxMutexGuiLeaveOrEnter();
-
-    // returns TRUE if the main thread has GUI lock
-    extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
-
-    // return TRUE if the main thread is waiting for some other to terminate:
-    // wxApp then should block all "dangerous" messages
-    extern bool WXDLLEXPORT wxIsWaitingForThread();
-
-#else // !MSW && !PM
-    // implement wxCriticalSection using mutexes
-    inline wxCriticalSection::wxCriticalSection() { }
-    inline wxCriticalSection::~wxCriticalSection() { }
-
-    inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
-    inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
-#endif // MSW/!MSW
+#endif // MSW, Mac, OS/2
 
-    // we can define these inline functions now (they should be defined after
-    // wxCriticalSection::Enter/Leave)
-    inline
-    wxCriticalSectionLocker:: wxCriticalSectionLocker(wxCriticalSection& cs)
-        : m_critsect(cs) { m_critsect.Enter(); }
-    inline
-    wxCriticalSectionLocker::~wxCriticalSectionLocker() { m_critsect.Leave(); }
 #endif // wxUSE_THREADS
 
-#endif // __THREADH__
+#endif // _WX_THREAD_H_
 
diff --git a/include/wx/thrimpl.cpp b/include/wx/thrimpl.cpp
new file mode 100644 (file)
index 0000000..b01436a
--- /dev/null
@@ -0,0 +1,175 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        include/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
+/////////////////////////////////////////////////////////////////////////////
+
+// this file is supposed to be included only by the various thread.cpp
+
+// ----------------------------------------------------------------------------
+// wxMutex
+// ----------------------------------------------------------------------------
+
+wxMutex::wxMutex(wxMutexType mutexType)
+{
+    m_internal = new wxMutexInternal(mutexType);
+
+    if ( !m_internal->IsOk() )
+    {
+        delete m_internal;
+        m_internal = NULL;
+    }
+}
+
+wxMutex::~wxMutex()
+{
+    delete m_internal;
+}
+
+bool wxMutex::IsOk() const
+{
+    return m_internal != NULL;
+}
+
+wxMutexError wxMutex::Lock()
+{
+    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
+                 _T("wxMutex::Lock(): not initialized") );
+
+    return m_internal->Lock();
+}
+
+wxMutexError wxMutex::TryLock()
+{
+    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
+                 _T("wxMutex::TryLock(): not initialized") );
+
+    return m_internal->TryLock();
+}
+
+wxMutexError wxMutex::Unlock()
+{
+    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
+                 _T("wxMutex::Unlock(): not initialized") );
+
+    return m_internal->Unlock();
+}
+
+// ----------------------------------------------------------------------------
+// wxCondition
+// ----------------------------------------------------------------------------
+
+wxCondition::wxCondition(wxMutex& mutex)
+{
+    m_internal = new wxConditionInternal(mutex);
+
+    if ( !m_internal->IsOk() )
+    {
+        delete m_internal;
+        m_internal = NULL;
+    }
+}
+
+wxCondition::~wxCondition()
+{
+    delete m_internal;
+}
+
+bool wxCondition::IsOk() const
+{
+    return m_internal != NULL;
+}
+
+wxCondError wxCondition::Wait()
+{
+    wxCHECK_MSG( m_internal, wxCOND_INVALID,
+                 _T("wxCondition::Wait(): not initialized") );
+
+    return m_internal->Wait();
+}
+
+wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
+{
+    wxCHECK_MSG( m_internal, wxCOND_INVALID,
+                 _T("wxCondition::Wait(): not initialized") );
+
+    return m_internal->WaitTimeout(milliseconds);
+}
+
+wxCondError wxCondition::Signal()
+{
+    wxCHECK_MSG( m_internal, wxCOND_INVALID,
+                 _T("wxCondition::Signal(): not initialized") );
+
+    return m_internal->Signal();
+}
+
+wxCondError wxCondition::Broadcast()
+{
+    wxCHECK_MSG( m_internal, wxCOND_INVALID,
+                 _T("wxCondition::Broadcast(): not initialized") );
+
+    return m_internal->Broadcast();
+}
+
+// --------------------------------------------------------------------------
+// wxSemaphore
+// --------------------------------------------------------------------------
+
+wxSemaphore::wxSemaphore(int initialcount, int maxcount)
+{
+    m_internal = new wxSemaphoreInternal( initialcount, maxcount );
+    if ( !m_internal->IsOk() )
+    {
+        delete m_internal;
+        m_internal = NULL;
+    }
+}
+
+wxSemaphore::~wxSemaphore()
+{
+    delete m_internal;
+}
+
+bool wxSemaphore::IsOk() const
+{
+    return m_internal != NULL;
+}
+
+wxSemaError wxSemaphore::Wait()
+{
+    wxCHECK_MSG( m_internal, wxSEMA_INVALID,
+                 _T("wxSemaphore::Wait(): not initialized") );
+
+    return m_internal->Wait();
+}
+
+wxSemaError wxSemaphore::TryWait()
+{
+    wxCHECK_MSG( m_internal, wxSEMA_INVALID,
+                 _T("wxSemaphore::TryWait(): not initialized") );
+
+    return m_internal->TryWait();
+}
+
+wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
+{
+    wxCHECK_MSG( m_internal, wxSEMA_INVALID,
+                 _T("wxSemaphore::WaitTimeout(): not initialized") );
+
+    return m_internal->WaitTimeout(milliseconds);
+}
+
+wxSemaError wxSemaphore::Post()
+{
+    wxCHECK_MSG( m_internal, wxSEMA_INVALID,
+                 _T("wxSemaphore::Post(): not initialized") );
+
+    return m_internal->Post();
+}
+
index f7e9f0517b6b3791b9b6aca14f01baed0871dd6b..b3bc923c6877110b8bc2c5f703ccc49afc0d1c97 100644 (file)
@@ -1,12 +1,12 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        thread.cpp
+// Name:        src/msw/thread.cpp
 // Purpose:     wxThread Implementation
 // Author:      Original from Wolfram Gloger/Guilhem Lavaux
 // Modified by: Vadim Zeitlin to make it work :-)
 // Created:     04/22/98
 // RCS-ID:      $Id$
-// Copyright:   (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
-//                  Vadim Zeitlin (1999)
+// Copyright:   (c) Wolfram Gloger (1996, 1997), Guilhem Lavaux (1998);
+//                  Vadim Zeitlin (1999-2002)
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 #include "wx/module.h"
 #include "wx/thread.h"
 
-#ifdef Yield
-#    undef Yield
-#endif
-
 // must have this symbol defined to get _beginthread/_endthread declarations
 #ifndef _MT
     #define _MT
@@ -127,128 +123,157 @@ static size_t gs_nWaitingForGui = 0;
 static bool gs_waitingForThread = FALSE;
 
 // ============================================================================
-// Windows implementation of thread classes
+// Windows implementation of thread and related classes
 // ============================================================================
 
 // ----------------------------------------------------------------------------
-// wxMutex implementation
+// wxCriticalSection
+// ----------------------------------------------------------------------------
+
+wxCriticalSection::wxCriticalSection()
+{
+    wxCOMPILE_TIME_ASSERT( sizeof(CRITICAL_SECTION) <= sizeof(m_buffer),
+                           wxCriticalSectionBufferTooSmall );
+
+    ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
+}
+
+wxCriticalSection::~wxCriticalSection()
+{
+    ::DeleteCriticalSection((CRITICAL_SECTION *)m_buffer);
+}
+
+void wxCriticalSection::Enter()
+{
+    ::EnterCriticalSection((CRITICAL_SECTION *)m_buffer);
+}
+
+void wxCriticalSection::Leave()
+{
+    ::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
+}
+
+// ----------------------------------------------------------------------------
+// wxMutex
 // ----------------------------------------------------------------------------
 
 class wxMutexInternal
 {
 public:
-    wxMutexInternal()
-    {
-        m_mutex = ::CreateMutex(NULL, FALSE, NULL);
-        if ( !m_mutex )
-        {
-            wxLogSysError(_("Can not create mutex"));
-        }
-    }
+    wxMutexInternal(wxMutexType mutexType);
+    ~wxMutexInternal();
 
-    ~wxMutexInternal() { if ( m_mutex ) ::CloseHandle(m_mutex); }
+    bool IsOk() const { return m_mutex != NULL; }
+
+    wxMutexError Lock() { return LockTimeout(INFINITE); }
+    wxMutexError TryLock() { return LockTimeout(0); }
+    wxMutexError Unlock();
+
+private:
+    wxMutexError LockTimeout(DWORD milliseconds);
 
-public:
     HANDLE m_mutex;
 };
 
-wxMutex::wxMutex()
+// all mutexes are recursive under Win32 so we don't use mutexType
+wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(mutexType))
 {
-    m_internal = new wxMutexInternal;
+    // create a nameless (hence intra process and always private) mutex
+    m_mutex = ::CreateMutex
+                (
+                    NULL,       // default secutiry attributes
+                    FALSE,      // not initially locked
+                    NULL        // no name
+                );
 
-    m_locked = 0;
+    if ( !m_mutex )
+    {
+        wxLogLastError(_T("CreateMutex()"));
+    }
 }
 
-wxMutex::~wxMutex()
+wxMutexInternal::~wxMutexInternal()
 {
-    if ( m_locked > 0 )
+    if ( m_mutex )
     {
-        wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked);
+        if ( !::CloseHandle(m_mutex) )
+        {
+            wxLogLastError(_T("CloseHandle(mutex)"));
+        }
     }
-
-    delete m_internal;
 }
 
-wxMutexError wxMutex::Lock()
+wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds)
 {
-    DWORD ret;
-
-    ret = WaitForSingleObject(m_internal->m_mutex, INFINITE);
-    switch ( ret )
+    DWORD rc = ::WaitForSingleObject(m_mutex, milliseconds);
+    if ( rc == WAIT_ABANDONED )
     {
-        case WAIT_ABANDONED:
-            return wxMUTEX_BUSY;
+        // the previous caller died without releasing the mutex, but now we can
+        // really lock it
+        wxLogDebug(_T("WaitForSingleObject() returned WAIT_ABANDONED"));
+
+        // use 0 timeout, normally we should always get it
+        rc = ::WaitForSingleObject(m_mutex, 0);
+    }
 
+    switch ( rc )
+    {
         case WAIT_OBJECT_0:
             // ok
             break;
 
-        case WAIT_FAILED:
-            wxLogSysError(_("Couldn't acquire a mutex lock"));
-            return wxMUTEX_MISC_ERROR;
-
         case WAIT_TIMEOUT:
+            return wxMUTEX_BUSY;
+
+        case WAIT_ABANDONED:        // checked for above
         default:
             wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
-    }
+            // fall through
 
-    m_locked++;
-    return wxMUTEX_NO_ERROR;
-}
-
-wxMutexError wxMutex::TryLock()
-{
-    DWORD ret;
-
-    ret = WaitForSingleObject(m_internal->m_mutex, 0);
-    if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
-        return wxMUTEX_BUSY;
+        case WAIT_FAILED:
+            wxLogLastError(_T("WaitForSingleObject(mutex)"));
+            return wxMUTEX_MISC_ERROR;
+    }
 
-    m_locked++;
     return wxMUTEX_NO_ERROR;
 }
 
-wxMutexError wxMutex::Unlock()
+wxMutexError wxMutexInternal::Unlock()
 {
-    if (m_locked > 0)
-        m_locked--;
-
-    BOOL ret = ReleaseMutex(m_internal->m_mutex);
-    if ( ret == 0 )
+    if ( !::ReleaseMutex(m_mutex) )
     {
-        wxLogSysError(_("Couldn't release a mutex"));
+        wxLogLastError(_("ReleaseMutex()"));
+
         return wxMUTEX_MISC_ERROR;
     }
 
     return wxMUTEX_NO_ERROR;
 }
 
-// ==========================================================================
-// wxSemaphore
-// ==========================================================================
-
 // --------------------------------------------------------------------------
-// wxSemaphoreInternal
+// wxSemaphore
 // --------------------------------------------------------------------------
 
+// a trivial wrapper around Win32 semaphore
 class wxSemaphoreInternal
 {
 public:
-    wxSemaphoreInternal( int initialcount = 0, int maxcount = 0 );
+    wxSemaphoreInternal(int initialcount, int maxcount);
     ~wxSemaphoreInternal();
 
-    void Wait();
-    bool TryWait();
+    bool IsOk() const { return m_semaphore != NULL; }
 
-    bool Wait( unsigned long timeout_millis );
+    wxSemaError Wait() { return WaitTimeout(INFINITE); }
+    wxSemaError TryWait() { return WaitTimeout(0); }
+    wxSemaError WaitTimeout(unsigned long milliseconds);
 
-    void Post();
+    wxSemaError Post();
 
 private:
     HANDLE m_semaphore;
 };
 
-wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount )
+wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
 {
     if ( maxcount == 0 )
     {
@@ -256,7 +281,14 @@ wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount )
         maxcount = INT_MAX;
     }
 
-    m_semaphore = ::CreateSemaphore( NULL, initialcount, maxcount, NULL );
+    m_semaphore = ::CreateSemaphore
+                    (
+                        NULL,           // default security attributes
+                        initialcount,
+                        maxcount,
+                        NULL            // no name
+                    );
+
     if ( !m_semaphore )
     {
         wxLogLastError(_T("CreateSemaphore()"));
@@ -265,129 +297,89 @@ wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount )
 
 wxSemaphoreInternal::~wxSemaphoreInternal()
 {
-    CloseHandle( m_semaphore );
-}
-
-void wxSemaphoreInternal::Wait()
-{
-    if ( ::WaitForSingleObject( m_semaphore, INFINITE ) != WAIT_OBJECT_0 )
+    if ( m_semaphore )
     {
-        wxLogLastError(_T("WaitForSingleObject"));
+        if ( !::CloseHandle(m_semaphore) )
+        {
+            wxLogLastError(_T("CloseHandle(semaphore)"));
+        }
     }
 }
 
-bool wxSemaphoreInternal::TryWait()
-{
-    return Wait(0);
-}
-
-bool wxSemaphoreInternal::Wait( unsigned long timeout_millis )
+wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
 {
-    DWORD result = ::WaitForSingleObject( m_semaphore, timeout_millis );
+    DWORD rc = ::WaitForSingleObject( m_semaphore, milliseconds );
 
-    switch ( result )
+    switch ( rc )
     {
         case WAIT_OBJECT_0:
-           return TRUE;
+           return wxSEMA_NO_ERROR;
 
         case WAIT_TIMEOUT:
-           break;
+           return wxSEMA_BUSY;
 
         default:
-            wxLogLastError(_T("WaitForSingleObject()"));
+            wxLogLastError(_T("WaitForSingleObject(semaphore)"));
     }
 
-    return FALSE;
+    return wxSEMA_MISC_ERROR;
 }
 
-void wxSemaphoreInternal::Post()
+wxSemaError wxSemaphoreInternal::Post()
 {
-    if ( !::ReleaseSemaphore( m_semaphore, 1, NULL ) )
+    if ( !::ReleaseSemaphore(m_semaphore, 1, NULL /* ptr to previous count */) )
     {
         wxLogLastError(_T("ReleaseSemaphore"));
-    }
-}
-
-// --------------------------------------------------------------------------
-// wxSemaphore
-// --------------------------------------------------------------------------
 
-wxSemaphore::wxSemaphore( int initialcount, int maxcount )
-{
-    m_internal = new wxSemaphoreInternal( initialcount, maxcount );
-}
-
-wxSemaphore::~wxSemaphore()
-{
-    delete m_internal;
-}
-
-void wxSemaphore::Wait()
-{
-    m_internal->Wait();
-}
-
-bool wxSemaphore::TryWait()
-{
-    return m_internal->TryWait();
-}
-
-bool wxSemaphore::Wait( unsigned long timeout_millis )
-{
-    return m_internal->Wait( timeout_millis );
-}
+        return wxSEMA_MISC_ERROR;
+    }
 
-void wxSemaphore::Post()
-{
-    m_internal->Post();
+    return wxSEMA_NO_ERROR;
 }
 
-
-// ==========================================================================
-// wxCondition
-// ==========================================================================
-
 // --------------------------------------------------------------------------
-// wxConditionInternal
+// wxCondition
 // --------------------------------------------------------------------------
 
+// Win32 doesn't have explicit support for the POSIX condition variables and
+// the Win32 events have quite different semantics, so we reimplement the
+// conditions from scratch using the mutexes and semaphores
 class wxConditionInternal
 {
 public:
     wxConditionInternal(wxMutex& mutex);
 
-    void Wait();
+    bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); }
 
-    bool Wait( unsigned long timeout_millis );
+    wxCondError Wait();
+    wxCondError WaitTimeout(unsigned long milliseconds);
 
-    void Signal();
-
-    void Broadcast();
+    wxCondError Signal();
+    wxCondError Broadcast();
 
 private:
-    int m_numWaiters;
-    wxMutex m_mutexNumWaiters;
+    // the number of threads currently waiting for this condition
+    LONG m_numWaiters;
 
-    wxMutex& m_mutex;
+    // the critical section protecting m_numWaiters
+    wxCriticalSection m_csWaiters;
 
+    wxMutex& m_mutex;
     wxSemaphore m_semaphore;
-
-    DECLARE_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;
 }
 
-void wxConditionInternal::Wait()
+wxCondError wxConditionInternal::Wait()
 {
     // increment the number of waiters
-    m_mutexNumWaiters.Lock();
-    m_numWaiters++;
-    m_mutexNumWaiters.Unlock();
+    ::InterlockedIncrement(&m_numWaiters);
 
     m_mutex.Unlock();
 
@@ -402,16 +394,15 @@ void wxConditionInternal::Wait()
     // can 'remember' signals the race condition will not occur
 
     // wait ( if necessary ) and decrement semaphore
-    m_semaphore.Wait();
-
+    wxSemaError err = m_semaphore.Wait();
     m_mutex.Lock();
+
+    return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
 }
 
-bool wxConditionInternal::Wait( unsigned long timeout_millis )
+wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
 {
-    m_mutexNumWaiters.Lock();
-    m_numWaiters++;
-    m_mutexNumWaiters.Unlock();
+    ::InterlockedIncrement(&m_numWaiters);
 
     m_mutex.Unlock();
 
@@ -419,11 +410,9 @@ bool wxConditionInternal::Wait( unsigned long timeout_millis )
     //
     // please see the comments in Wait(), for details
 
-    bool success = TRUE;
+    wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
 
-    bool result = m_semaphore.Wait( timeout_millis );
-
-    if ( !result )
+    if ( err == wxSEMA_BUSY )
     {
         // another potential race condition exists here it is caused when a
         // 'waiting' thread timesout, and returns from WaitForSingleObject, but
@@ -437,116 +426,50 @@ bool wxConditionInternal::Wait( unsigned long timeout_millis )
         // 'nwaiters_mutex'. this call does not block because of the zero
         // timeout, but will allow the waiting thread to catch the missed
         // signals.
-        m_mutexNumWaiters.Lock();
-        result = m_semaphore.Wait( 0 );
+        wxCriticalSectionLocker lock(m_csWaiters);
+
+        err = m_semaphore.WaitTimeout(0);
 
-        if ( !result )
+        if ( err != wxSEMA_NO_ERROR )
         {
             m_numWaiters--;
-            success = FALSE;
         }
-
-        m_mutexNumWaiters.Unlock();
     }
 
     m_mutex.Lock();
 
-    return success;
+    return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
 }
 
-void wxConditionInternal::Signal()
+wxCondError wxConditionInternal::Signal()
 {
-    m_mutexNumWaiters.Lock();
+    wxCriticalSectionLocker lock(m_csWaiters);
 
     if ( m_numWaiters > 0 )
     {
         // increment the semaphore by 1
-        m_semaphore.Post();
+        if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
+            return wxCOND_MISC_ERROR;
 
         m_numWaiters--;
     }
 
-    m_mutexNumWaiters.Unlock();
+    return wxCOND_NO_ERROR;
 }
 
-void wxConditionInternal::Broadcast()
+wxCondError wxConditionInternal::Broadcast()
 {
-    m_mutexNumWaiters.Lock();
+    wxCriticalSectionLocker lock(m_csWaiters);
 
     while ( m_numWaiters > 0 )
     {
-        m_semaphore.Post();
+        if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
+            return wxCOND_MISC_ERROR;
+
         m_numWaiters--;
     }
 
-    m_mutexNumWaiters.Unlock();
-}
-
-// ----------------------------------------------------------------------------
-// wxCondition implementation
-// ----------------------------------------------------------------------------
-
-wxCondition::wxCondition(wxMutex& mutex)
-{
-    m_internal = new wxConditionInternal( mutex );
-}
-
-wxCondition::~wxCondition()
-{
-    delete m_internal;
-}
-
-void wxCondition::Wait()
-{
-    m_internal->Wait();
-}
-
-bool wxCondition::Wait( unsigned long timeout_millis )
-{
-    return m_internal->Wait(timeout_millis);
-}
-
-void wxCondition::Signal()
-{
-    m_internal->Signal();
-}
-
-void wxCondition::Broadcast()
-{
-    m_internal->Broadcast();
-}
-
-// ----------------------------------------------------------------------------
-// wxCriticalSection implementation
-// ----------------------------------------------------------------------------
-
-wxCriticalSection::wxCriticalSection()
-{
-#ifdef __WXDEBUG__
-    // Done this way to stop warnings during compilation about statement
-    // always being FALSE
-    int csSize = sizeof(CRITICAL_SECTION);
-    int bSize  = sizeof(m_buffer);
-    wxASSERT_MSG( csSize <= bSize,
-                  _T("must increase buffer size in wx/thread.h") );
-#endif
-
-    ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
-}
-
-wxCriticalSection::~wxCriticalSection()
-{
-    ::DeleteCriticalSection((CRITICAL_SECTION *)m_buffer);
-}
-
-void wxCriticalSection::Enter()
-{
-    ::EnterCriticalSection((CRITICAL_SECTION *)m_buffer);
-}
-
-void wxCriticalSection::Leave()
-{
-    ::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
+    return wxCOND_NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
@@ -1429,6 +1352,11 @@ bool WXDLLEXPORT wxIsWaitingForThread()
     return gs_waitingForThread;
 }
 
+// ----------------------------------------------------------------------------
+// include common implementation code
+// ----------------------------------------------------------------------------
+
+#include "wx/thrimpl.cpp"
+
 #endif // wxUSE_THREADS
 
-// vi:sts=4:sw=4:et
index 72be9193352b2b1191d936e2f62c4e449b37b131..36d6ee7d0ebc6a7b2927de8ac13ca5ccc70a63cc 100644 (file)
@@ -71,9 +71,12 @@ enum wxThreadState
 // the exit value of a thread which has been cancelled
 static const wxThread::ExitCode EXITCODE_CANCELLED = (wxThread::ExitCode)-1;
 
-// our trace mask
+// trace mask for wxThread operations
 #define TRACE_THREADS   _T("thread")
 
+// you can get additional debugging messages for the semaphore operations
+#define TRACE_SEMA      _T("semaphore")
+
 // ----------------------------------------------------------------------------
 // private functions
 // ----------------------------------------------------------------------------
@@ -82,11 +85,14 @@ static void ScheduleThreadForDeletion();
 static void DeleteThread(wxThread *This);
 
 // ----------------------------------------------------------------------------
-// types
+// private classes
 // ----------------------------------------------------------------------------
 
+// an (non owning) array of pointers to threads
 WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
 
+// an entry for a thread we can wait for
+
 // -----------------------------------------------------------------------------
 // global data
 // -----------------------------------------------------------------------------
@@ -118,6 +124,15 @@ static wxCondition *gs_condAllDeleted = (wxCondition *)NULL;
     static wxMutex *gs_mutexGui;
 #endif // wxUSE_GUI
 
+// 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
+// member of the thread itself as a detached thread may delete itself at any
+// moment and accessing the condition member of the thread after this would
+// result in a disaster
+//
+// so instead we maintain a global list of the structs below for the threads
+// we're interested in waiting on
+
 // ============================================================================
 // wxMutex implementation
 // ============================================================================
@@ -126,51 +141,86 @@ static wxCondition *gs_condAllDeleted = (wxCondition *)NULL;
 // wxMutexInternal
 // ----------------------------------------------------------------------------
 
+// this is a simple wrapper around pthread_mutex_t which provides error
+// checking
 class wxMutexInternal
 {
 public:
-    wxMutexInternal();
+    wxMutexInternal(wxMutexType mutexType);
     ~wxMutexInternal();
 
     wxMutexError Lock();
     wxMutexError TryLock();
     wxMutexError Unlock();
 
+    bool IsOk() const { return m_isOk; }
+
 private:
     pthread_mutex_t m_mutex;
+    bool m_isOk;
 
+    // wxConditionInternal uses our m_mutex
     friend class wxConditionInternal;
 };
 
-wxMutexInternal::wxMutexInternal()
+wxMutexInternal::wxMutexInternal(wxMutexType mutexType)
 {
-    // support recursive locks like Win32, i.e. a thread can lock a mutex which
-    // it had itself already locked
-    //
-    // but initialization of recursive mutexes is non portable <sigh>, so try
-    // several methods
+    int err;
+    switch ( mutexType )
+    {
+        case wxMUTEX_RECURSIVE:
+            // support recursive locks like Win32, i.e. a thread can lock a
+            // mutex which it had itself already locked
+            //
+            // unfortunately initialization of recursive mutexes is non
+            // portable, so try several methods
 #ifdef HAVE_PTHREAD_MUTEXATTR_T
-    pthread_mutexattr_t attr;
-    pthread_mutexattr_init(&attr);
-    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+            {
+                pthread_mutexattr_t attr;
+                pthread_mutexattr_init(&attr);
+                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 
-    pthread_mutex_init(&m_mutex, &attr);
+                err = pthread_mutex_init(&m_mutex, &attr);
+            }
 #elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
-    // we can use this only as initializer so we have to assign it first to a
-    // temp var - assigning directly to m_mutex wouldn't even compile
-    pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-    m_mutex = mutex;
+            // we can use this only as initializer so we have to assign it
+            // first to a temp var - assigning directly to m_mutex wouldn't
+            // even compile
+            {
+                pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+                m_mutex = mutex;
+            }
 #else // no recursive mutexes
-    pthread_mutex_init(&m_mutex, NULL);
-
-    // used by TryLock() below
-    #define NO_RECURSIVE_MUTEXES
+            err = EINVAL;
 #endif // HAVE_PTHREAD_MUTEXATTR_T/...
+            break;
+
+        default:
+            wxFAIL_MSG( _T("unknown mutex type") );
+            // fall through
+
+        case wxMUTEX_DEFAULT:
+            err = pthread_mutex_init(&m_mutex, NULL);
+            break;
+    }
+
+    m_isOk = err == 0;
+    if ( !m_isOk )
+    {
+        wxLogApiError("pthread_mutex_init()", err);
+    }
 }
 
 wxMutexInternal::~wxMutexInternal()
 {
-    pthread_mutex_destroy(&m_mutex);
+    if ( m_isOk )
+    {
+        int err = pthread_mutex_destroy(&m_mutex);
+        if ( err != 0 )
+        {
+            wxLogApiError("pthread_mutex_destroy()", err);
+        }
+    }
 }
 
 wxMutexError wxMutexInternal::Lock()
@@ -179,20 +229,23 @@ wxMutexError wxMutexInternal::Lock()
     switch ( err )
     {
         case EDEADLK:
-            wxLogDebug(wxT("Locking this mutex would lead to deadlock!"));
+            // only error checking mutexes return this value and so it's an
+            // unexpected situation -- hence use assert, not wxLogDebug
+            wxFAIL_MSG( _T("mutex deadlock prevented") );
             return wxMUTEX_DEAD_LOCK;
 
-        default:
-            wxFAIL_MSG( _T("unexpected pthread_mutex_lock() return") );
-            // fall through
-
         case EINVAL:
-            wxLogDebug(_T("Failed to lock the mutex."));
-            return wxMUTEX_MISC_ERROR;
+            wxLogDebug(_T("pthread_mutex_lock(): mutex not initialized."));
+            break;
 
         case 0:
             return wxMUTEX_NO_ERROR;
+
+        default:
+            wxLogApiError(_T("pthread_mutex_lock()"), err);
     }
+
+    return wxMUTEX_MISC_ERROR;
 }
 
 wxMutexError wxMutexInternal::TryLock()
@@ -201,19 +254,22 @@ wxMutexError wxMutexInternal::TryLock()
     switch ( err )
     {
         case EBUSY:
+            // not an error: mutex is already locked, but we're prepared for
+            // this
             return wxMUTEX_BUSY;
 
-        default:
-            wxFAIL_MSG( _T("unexpected pthread_mutex_trylock() return") );
-            // fall through
-
         case EINVAL:
-            wxLogDebug(_T("Failed to try to lock the mutex."));
-            return wxMUTEX_MISC_ERROR;
+            wxLogDebug(_T("pthread_mutex_trylock(): mutex not initialized."));
+            break;
 
         case 0:
             return wxMUTEX_NO_ERROR;
+
+        default:
+            wxLogApiError(_T("pthread_mutex_trylock()"), err);
     }
+
+    return wxMUTEX_MISC_ERROR;
 }
 
 wxMutexError wxMutexInternal::Unlock()
@@ -225,87 +281,18 @@ wxMutexError wxMutexInternal::Unlock()
             // we don't own the mutex
             return wxMUTEX_UNLOCKED;
 
-        default:
-            wxFAIL_MSG( _T("unexpected pthread_mutex_unlock() return") );
-            // fall through
-
         case EINVAL:
-            wxLogDebug(_T("Failed to unlock the mutex."));
-            return wxMUTEX_MISC_ERROR;
+            wxLogDebug(_T("pthread_mutex_unlock(): mutex not initialized."));
+            break;
 
         case 0:
             return wxMUTEX_NO_ERROR;
-    }
-}
-
-// ----------------------------------------------------------------------------
-// wxMutex
-// ----------------------------------------------------------------------------
-
-// TODO: this is completely generic, move it to common code?
-
-wxMutex::wxMutex()
-{
-    m_internal = new wxMutexInternal;
-
-    m_locked = 0;
-}
-
-wxMutex::~wxMutex()
-{
-    if ( m_locked > 0 )
-        wxLogDebug(wxT("Freeing a locked mutex (%d locks)"), m_locked);
-
-    delete m_internal;
-}
-
-wxMutexError wxMutex::Lock()
-{
-    wxMutexError err = m_internal->Lock();
-
-    if ( !err )
-    {
-        m_locked++;
-    }
-
-    return err;
-}
-
-wxMutexError wxMutex::TryLock()
-{
-    if ( m_locked )
-    {
-#ifdef NO_RECURSIVE_MUTEXES
-        return wxMUTEX_DEAD_LOCK;
-#else // have recursive mutexes on this platform
-        // we will succeed in locking it when we have it already locked
-        return wxMUTEX_NO_ERROR;
-#endif // recursive/non-recursive mutexes
-    }
-
-    wxMutexError err = m_internal->TryLock();
-    if ( !err )
-    {
-        m_locked++;
-    }
 
-    return err;
-}
-
-wxMutexError wxMutex::Unlock()
-{
-    if ( m_locked > 0 )
-    {
-        m_locked--;
-    }
-    else
-    {
-        wxLogDebug(wxT("Unlocking not locked mutex."));
-
-        return wxMUTEX_UNLOCKED;
+        default:
+            wxLogApiError(_T("pthread_mutex_unlock()"), err);
     }
 
-    return m_internal->Unlock();
+    return wxMUTEX_MISC_ERROR;
 }
 
 // ===========================================================================
@@ -316,112 +303,77 @@ wxMutexError wxMutex::Unlock()
 // wxConditionInternal
 // ---------------------------------------------------------------------------
 
+// this is a wrapper around pthread_cond_t associated with a wxMutex (and hence
+// with a pthread_mutex_t)
 class wxConditionInternal
 {
 public:
     wxConditionInternal(wxMutex& mutex);
     ~wxConditionInternal();
 
-    void Wait();
-
-    bool Wait( const timespec *ts );
+    bool IsOk() const { return m_isOk && m_mutex.IsOk(); }
 
-    void Signal();
+    wxCondError Wait();
+    wxCondError WaitTimeout(unsigned long milliseconds);
 
-    void Broadcast();
+    wxCondError Signal();
+    wxCondError Broadcast();
 
 private:
     // get the POSIX mutex associated with us
-    pthread_mutex_t *GetMutex() const { return &m_mutex.m_internal->m_mutex; }
+    pthread_mutex_t *GetPMutex() const { return &m_mutex.m_internal->m_mutex; }
 
     wxMutex& m_mutex;
     pthread_cond_t m_cond;
+
+    bool m_isOk;
 };
 
 wxConditionInternal::wxConditionInternal(wxMutex& mutex)
                    : m_mutex(mutex)
 {
-    if ( pthread_cond_init( &m_cond, NULL ) != 0 )
-    {
-        wxLogDebug(_T("pthread_cond_init() failed"));
-    }
-}
+    int err = pthread_cond_init(&m_cond, NULL /* default attributes */);
 
-wxConditionInternal::~wxConditionInternal()
-{
-    if ( pthread_cond_destroy( &m_cond ) != 0 )
-    {
-        wxLogDebug(_T("pthread_cond_destroy() failed"));
-    }
-}
+    m_isOk = err == 0;
 
-void wxConditionInternal::Wait()
-{
-    if ( pthread_cond_wait( &m_cond, GetMutex() ) != 0 )
+    if ( !m_isOk )
     {
-        wxLogDebug(_T("pthread_cond_wait() failed"));
+        wxLogApiError(_T("pthread_cond_init()"), err);
     }
 }
 
-bool wxConditionInternal::Wait( const timespec *ts )
+wxConditionInternal::~wxConditionInternal()
 {
-    int result = pthread_cond_timedwait( &m_cond, GetMutex(), ts );
-    if ( result == ETIMEDOUT )
-        return FALSE;
-
-    if ( result != 0 )
+    if ( m_isOk )
     {
-        wxLogDebug(_T("pthread_cond_timedwait() failed"));
+        int err = pthread_cond_destroy(&m_cond);
+        if ( err != 0 )
+        {
+            wxLogApiError(_T("pthread_cond_destroy()"), err);
+        }
     }
-
-    return TRUE;
 }
 
-void wxConditionInternal::Signal()
-{
-    int result = pthread_cond_signal( &m_cond );
-    if ( result != 0 )
+wxCondError wxConditionInternal::Wait()
 {
-        wxFAIL_MSG( _T("pthread_cond_signal() failed") );
-    }
-}
+    int err = pthread_cond_wait(&m_cond, GetPMutex());
+    if ( err != 0 )
+    {
+        wxLogApiError(_T("pthread_cond_wait()"), err);
 
-void wxConditionInternal::Broadcast()
-{
-    int result = pthread_cond_broadcast( &m_cond );
-    if ( result != 0 )
-{
-        wxFAIL_MSG( _T("pthread_cond_broadcast() failed") );
+        return wxCOND_MISC_ERROR;
     }
-}
 
-
-// ---------------------------------------------------------------------------
-// wxCondition
-// ---------------------------------------------------------------------------
-
-wxCondition::wxCondition(wxMutex& mutex)
-{
-    m_internal = new wxConditionInternal( mutex );
-}
-
-wxCondition::~wxCondition()
-{
-    delete m_internal;
+    return wxCOND_NO_ERROR;
 }
 
-void wxCondition::Wait()
-{
-    m_internal->Wait();
-}
-
-bool wxCondition::Wait( unsigned long timeout_millis )
+wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
 {
     wxLongLong curtime = wxGetLocalTimeMillis();
-    curtime += timeout_millis;
+    curtime += milliseconds;
     wxLongLong temp = curtime / 1000;
     int sec = temp.GetLo();
-    temp = temp * 1000;
+    temp *= 1000;
     temp = curtime - temp;
     int millis = temp.GetLo();
 
@@ -430,17 +382,46 @@ bool wxCondition::Wait( unsigned long timeout_millis )
     tspec.tv_sec = sec;
     tspec.tv_nsec = millis * 1000L * 1000L;
 
-    return m_internal->Wait(&tspec);
+    int err = pthread_cond_timedwait( &m_cond, GetPMutex(), &tspec );
+    switch ( err )
+    {
+        case ETIMEDOUT:
+            return wxCOND_TIMEOUT;
+
+        case 0:
+            return wxCOND_NO_ERROR;
+
+        default:
+            wxLogApiError(_T("pthread_cond_timedwait()"), err);
+    }
+
+    return wxCOND_MISC_ERROR;
 }
 
-void wxCondition::Signal()
+wxCondError wxConditionInternal::Signal()
 {
-    m_internal->Signal();
+    int err = pthread_cond_signal(&m_cond);
+    if ( err != 0 )
+    {
+        wxLogApiError(_T("pthread_cond_signal()"), err);
+
+        return wxCOND_MISC_ERROR;
+    }
+
+    return wxCOND_NO_ERROR;
 }
 
-void wxCondition::Broadcast()
+wxCondError wxConditionInternal::Broadcast()
 {
-    m_internal->Broadcast();
+    int err = pthread_cond_broadcast(&m_cond);
+    if ( err != 0 )
+    {
+        wxLogApiError(_T("pthread_cond_broadcast()"), err);
+
+        return wxCOND_MISC_ERROR;
+    }
+
+    return wxCOND_NO_ERROR;
 }
 
 // ===========================================================================
@@ -451,222 +432,131 @@ void wxCondition::Broadcast()
 // wxSemaphoreInternal
 // ---------------------------------------------------------------------------
 
+// we implement the semaphores using mutexes and conditions instead of using
+// the sem_xxx() POSIX functions because they're not widely available and also
+// because it's impossible to implement WaitTimeout() using them
 class wxSemaphoreInternal
 {
 public:
-    wxSemaphoreInternal( int initialcount, int maxcount );
+    wxSemaphoreInternal(int initialcount, int maxcount);
 
-    void Wait();
-    bool TryWait();
+    bool IsOk() const { return m_isOk; }
 
-    bool Wait( unsigned long timeout_millis );
+    wxSemaError Wait();
+    wxSemaError TryWait();
+    wxSemaError WaitTimeout(unsigned long milliseconds);
 
-    void Post();
+    wxSemaError Post();
 
 private:
     wxMutex m_mutex;
     wxCondition m_cond;
 
-    int count,
-        maxcount;
+    size_t m_count,
+           m_maxcount;
+
+    bool m_isOk;
 };
 
-wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount )
+wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
                    : m_cond(m_mutex)
 {
 
-    if ( (initialcount < 0) || ((maxcount > 0) && (initialcount > maxcount)) )
+    if ( (initialcount < 0 || maxcount < 0) ||
+            ((maxcount > 0) && (initialcount > maxcount)) )
+    {
+        wxFAIL_MSG( _T("wxSemaphore: invalid initial or maximal count") );
+
+        m_isOk = FALSE;
+    }
+    else
     {
-        wxFAIL_MSG( _T("wxSemaphore: invalid initial count") );
+        m_maxcount = (size_t)maxcount;
+        m_count = (size_t)initialcount;
     }
 
-    maxcount = maxcount;
-    count = initialcount;
+    m_isOk = m_mutex.IsOk() && m_cond.IsOk();
 }
 
-void wxSemaphoreInternal::Wait()
+wxSemaError wxSemaphoreInternal::Wait()
 {
     wxMutexLocker locker(m_mutex);
 
-    while ( count <= 0 )
+    while ( m_count == 0 )
     {
-        m_cond.Wait();
+        wxLogTrace(TRACE_SEMA,
+                   "Thread %ld waiting for semaphore to become signalled",
+                   wxThread::GetCurrentId());
+
+        if ( m_cond.Wait() != wxCOND_NO_ERROR )
+            return wxSEMA_MISC_ERROR;
+
+        wxLogTrace(TRACE_SEMA,
+                   "Thread %ld finished waiting for semaphore, count = %u",
+                   wxThread::GetCurrentId(), m_count);
     }
 
-    count--;
+    m_count--;
+
+    return wxSEMA_NO_ERROR;
 }
 
-bool wxSemaphoreInternal::TryWait()
+wxSemaError wxSemaphoreInternal::TryWait()
 {
     wxMutexLocker locker(m_mutex);
 
-    if ( count <= 0 )
-        return FALSE;
+    if ( m_count == 0 )
+        return wxSEMA_BUSY;
 
-    count--;
+    m_count--;
 
-    return TRUE;
+    return wxSEMA_NO_ERROR;
 }
 
-bool wxSemaphoreInternal::Wait( unsigned long timeout_millis )
+wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
 {
     wxMutexLocker locker(m_mutex);
 
     wxLongLong startTime = wxGetLocalTimeMillis();
 
-    while ( count <= 0 )
+    while ( m_count == 0 )
     {
         wxLongLong elapsed = wxGetLocalTimeMillis() - startTime;
-        long remainingTime = (long)timeout_millis - (long)elapsed.GetLo();
+        long remainingTime = (long)milliseconds - (long)elapsed.GetLo();
         if ( remainingTime <= 0 )
-            return FALSE;
+        {
+            // timeout
+            return wxSEMA_TIMEOUT;
+        }
 
-        bool result = m_cond.Wait( remainingTime );
-        if ( !result )
-            return FALSE;
+        if ( m_cond.Wait(remainingTime) != wxCOND_NO_ERROR )
+            return wxSEMA_MISC_ERROR;
     }
 
-    count--;
+    m_count--;
 
-    return TRUE;
+    return wxSEMA_NO_ERROR;
 }
 
-void wxSemaphoreInternal::Post()
+wxSemaError wxSemaphoreInternal::Post()
 {
     wxMutexLocker locker(m_mutex);
 
-    if ( maxcount > 0 && count == maxcount )
+    if ( m_maxcount > 0 && m_count == m_maxcount )
     {
-        wxFAIL_MSG( _T("wxSemaphore::Post() overflow") );
+        return wxSEMA_OVERFLOW;
     }
 
-    count++;
-
-    m_cond.Signal();
-}
-
-// --------------------------------------------------------------------------
-// wxSemaphore
-// --------------------------------------------------------------------------
-
-wxSemaphore::wxSemaphore( int initialcount, int maxcount )
-{
-    m_internal = new wxSemaphoreInternal( initialcount, maxcount );
-}
-
-wxSemaphore::~wxSemaphore()
-{
-    delete m_internal;
-}
-
-void wxSemaphore::Wait()
-{
-    m_internal->Wait();
-}
-
-bool wxSemaphore::TryWait()
-{
-    return m_internal->TryWait();
-}
-
-bool wxSemaphore::Wait( unsigned long timeout_millis )
-{
-    return m_internal->Wait( timeout_millis );
-}
+    m_count++;
 
-void wxSemaphore::Post()
-{
-    m_internal->Post();
+    wxLogTrace(TRACE_SEMA,
+               "Thread %ld about to signal semaphore, count = %u",
+               wxThread::GetCurrentId(), m_count);
+    
+    return m_cond.Signal() == wxCOND_NO_ERROR ? wxSEMA_NO_ERROR
+                                              : wxSEMA_MISC_ERROR;
 }
 
-// This class is used by wxThreadInternal to support Delete() on
-// a detached thread
-class wxRefCountedCondition
-{
-public:
-    // start with a initial reference count of 1
-    wxRefCountedCondition()
-    {
-        m_refCount = 1;
-        m_signaled = FALSE;
-
-        m_mutex = new wxMutex();
-        m_cond = new wxCondition( *m_mutex );
-    }
-
-    // increment the reference count
-    void AddRef()
-    {
-        wxMutexLocker locker( *m_mutex );
-
-        m_refCount++;
-    }
-
-    // decrement the reference count if reference count is zero then delete the
-    // object
-    void DeleteRef()
-    {
-        bool shouldDelete = FALSE;
-
-        m_mutex->Lock();
-
-        if ( --m_refCount == 0 )
-        {
-            shouldDelete = TRUE;
-        }
-
-        m_mutex->Unlock();
-
-        if ( shouldDelete )
-        {
-            delete this;
-        }
-    }
-
-
-    // sets the object to signaled this signal will be a persistent signal all
-    // further Wait()s on the object will return without blocking
-    void SetSignaled()
-    {
-        wxMutexLocker locker( *m_mutex );
-
-        m_signaled = TRUE;
-
-        m_cond->Broadcast();
-    }
-
-    // wait till the object is signaled if the object was already signaled then
-    // return immediately
-    void Wait()
-    {
-        wxMutexLocker locker( *m_mutex );
-
-        if ( !m_signaled )
-        {
-            m_cond->Wait();
-        }
-    }
-
-private:
-    int m_refCount;
-
-    wxMutex *m_mutex;
-    wxCondition *m_cond;
-
-    bool m_signaled;
-
-    // Cannot delete this object directly, call DeleteRef() instead
-    ~wxRefCountedCondition()
-    {
-        delete m_cond;
-        delete m_mutex;
-    }
-
-    // suppress gcc warning about the class having private dtor and not having
-    // friend (so what??)
-    friend class wxDummyFriend;
-};
-
 // ===========================================================================
 // wxThread implementation
 // ===========================================================================
@@ -700,12 +590,10 @@ public:
     // thread actions
         // start the thread
     wxThreadError Run();
+        // unblock the thread allowing it to run
+    void SignalRun() { m_semRun.Post(); }
         // ask the thread to terminate
     void Wait();
-        // wake up threads waiting for our termination
-    void SignalExit();
-        // wake up threads waiting for our start
-    void SignalRun() { m_semRun.Post(); }
         // go to sleep until Resume() is called
     void Pause();
         // resume the thread
@@ -717,7 +605,23 @@ public:
     void SetPriority(int prio) { m_prio = prio; }
         // state
     wxThreadState GetState() const { return m_state; }
-    void SetState(wxThreadState state) { m_state = state; }
+    void SetState(wxThreadState state)
+    {
+#ifdef __WXDEBUG__
+        static const wxChar *stateNames[] =
+        {
+            _T("NEW"),
+            _T("RUNNING"),
+            _T("PAUSED"),
+            _T("EXITED"),
+        };
+
+        wxLogTrace(TRACE_THREADS, _T("Thread %ld: %s => %s."),
+                   GetId(), stateNames[m_state], stateNames[state]);
+#endif // __WXDEBUG__
+
+        m_state = state;
+    }
         // id
     pthread_t GetId() const { return m_threadId; }
     pthread_t *GetIdPtr() { return &m_threadId; }
@@ -735,12 +639,11 @@ public:
         // tell the thread that it is a detached one
     void Detach()
     {
-        m_shouldBeJoined = m_shouldBroadcast = FALSE;
+        wxCriticalSectionLocker lock(m_csJoinFlag);
+
+        m_shouldBeJoined = FALSE;
         m_isDetached = TRUE;
     }
-        // but even detached threads need to notifyus about their termination
-        // sometimes - tell the thread that it should do it
-    void Notify() { m_shouldBroadcast = TRUE; }
 
 #if HAVE_THREAD_CLEANUP_FUNCTIONS
     // this is used by wxPthreadCleanup() only
@@ -766,7 +669,6 @@ private:
     // pthread_join(), so we have to keep track of this
     wxCriticalSection m_csJoinFlag;
     bool m_shouldBeJoined;
-    bool m_shouldBroadcast;
     bool m_isDetached;
 
     // this semaphore is posted by Run() and the threads Entry() is not
@@ -776,11 +678,6 @@ private:
     // this one is signaled when the thread should resume after having been
     // Pause()d
     wxSemaphore m_semSuspend;
-
-    // finally this one is signalled when the thread exits
-    // we are using a reference counted condition to support
-    // Delete() for a detached thread
-    wxRefCountedCondition *m_condEnd;
 };
 
 // ----------------------------------------------------------------------------
@@ -833,17 +730,17 @@ void *wxThreadInternal::PthreadStart(wxThread *thread)
     if ( !dontRunAtAll )
     {
         // call the main entry
+        wxLogTrace(TRACE_THREADS, _T("Thread %ld about to enter its Entry()."),
+                   pthread->GetId());
+
         pthread->m_exitcode = thread->Entry();
 
-        wxLogTrace(TRACE_THREADS, _T("Thread %ld left its Entry()."),
-                   pthread->GetId());
+        wxLogTrace(TRACE_THREADS, _T("Thread %ld Entry() returned %lu."),
+                   pthread->GetId(), (unsigned long)pthread->m_exitcode);
 
         {
             wxCriticalSectionLocker lock(thread->m_critsect);
 
-            wxLogTrace(TRACE_THREADS, _T("Thread %ld changes state to EXITED."),
-                       pthread->GetId());
-
             // change the state of the thread to "exited" so that
             // wxPthreadCleanup handler won't do anything from now (if it's
             // called before we do pthread_cleanup_pop below)
@@ -861,6 +758,7 @@ void *wxThreadInternal::PthreadStart(wxThread *thread)
 
     if ( dontRunAtAll )
     {
+        // FIXME: deleting a possibly joinable thread here???
         delete thread;
 
         return EXITCODE_CANCELLED;
@@ -918,15 +816,11 @@ wxThreadInternal::wxThreadInternal()
 
     // defaults for joinable threads
     m_shouldBeJoined = TRUE;
-    m_shouldBroadcast = TRUE;
     m_isDetached = FALSE;
-
-    m_condEnd = new wxRefCountedCondition();
 }
 
 wxThreadInternal::~wxThreadInternal()
 {
-    m_condEnd->DeleteRef();
 }
 
 wxThreadError wxThreadInternal::Run()
@@ -934,46 +828,29 @@ wxThreadError wxThreadInternal::Run()
     wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
                  wxT("thread may only be started once after Create()") );
 
-    SignalRun();
-
     SetState(STATE_RUNNING);
 
+    // wake up threads waiting for our start
+    SignalRun();
+
     return wxTHREAD_NO_ERROR;
 }
 
 void wxThreadInternal::Wait()
 {
+    wxCHECK_RET( !m_isDetached, _T("can't wait for a detached thread") );
+
     // if the thread we're waiting for is waiting for the GUI mutex, we will
     // deadlock so make sure we release it temporarily
     if ( wxThread::IsMain() )
         wxMutexGuiLeave();
 
-    bool isDetached = m_isDetached;
-    wxThreadIdType id = (wxThreadIdType) GetId();
-
     wxLogTrace(TRACE_THREADS,
-               _T("Starting to wait for thread %ld to exit."), id);
-
-    // wait until the thread terminates (we're blocking in _another_ thread,
-    // of course)
-
-    // a reference counting condition is used to handle the
-    // case where a detached thread deletes itself
-    // before m_condEnd->Wait() returns
-    // in this case the deletion of the condition object is deferred until
-    // all Wait()ing threads have finished calling DeleteRef()
-    m_condEnd->AddRef();
-    m_condEnd->Wait();
-    m_condEnd->DeleteRef();
+               _T("Starting to wait for thread %ld to exit."), GetId());
 
-    wxLogTrace(TRACE_THREADS, _T("Finished waiting for thread %ld."), id);
-
-    // we can't use any member variables any more if the thread is detached
-    // because it could be already deleted
-    if ( !isDetached )
+    // to avoid memory leaks we should call pthread_join(), but it must only be
+    // done once so use a critical section to serialize the code below
     {
-        // to avoid memory leaks we should call pthread_join(), but it must
-        // only be done once
         wxCriticalSectionLocker lock(m_csJoinFlag);
 
         if ( m_shouldBeJoined )
@@ -982,8 +859,12 @@ void wxThreadInternal::Wait()
             //       we're cancelled inside pthread_join(), things will almost
             //       certainly break - but if we disable the cancellation, we
             //       might deadlock
-            if ( pthread_join((pthread_t)id, &m_exitcode) != 0 )
+            if ( pthread_join((pthread_t)GetId(), &m_exitcode) != 0 )
             {
+                // this is a serious problem, so use wxLogError and not
+                // wxLogDebug: it is possible to bring the system to its knees
+                // by creating too many threads and not joining them quite
+                // easily
                 wxLogError(_("Failed to join a thread, potential memory leak "
                              "detected - please restart the program"));
             }
@@ -997,22 +878,6 @@ void wxThreadInternal::Wait()
         wxMutexGuiEnter();
 }
 
-void wxThreadInternal::SignalExit()
-{
-    wxLogTrace(TRACE_THREADS, _T("Thread %ld about to exit."), GetId());
-
-    SetState(STATE_EXITED);
-
-    // wake up all the threads waiting for our termination - if there are any
-    if ( m_shouldBroadcast )
-    {
-        wxLogTrace(TRACE_THREADS, _T("Thread %ld signals end condition."),
-                   GetId());
-
-        m_condEnd->SetSignaled();
-    }
-}
-
 void wxThreadInternal::Pause()
 {
     // the state is set from the thread which pauses us first, this function
@@ -1356,9 +1221,6 @@ wxThreadError wxThread::Pause()
         return wxTHREAD_NOT_RUNNING;
     }
 
-    wxLogTrace(TRACE_THREADS, _T("Asking thread %ld to pause."),
-               GetId());
-
     // just set a flag, the thread will be really paused only during the next
     // call to TestDestroy()
     m_internal->SetState(STATE_PAUSED);
@@ -1419,27 +1281,22 @@ wxThreadError wxThread::Delete(ExitCode *rc)
     wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
                  _T("a thread can't delete itself") );
 
+    bool isDetached = m_isDetached;
+
     m_critsect.Enter();
     wxThreadState state = m_internal->GetState();
 
     // ask the thread to stop
     m_internal->SetCancelFlag();
 
-    if ( m_isDetached )
-    {
-        // detached threads won't broadcast about their termination by default
-        // because usually nobody waits for them - but here we do, so ask the
-        // thread to notify us
-        m_internal->Notify();
-    }
-
     m_critsect.Leave();
 
     switch ( state )
     {
         case STATE_NEW:
             // we need to wake up the thread so that PthreadStart() will
-            // terminate - right now it's blocking on m_semRun
+            // terminate - right now it's blocking on run semaphore in
+            // PthreadStart()
             m_internal->SignalRun();
 
             // fall through
@@ -1449,24 +1306,24 @@ wxThreadError wxThread::Delete(ExitCode *rc)
             break;
 
         case STATE_PAUSED:
-            // resume the thread first (don't call our Resume() because this
-            // would dead lock when it tries to enter m_critsect)
+            // resume the thread first
             m_internal->Resume();
 
             // fall through
 
         default:
-            // wait until the thread stops
-            m_internal->Wait();
-
-            if ( rc )
+            if ( !isDetached )
             {
-                wxASSERT_MSG( !m_isDetached,
-                              _T("no return code for detached threads") );
+                // wait until the thread stops
+                m_internal->Wait();
 
-                // if it's a joinable thread, it's not deleted yet
-                *rc = m_internal->GetExitCode();
+                if ( rc )
+                {
+                    // return the exit code of the thread
+                    *rc = m_internal->GetExitCode();
+                }
             }
+            //else: can't wait for detached threads
     }
 
     return wxTHREAD_NO_ERROR;
@@ -1527,10 +1384,13 @@ void wxThread::Exit(ExitCode status)
                   _T("wxThread::Exit() can only be called in the "
                      "context of the same thread") );
 
-    // from the moment we call OnExit(), the main program may terminate at any
-    // moment, so mark this thread as being already in process of being
-    // deleted or wxThreadModule::OnExit() will try to delete it again
-    ScheduleThreadForDeletion();
+    if ( m_isDetached )
+    {
+        // from the moment we call OnExit(), the main program may terminate at
+        // any moment, so mark this thread as being already in process of being
+        // deleted or wxThreadModule::OnExit() will try to delete it again
+        ScheduleThreadForDeletion();
+    }
 
     // don't enter m_critsect before calling OnExit() because the user code
     // might deadlock if, for example, it signals a condition in OnExit() (a
@@ -1538,17 +1398,6 @@ void wxThread::Exit(ExitCode status)
     // m_critsect on us (almost all of them do)
     OnExit();
 
-    // now do enter it because SignalExit() will change our state
-    m_critsect.Enter();
-
-    // next wake up the threads waiting for us (OTOH, this function won't return
-    // until someone waited for us!)
-    m_internal->SignalExit();
-
-    // leave the critical section before entering the dtor which tries to
-    // enter it
-    m_critsect.Leave();
-
     // delete C++ thread object if this is a detached thread - user is
     // responsible for doing this for joinable ones
     if ( m_isDetached )
@@ -1617,18 +1466,6 @@ wxThread::~wxThread()
 
     // remove this thread from the global array
     gs_allThreads.Remove(this);
-
-    // detached thread will decrement this counter in DeleteThread(), but it
-    // is not called for the joinable threads, so do it here
-    if ( !m_isDetached )
-    {
-        wxMutexLocker lock( *gs_mutexDeleteThread );
-
-        gs_nThreadsBeingDeleted--;
-
-        wxLogTrace(TRACE_THREADS, _T("%u scheduled for deletion threads left."),
-                   gs_nThreadsBeingDeleted - 1);
-    }
 }
 
 // -----------------------------------------------------------------------------
@@ -1717,9 +1554,9 @@ void wxThreadModule::OnExit()
         nThreadsBeingDeleted = gs_nThreadsBeingDeleted;
 
         if ( nThreadsBeingDeleted > 0 )
-{
+        {
             wxLogTrace(TRACE_THREADS, _T("Waiting for %u threads to disappear"),
-                           nThreadsBeingDeleted);
+                       nThreadsBeingDeleted);
 
             // have to wait until all of them disappear
             gs_condAllDeleted->Wait();
@@ -1781,8 +1618,7 @@ static void DeleteThread(wxThread *This)
     delete This;
 
     wxCHECK_RET( gs_nThreadsBeingDeleted > 0,
-                     _T("no threads scheduled for deletion, yet we delete "
-                        "one?") );
+                 _T("no threads scheduled for deletion, yet we delete one?") );
 
     wxLogTrace(TRACE_THREADS, _T("%u scheduled for deletion threads left."),
                gs_nThreadsBeingDeleted - 1);
@@ -1808,5 +1644,11 @@ void wxMutexGuiLeave()
 #endif // wxUSE_GUI
 }
 
-#endif
-  // wxUSE_THREADS
+// ----------------------------------------------------------------------------
+// include common implementation code
+// ----------------------------------------------------------------------------
+
+#include "wx/thrimpl.cpp"
+
+#endif // wxUSE_THREADS
+