]> git.saurik.com Git - wxWidgets.git/commitdiff
thread fixes (compiles, but doesn't work yet)
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 21 Jan 1999 16:06:01 +0000 (16:06 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 21 Jan 1999 16:06:01 +0000 (16:06 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1443 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

src/gtk/threadgui.inc
src/gtk/threadpsx.cpp
src/gtk1/threadgui.inc
src/gtk1/threadpsx.cpp

index 7f29dc9cf165957c4b20dd382e602b54ff9fbddd..1717b172f66143d4b9a3894ef9ca8f020ea81126 100644 (file)
@@ -71,11 +71,10 @@ static void wxThreadGuiExit()
 
 void wxMutexGuiEnter()
 {
-  wxMainMutex->Lock();
+  gs_mutexGui->Lock();
 }
 
 void wxMutexGuiLeave()
 {
-  wxMainMutex->Unlock();
+  gs_mutexGui->Unlock();
 }
-
index f4fd5908db566e78ab7ed3acd809f9f4e6fc465b..28abd1b362df3a014fb1be3ee4bb35eecba6f3c3 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
 
 #ifdef __GNUG__
-#pragma implementation "thread.h"
+    #pragma implementation "thread.h"
 #endif
 
 #include <stdio.h>
 #include <unistd.h>
 #include <pthread.h>
 #include <errno.h>
+
+#ifdef __linux__
+    #include <sched.h>
+#endif
+
 #include "wx/thread.h"
 #include "wx/module.h"
 #include "wx/utils.h"
 #include "wx/log.h"
+#include "wx/intl.h"
 
 #include "gdk/gdk.h"
 #include "gtk/gtk.h"
 
-enum thread_state 
+enum thread_state
 {
-  STATE_IDLE = 0,
-  STATE_RUNNING,
-  STATE_PAUSING,
-  STATE_PAUSED,
-  STATE_CANCELED,
-  STATE_EXITED
+    STATE_NEW,          // didn't start execution yet (=> RUNNING)
+    STATE_RUNNING,
+    STATE_PAUSED,
+    STATE_CANCELED,
+    STATE_EXITED
 };
 
 //--------------------------------------------------------------------
 // global data
 //--------------------------------------------------------------------
 
-static pthread_t p_mainid;
+// the id of the main thread
+static pthread_t gs_pidMain;
 
-wxMutex *wxMainMutex; /* controls access to all GUI functions */
+// the key for the pointer to the associated wxThread object
+static pthread_key_t gs_keySelf;
+
+// this mutex must be acquired before any call to a GUI function
+static wxMutex *gs_mutexGui;
 
 //--------------------------------------------------------------------
 // common GUI thread code
@@ -55,7 +65,7 @@ wxMutex *wxMainMutex; /* controls access to all GUI functions */
 // wxMutex (Posix implementation)
 //--------------------------------------------------------------------
 
-class wxMutexInternal 
+class wxMutexInternal
 {
 public:
   pthread_mutex_t p_mutex;
@@ -71,7 +81,7 @@ wxMutex::wxMutex()
 wxMutex::~wxMutex()
 {
     if (m_locked > 0)
-        wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)\n", m_locked );
+        wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)", m_locked );
 
     pthread_mutex_destroy( &(p_internal->p_mutex) );
     delete p_internal;
@@ -84,9 +94,9 @@ wxMutexError wxMutex::Lock()
     {
         return wxMUTEX_DEAD_LOCK;
     }
-       
+
     m_locked++;
-    
+
     return wxMUTEX_NO_ERROR;
 }
 
@@ -96,15 +106,15 @@ wxMutexError wxMutex::TryLock()
     {
         return wxMUTEX_BUSY;
     }
-       
+
     int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
-    switch (err) 
+    switch (err)
     {
         case EBUSY: return wxMUTEX_BUSY;
     }
-    
+
     m_locked++;
-    
+
     return wxMUTEX_NO_ERROR;
 }
 
@@ -118,9 +128,9 @@ wxMutexError wxMutex::Unlock()
     {
         return wxMUTEX_UNLOCKED;
     }
-       
+
     pthread_mutex_unlock( &(p_internal->p_mutex) );
-    
+
     return wxMUTEX_NO_ERROR;
 }
 
@@ -128,7 +138,7 @@ wxMutexError wxMutex::Unlock()
 // wxCondition (Posix implementation)
 //--------------------------------------------------------------------
 
-class wxConditionInternal 
+class wxConditionInternal
 {
 public:
   pthread_cond_t p_condition;
@@ -143,7 +153,7 @@ wxCondition::wxCondition()
 wxCondition::~wxCondition()
 {
     pthread_cond_destroy( &(p_internal->p_condition) );
-    
+
     delete p_internal;
 }
 
@@ -175,218 +185,378 @@ void wxCondition::Broadcast()
 // wxThread (Posix implementation)
 //--------------------------------------------------------------------
 
-class wxThreadInternal 
+class wxThreadInternal
 {
 public:
-  wxThreadInternal() { state = STATE_IDLE; }
-  ~wxThreadInternal() {}
-  static void *PthreadStart(void *ptr);
-  pthread_t thread_id;
-  int state;
-  int prio;
-  int defer_destroy;
+    wxThreadInternal() { m_state = STATE_NEW; }
+    ~wxThreadInternal() {}
+
+    // thread entry function
+    static void *PthreadStart(void *ptr);
+
+    // start the thread
+    wxThreadError Run();
+
+    // accessors
+        // priority
+    int GetPriority() const { return m_prio; }
+    void SetPriority(int prio) { m_prio = prio; }
+        // state
+    thread_state GetState() const { return m_state; }
+    void SetState(thread_state state) { m_state = state; }
+        // id
+    pthread_t GetId() const { return thread_id; }
+        // "cancelled" flag
+    void Cancel();
+    bool WasCancelled() const { return m_cancelled; }
+
+//private: -- should be!
+    pthread_t thread_id;
+
+private:
+    thread_state m_state;    // see thread_state enum
+    int          m_prio;     // in wxWindows units: from 0 to 100
+
+    // set when the thread should terminate
+    bool m_cancelled;
+
+    // we start running when this condition becomes true
+    wxMutex     m_mutexRun;
+    wxCondition m_condRun;
+
+    // this condition becomes true when we get back to PthreadStart() function
+    wxMutex     m_mutexStop;
+    wxCondition m_condStop;
 };
 
 void *wxThreadInternal::PthreadStart(void *ptr)
 {
     wxThread *thread = (wxThread *)ptr;
+    wxThreadInternal *pthread = thread->p_internal;
 
-    /* Call the main entry */
-    pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, (int*) NULL );
+    if ( pthread_setspecific(gs_keySelf, thread) != 0 )
+    {
+        wxLogError(_("Can not start thread: error writing TLS."));
+
+        return (void *)-1;
+    }
+
+    // wait for the condition to be signaled from Run()
+    pthread->m_mutexRun.Lock();
+    pthread->m_condRun.Wait(pthread->m_mutexRun);
+
+    // call the main entry
     void* status = thread->Entry();
 
+    pthread->m_mutexRun.Unlock();
+
+    // wake up the pthread(s) waiting for our termination
+    pthread->m_condStop.Broadcast();
+
+    // terminate the thread
     thread->Exit(status);
 
+    wxFAIL_MSG("wxThread::Exit() can't return.");
+
     return NULL;
 }
 
-wxThreadError wxThread::Create()
+wxThreadError wxThreadInternal::Run()
 {
-    pthread_attr_t a;
-    int min_prio, max_prio, p;
-    struct sched_param sp;
+    wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
+                 "thread may only be started once after successful Create()" );
 
-    if (p_internal->state != STATE_IDLE)
-        return wxTHREAD_RUNNING;
+    wxMutexLocker lock(&m_mutexRun);
+    m_condRun.Signal();
 
-    /* Change thread priority */
-    pthread_attr_init(&a);
-    pthread_attr_getschedpolicy(&a, &p);
+    return wxTHREAD_NO_ERROR;
+}
 
-    min_prio = sched_get_priority_min(p);
-    max_prio = sched_get_priority_max(p);
+void wxThreadInternal::Cancel()
+{
+    wxMutexLocker lock(&m_mutexStop);
+    m_cancelled = TRUE;
+    m_condStop.Wait(m_mutexStop);
+}
 
-    pthread_attr_getschedparam(&a, &sp);
-    sp.sched_priority = min_prio +
-               (p_internal->prio*(max_prio-min_prio))/100;
-    pthread_attr_setschedparam(&a, &sp);
+// -----------------------------------------------------------------------------
+// static functions
+// -----------------------------------------------------------------------------
 
-    // this is the point of no return
-    p_internal->state = STATE_RUNNING;
-    if (pthread_create(&p_internal->thread_id, &a,
-                     wxThreadInternal::PthreadStart, (void *)this) != 0) 
-    {
-        p_internal->state = STATE_IDLE;
-        pthread_attr_destroy(&a);
-        return wxTHREAD_NO_RESOURCE;
-    }
-    pthread_attr_destroy(&a);
+wxThread *wxThread::This()
+{
+    return (wxThread *)pthread_getspecific(gs_keySelf);
+}
 
-    return wxTHREAD_NO_ERROR;
+bool wxThread::IsMain()
+{
+    return (bool)pthread_equal(pthread_self(), gs_pidMain);
+}
+
+void wxThread::Yield()
+{
+    sched_yield();
 }
 
-void wxThread::SetPriority(int prio)
+void wxThread::Sleep(unsigned long milliseconds)
 {
-    if (p_internal->state == STATE_RUNNING)
-        return;
+    // FIXME how to test for nanosleep() availability?
 
-    if (prio > 100) prio = 100;
-       
-    if (prio < 0) prio = 0;
-    
-    p_internal->prio = prio;
+    usleep(milliseconds * 1000); // usleep(3) wants microseconds
 }
 
-int wxThread::GetPriority() const
+// -----------------------------------------------------------------------------
+// creating thread
+// -----------------------------------------------------------------------------
+
+wxThread::wxThread()
 {
-    return p_internal->prio;
+    p_internal = new wxThreadInternal();
 }
 
-void wxThread::DeferDestroy(bool on)
+wxThreadError wxThread::Create()
 {
-    if (on)
-        pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, (int*) NULL);
+    if (p_internal->GetState() != STATE_NEW)
+        return wxTHREAD_RUNNING;
+
+    // set up the thread attribute: right now, we only set thread priority
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+
+    int prio;
+    if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
+    {
+        wxLogError(_("Can not retrieve thread scheduling policy."));
+    }
+
+    int min_prio = sched_get_priority_min(prio),
+        max_prio = sched_get_priority_max(prio);
+
+    if ( min_prio == -1 || max_prio == -1 )
+    {
+        wxLogError(_("Can not get priority range for scheduling policy %d."),
+                   prio);
+    }
     else
-        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, (int*) NULL);
+    {
+        struct sched_param sp;
+        pthread_attr_getschedparam(&attr, &sp);
+        sp.sched_priority = min_prio +
+                           (p_internal->GetPriority()*(max_prio-min_prio))/100;
+        pthread_attr_setschedparam(&attr, &sp);
+    }
+
+    // this is the point of no return
+    int rc = pthread_create(&p_internal->thread_id, &attr,
+                            wxThreadInternal::PthreadStart, (void *)this);
+    pthread_attr_destroy(&attr);
+
+    if ( rc != 0 )
+    {
+        p_internal->SetState(STATE_EXITED);
+        return wxTHREAD_NO_RESOURCE;
+    }
+
+    return wxTHREAD_NO_ERROR;
 }
 
-wxThreadError wxThread::Destroy()
+wxThreadError wxThread::Run()
 {
-    int res = 0;
+    return p_internal->Run();
+}
+
+// -----------------------------------------------------------------------------
+// misc accessors
+// -----------------------------------------------------------------------------
 
-    if (p_internal->state == STATE_RUNNING) 
+void wxThread::SetPriority(unsigned int prio)
+{
+    wxCHECK_RET( (WXTHREAD_MIN_PRIORITY <= prio) &&
+                 (prio <= WXTHREAD_MAX_PRIORITY), "invalid thread priority" );
+
+    wxCriticalSectionLocker lock(m_critsect);
+
+    switch ( p_internal->GetState() )
     {
-        res = pthread_cancel(p_internal->thread_id);
-        if (res == 0)
-           p_internal->state = STATE_CANCELED;
+        case STATE_NEW:
+            // thread not yet started, priority will be set when it is
+            p_internal->SetPriority(prio);
+            break;
+
+        case STATE_RUNNING:
+        case STATE_PAUSED:
+            {
+                struct sched_param sparam;
+                sparam.sched_priority = prio;
+
+                if ( pthread_setschedparam(p_internal->GetId(),
+                                           SCHED_OTHER, &sparam) != 0 )
+                {
+                    wxLogError(_("Failed to set thread priority %d."), prio);
+                }
+            }
+            break;
+
+        case STATE_EXITED:
+        default:
+            wxFAIL_MSG("impossible to set thread priority in this state");
     }
+}
 
-    return wxTHREAD_NO_ERROR;
+unsigned int wxThread::GetPriority() const
+{
+    wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
+
+    return p_internal->GetPriority();
 }
 
+unsigned long wxThread::GetID() const
+{
+    return (unsigned long)p_internal->thread_id;
+}
+
+// -----------------------------------------------------------------------------
+// pause/resume
+// -----------------------------------------------------------------------------
+
 wxThreadError wxThread::Pause()
 {
-    if (p_internal->state != STATE_RUNNING)
+    wxCriticalSectionLocker lock(m_critsect);
+
+    if ( p_internal->GetState() != STATE_RUNNING )
+    {
+        wxLogDebug("Can't pause thread which is not running.");
+
         return wxTHREAD_NOT_RUNNING;
+    }
 
-    if (!p_internal->defer_destroy)
-        return wxTHREAD_MISC_ERROR;
+    p_internal->SetState(STATE_PAUSED);
 
-    p_internal->state = STATE_PAUSING;
     return wxTHREAD_NO_ERROR;
 }
 
 wxThreadError wxThread::Resume()
 {
-    if (p_internal->state == STATE_PAUSING || p_internal->state == STATE_PAUSED)
-      p_internal->state = STATE_RUNNING;
+    wxCriticalSectionLocker lock(m_critsect);
 
-    return wxTHREAD_NO_ERROR;
+    if ( p_internal->GetState() == STATE_PAUSED )
+    {
+        p_internal->SetState(STATE_RUNNING);
+
+        return wxTHREAD_NO_ERROR;
+    }
+    else
+    {
+        wxLogDebug("Attempt to resume a thread which is not paused.");
+
+        return wxTHREAD_MISC_ERROR;
+    }
 }
 
-void *wxThread::Join()
+// -----------------------------------------------------------------------------
+// exiting thread
+// -----------------------------------------------------------------------------
+
+wxThread::ExitCode wxThread::Delete()
 {
-    void* status = 0;
+    m_critsect.Enter();
+    thread_state state = p_internal->GetState();
+    m_critsect.Leave();
 
-    if (p_internal->state != STATE_IDLE) 
+    switch ( state )
     {
-        bool do_unlock = wxThread::IsMain();
+        case STATE_NEW:
+        case STATE_EXITED:
+            // nothing to do
+            break;
 
-        while (p_internal->state == STATE_RUNNING)
-            wxYield();
+        case STATE_PAUSED:
+            // resume the thread first
+            Resume();
 
-        if (do_unlock) wxMainMutex->Unlock();
-      
-        pthread_join(p_internal->thread_id, &status);
-      
-        if (do_unlock) wxMainMutex->Lock();
+            // fall through
 
-        p_internal->state = STATE_IDLE;
+        default:
+            // set the flag telling to the thread to stop and wait
+            p_internal->Cancel();
     }
-    
-    return status;
+
+    return NULL;
 }
 
-unsigned long wxThread::GetID() const
+wxThreadError wxThread::Kill()
 {
-    return p_internal->thread_id;
+    switch ( p_internal->GetState() )
+    {
+        case STATE_NEW:
+        case STATE_EXITED:
+            return wxTHREAD_NOT_RUNNING;
+
+        default:
+            if ( pthread_cancel(p_internal->GetId()) != 0 )
+            {
+                wxLogError(_("Failed to terminate a thread."));
+
+                return wxTHREAD_MISC_ERROR;
+            }
+
+            return wxTHREAD_NO_ERROR;
+    }
 }
 
 void wxThread::Exit(void *status)
 {
-    wxThread* ptr = this;
-
+    wxThread *ptr = this;
     THREAD_SEND_EXIT_MSG(ptr);
-    p_internal->state = STATE_EXITED;
+
+    OnExit();
+
+    p_internal->SetState(STATE_EXITED);
+
+    delete this;
+
     pthread_exit(status);
 }
 
-bool wxThread::TestDestroy()
+bool wxThread::TestDestroy() const
 {
-    if (p_internal->state == STATE_PAUSING) 
-    {
-        p_internal->state = STATE_PAUSED;
-        while (p_internal->state == STATE_PAUSED) 
-       {
-            pthread_testcancel();
-            usleep(1);
-        }
-    }
+    wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
 
-    // VZ: do I understand it correctly that it will terminate the thread all by
-    //     itself if it was cancelled?
-    pthread_testcancel();
-    
-    return FALSE;
+    return p_internal->WasCancelled();
 }
 
-bool wxThread::IsMain()
+wxThread::~wxThread()
 {
-    return (bool)pthread_equal(pthread_self(), p_mainid);
 }
 
+// -----------------------------------------------------------------------------
+// state tests
+// -----------------------------------------------------------------------------
+
 bool wxThread::IsRunning() const
 {
-    return (p_internal->state == STATE_RUNNING);
+    wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
+
+    return p_internal->GetState() == STATE_RUNNING;
 }
 
 bool wxThread::IsAlive() const
 {
-    return (p_internal->state == STATE_RUNNING) ||
-           (p_internal->state == STATE_PAUSING) ||
-           (p_internal->state == STATE_PAUSED);
-}
+    wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
 
-wxThread::wxThread()
-{
-    p_internal = new wxThreadInternal();
-}
-
-wxThread::~wxThread()
-{
-    Destroy();
-    Join();
-    delete p_internal;
-}
+    switch ( p_internal->GetState() )
+    {
+        case STATE_RUNNING:
+        case STATE_PAUSED:
+            return TRUE;
 
-/* The default callback just joins the thread and throws away the result. */
-void wxThread::OnExit()
-{
-    Join();
+        default:
+            return FALSE;
+    }
 }
 
 //--------------------------------------------------------------------
-// wxThreadModule 
+// wxThreadModule
 //--------------------------------------------------------------------
 
 class wxThreadModule : public wxModule
@@ -401,20 +571,29 @@ private:
 
 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
 
-bool wxThreadModule::OnInit() 
+bool wxThreadModule::OnInit()
 {
-    wxMainMutex = new wxMutex();
+    if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 )
+    {
+        wxLogError(_("Thread module initialization failed: "
+                     "failed to create pthread key."));
+
+        return FALSE;
+    }
+
+    gs_mutexGui = new wxMutex();
     wxThreadGuiInit();
-    p_mainid = (int)getpid();
-    wxMainMutex->Lock();
+    gs_pidMain = (int)getpid();
+    gs_mutexGui->Lock();
+
     return TRUE;
 }
 
 void wxThreadModule::OnExit()
 {
-    wxMainMutex->Unlock();
+    gs_mutexGui->Unlock();
     wxThreadGuiExit();
-    delete wxMainMutex;
-}
-
+    delete gs_mutexGui;
 
+    (void)pthread_key_delete(gs_keySelf);
+}
index 7f29dc9cf165957c4b20dd382e602b54ff9fbddd..1717b172f66143d4b9a3894ef9ca8f020ea81126 100644 (file)
@@ -71,11 +71,10 @@ static void wxThreadGuiExit()
 
 void wxMutexGuiEnter()
 {
-  wxMainMutex->Lock();
+  gs_mutexGui->Lock();
 }
 
 void wxMutexGuiLeave()
 {
-  wxMainMutex->Unlock();
+  gs_mutexGui->Unlock();
 }
-
index f4fd5908db566e78ab7ed3acd809f9f4e6fc465b..28abd1b362df3a014fb1be3ee4bb35eecba6f3c3 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
 
 #ifdef __GNUG__
-#pragma implementation "thread.h"
+    #pragma implementation "thread.h"
 #endif
 
 #include <stdio.h>
 #include <unistd.h>
 #include <pthread.h>
 #include <errno.h>
+
+#ifdef __linux__
+    #include <sched.h>
+#endif
+
 #include "wx/thread.h"
 #include "wx/module.h"
 #include "wx/utils.h"
 #include "wx/log.h"
+#include "wx/intl.h"
 
 #include "gdk/gdk.h"
 #include "gtk/gtk.h"
 
-enum thread_state 
+enum thread_state
 {
-  STATE_IDLE = 0,
-  STATE_RUNNING,
-  STATE_PAUSING,
-  STATE_PAUSED,
-  STATE_CANCELED,
-  STATE_EXITED
+    STATE_NEW,          // didn't start execution yet (=> RUNNING)
+    STATE_RUNNING,
+    STATE_PAUSED,
+    STATE_CANCELED,
+    STATE_EXITED
 };
 
 //--------------------------------------------------------------------
 // global data
 //--------------------------------------------------------------------
 
-static pthread_t p_mainid;
+// the id of the main thread
+static pthread_t gs_pidMain;
 
-wxMutex *wxMainMutex; /* controls access to all GUI functions */
+// the key for the pointer to the associated wxThread object
+static pthread_key_t gs_keySelf;
+
+// this mutex must be acquired before any call to a GUI function
+static wxMutex *gs_mutexGui;
 
 //--------------------------------------------------------------------
 // common GUI thread code
@@ -55,7 +65,7 @@ wxMutex *wxMainMutex; /* controls access to all GUI functions */
 // wxMutex (Posix implementation)
 //--------------------------------------------------------------------
 
-class wxMutexInternal 
+class wxMutexInternal
 {
 public:
   pthread_mutex_t p_mutex;
@@ -71,7 +81,7 @@ wxMutex::wxMutex()
 wxMutex::~wxMutex()
 {
     if (m_locked > 0)
-        wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)\n", m_locked );
+        wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)", m_locked );
 
     pthread_mutex_destroy( &(p_internal->p_mutex) );
     delete p_internal;
@@ -84,9 +94,9 @@ wxMutexError wxMutex::Lock()
     {
         return wxMUTEX_DEAD_LOCK;
     }
-       
+
     m_locked++;
-    
+
     return wxMUTEX_NO_ERROR;
 }
 
@@ -96,15 +106,15 @@ wxMutexError wxMutex::TryLock()
     {
         return wxMUTEX_BUSY;
     }
-       
+
     int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
-    switch (err) 
+    switch (err)
     {
         case EBUSY: return wxMUTEX_BUSY;
     }
-    
+
     m_locked++;
-    
+
     return wxMUTEX_NO_ERROR;
 }
 
@@ -118,9 +128,9 @@ wxMutexError wxMutex::Unlock()
     {
         return wxMUTEX_UNLOCKED;
     }
-       
+
     pthread_mutex_unlock( &(p_internal->p_mutex) );
-    
+
     return wxMUTEX_NO_ERROR;
 }
 
@@ -128,7 +138,7 @@ wxMutexError wxMutex::Unlock()
 // wxCondition (Posix implementation)
 //--------------------------------------------------------------------
 
-class wxConditionInternal 
+class wxConditionInternal
 {
 public:
   pthread_cond_t p_condition;
@@ -143,7 +153,7 @@ wxCondition::wxCondition()
 wxCondition::~wxCondition()
 {
     pthread_cond_destroy( &(p_internal->p_condition) );
-    
+
     delete p_internal;
 }
 
@@ -175,218 +185,378 @@ void wxCondition::Broadcast()
 // wxThread (Posix implementation)
 //--------------------------------------------------------------------
 
-class wxThreadInternal 
+class wxThreadInternal
 {
 public:
-  wxThreadInternal() { state = STATE_IDLE; }
-  ~wxThreadInternal() {}
-  static void *PthreadStart(void *ptr);
-  pthread_t thread_id;
-  int state;
-  int prio;
-  int defer_destroy;
+    wxThreadInternal() { m_state = STATE_NEW; }
+    ~wxThreadInternal() {}
+
+    // thread entry function
+    static void *PthreadStart(void *ptr);
+
+    // start the thread
+    wxThreadError Run();
+
+    // accessors
+        // priority
+    int GetPriority() const { return m_prio; }
+    void SetPriority(int prio) { m_prio = prio; }
+        // state
+    thread_state GetState() const { return m_state; }
+    void SetState(thread_state state) { m_state = state; }
+        // id
+    pthread_t GetId() const { return thread_id; }
+        // "cancelled" flag
+    void Cancel();
+    bool WasCancelled() const { return m_cancelled; }
+
+//private: -- should be!
+    pthread_t thread_id;
+
+private:
+    thread_state m_state;    // see thread_state enum
+    int          m_prio;     // in wxWindows units: from 0 to 100
+
+    // set when the thread should terminate
+    bool m_cancelled;
+
+    // we start running when this condition becomes true
+    wxMutex     m_mutexRun;
+    wxCondition m_condRun;
+
+    // this condition becomes true when we get back to PthreadStart() function
+    wxMutex     m_mutexStop;
+    wxCondition m_condStop;
 };
 
 void *wxThreadInternal::PthreadStart(void *ptr)
 {
     wxThread *thread = (wxThread *)ptr;
+    wxThreadInternal *pthread = thread->p_internal;
 
-    /* Call the main entry */
-    pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, (int*) NULL );
+    if ( pthread_setspecific(gs_keySelf, thread) != 0 )
+    {
+        wxLogError(_("Can not start thread: error writing TLS."));
+
+        return (void *)-1;
+    }
+
+    // wait for the condition to be signaled from Run()
+    pthread->m_mutexRun.Lock();
+    pthread->m_condRun.Wait(pthread->m_mutexRun);
+
+    // call the main entry
     void* status = thread->Entry();
 
+    pthread->m_mutexRun.Unlock();
+
+    // wake up the pthread(s) waiting for our termination
+    pthread->m_condStop.Broadcast();
+
+    // terminate the thread
     thread->Exit(status);
 
+    wxFAIL_MSG("wxThread::Exit() can't return.");
+
     return NULL;
 }
 
-wxThreadError wxThread::Create()
+wxThreadError wxThreadInternal::Run()
 {
-    pthread_attr_t a;
-    int min_prio, max_prio, p;
-    struct sched_param sp;
+    wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
+                 "thread may only be started once after successful Create()" );
 
-    if (p_internal->state != STATE_IDLE)
-        return wxTHREAD_RUNNING;
+    wxMutexLocker lock(&m_mutexRun);
+    m_condRun.Signal();
 
-    /* Change thread priority */
-    pthread_attr_init(&a);
-    pthread_attr_getschedpolicy(&a, &p);
+    return wxTHREAD_NO_ERROR;
+}
 
-    min_prio = sched_get_priority_min(p);
-    max_prio = sched_get_priority_max(p);
+void wxThreadInternal::Cancel()
+{
+    wxMutexLocker lock(&m_mutexStop);
+    m_cancelled = TRUE;
+    m_condStop.Wait(m_mutexStop);
+}
 
-    pthread_attr_getschedparam(&a, &sp);
-    sp.sched_priority = min_prio +
-               (p_internal->prio*(max_prio-min_prio))/100;
-    pthread_attr_setschedparam(&a, &sp);
+// -----------------------------------------------------------------------------
+// static functions
+// -----------------------------------------------------------------------------
 
-    // this is the point of no return
-    p_internal->state = STATE_RUNNING;
-    if (pthread_create(&p_internal->thread_id, &a,
-                     wxThreadInternal::PthreadStart, (void *)this) != 0) 
-    {
-        p_internal->state = STATE_IDLE;
-        pthread_attr_destroy(&a);
-        return wxTHREAD_NO_RESOURCE;
-    }
-    pthread_attr_destroy(&a);
+wxThread *wxThread::This()
+{
+    return (wxThread *)pthread_getspecific(gs_keySelf);
+}
 
-    return wxTHREAD_NO_ERROR;
+bool wxThread::IsMain()
+{
+    return (bool)pthread_equal(pthread_self(), gs_pidMain);
+}
+
+void wxThread::Yield()
+{
+    sched_yield();
 }
 
-void wxThread::SetPriority(int prio)
+void wxThread::Sleep(unsigned long milliseconds)
 {
-    if (p_internal->state == STATE_RUNNING)
-        return;
+    // FIXME how to test for nanosleep() availability?
 
-    if (prio > 100) prio = 100;
-       
-    if (prio < 0) prio = 0;
-    
-    p_internal->prio = prio;
+    usleep(milliseconds * 1000); // usleep(3) wants microseconds
 }
 
-int wxThread::GetPriority() const
+// -----------------------------------------------------------------------------
+// creating thread
+// -----------------------------------------------------------------------------
+
+wxThread::wxThread()
 {
-    return p_internal->prio;
+    p_internal = new wxThreadInternal();
 }
 
-void wxThread::DeferDestroy(bool on)
+wxThreadError wxThread::Create()
 {
-    if (on)
-        pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, (int*) NULL);
+    if (p_internal->GetState() != STATE_NEW)
+        return wxTHREAD_RUNNING;
+
+    // set up the thread attribute: right now, we only set thread priority
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+
+    int prio;
+    if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
+    {
+        wxLogError(_("Can not retrieve thread scheduling policy."));
+    }
+
+    int min_prio = sched_get_priority_min(prio),
+        max_prio = sched_get_priority_max(prio);
+
+    if ( min_prio == -1 || max_prio == -1 )
+    {
+        wxLogError(_("Can not get priority range for scheduling policy %d."),
+                   prio);
+    }
     else
-        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, (int*) NULL);
+    {
+        struct sched_param sp;
+        pthread_attr_getschedparam(&attr, &sp);
+        sp.sched_priority = min_prio +
+                           (p_internal->GetPriority()*(max_prio-min_prio))/100;
+        pthread_attr_setschedparam(&attr, &sp);
+    }
+
+    // this is the point of no return
+    int rc = pthread_create(&p_internal->thread_id, &attr,
+                            wxThreadInternal::PthreadStart, (void *)this);
+    pthread_attr_destroy(&attr);
+
+    if ( rc != 0 )
+    {
+        p_internal->SetState(STATE_EXITED);
+        return wxTHREAD_NO_RESOURCE;
+    }
+
+    return wxTHREAD_NO_ERROR;
 }
 
-wxThreadError wxThread::Destroy()
+wxThreadError wxThread::Run()
 {
-    int res = 0;
+    return p_internal->Run();
+}
+
+// -----------------------------------------------------------------------------
+// misc accessors
+// -----------------------------------------------------------------------------
 
-    if (p_internal->state == STATE_RUNNING) 
+void wxThread::SetPriority(unsigned int prio)
+{
+    wxCHECK_RET( (WXTHREAD_MIN_PRIORITY <= prio) &&
+                 (prio <= WXTHREAD_MAX_PRIORITY), "invalid thread priority" );
+
+    wxCriticalSectionLocker lock(m_critsect);
+
+    switch ( p_internal->GetState() )
     {
-        res = pthread_cancel(p_internal->thread_id);
-        if (res == 0)
-           p_internal->state = STATE_CANCELED;
+        case STATE_NEW:
+            // thread not yet started, priority will be set when it is
+            p_internal->SetPriority(prio);
+            break;
+
+        case STATE_RUNNING:
+        case STATE_PAUSED:
+            {
+                struct sched_param sparam;
+                sparam.sched_priority = prio;
+
+                if ( pthread_setschedparam(p_internal->GetId(),
+                                           SCHED_OTHER, &sparam) != 0 )
+                {
+                    wxLogError(_("Failed to set thread priority %d."), prio);
+                }
+            }
+            break;
+
+        case STATE_EXITED:
+        default:
+            wxFAIL_MSG("impossible to set thread priority in this state");
     }
+}
 
-    return wxTHREAD_NO_ERROR;
+unsigned int wxThread::GetPriority() const
+{
+    wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
+
+    return p_internal->GetPriority();
 }
 
+unsigned long wxThread::GetID() const
+{
+    return (unsigned long)p_internal->thread_id;
+}
+
+// -----------------------------------------------------------------------------
+// pause/resume
+// -----------------------------------------------------------------------------
+
 wxThreadError wxThread::Pause()
 {
-    if (p_internal->state != STATE_RUNNING)
+    wxCriticalSectionLocker lock(m_critsect);
+
+    if ( p_internal->GetState() != STATE_RUNNING )
+    {
+        wxLogDebug("Can't pause thread which is not running.");
+
         return wxTHREAD_NOT_RUNNING;
+    }
 
-    if (!p_internal->defer_destroy)
-        return wxTHREAD_MISC_ERROR;
+    p_internal->SetState(STATE_PAUSED);
 
-    p_internal->state = STATE_PAUSING;
     return wxTHREAD_NO_ERROR;
 }
 
 wxThreadError wxThread::Resume()
 {
-    if (p_internal->state == STATE_PAUSING || p_internal->state == STATE_PAUSED)
-      p_internal->state = STATE_RUNNING;
+    wxCriticalSectionLocker lock(m_critsect);
 
-    return wxTHREAD_NO_ERROR;
+    if ( p_internal->GetState() == STATE_PAUSED )
+    {
+        p_internal->SetState(STATE_RUNNING);
+
+        return wxTHREAD_NO_ERROR;
+    }
+    else
+    {
+        wxLogDebug("Attempt to resume a thread which is not paused.");
+
+        return wxTHREAD_MISC_ERROR;
+    }
 }
 
-void *wxThread::Join()
+// -----------------------------------------------------------------------------
+// exiting thread
+// -----------------------------------------------------------------------------
+
+wxThread::ExitCode wxThread::Delete()
 {
-    void* status = 0;
+    m_critsect.Enter();
+    thread_state state = p_internal->GetState();
+    m_critsect.Leave();
 
-    if (p_internal->state != STATE_IDLE) 
+    switch ( state )
     {
-        bool do_unlock = wxThread::IsMain();
+        case STATE_NEW:
+        case STATE_EXITED:
+            // nothing to do
+            break;
 
-        while (p_internal->state == STATE_RUNNING)
-            wxYield();
+        case STATE_PAUSED:
+            // resume the thread first
+            Resume();
 
-        if (do_unlock) wxMainMutex->Unlock();
-      
-        pthread_join(p_internal->thread_id, &status);
-      
-        if (do_unlock) wxMainMutex->Lock();
+            // fall through
 
-        p_internal->state = STATE_IDLE;
+        default:
+            // set the flag telling to the thread to stop and wait
+            p_internal->Cancel();
     }
-    
-    return status;
+
+    return NULL;
 }
 
-unsigned long wxThread::GetID() const
+wxThreadError wxThread::Kill()
 {
-    return p_internal->thread_id;
+    switch ( p_internal->GetState() )
+    {
+        case STATE_NEW:
+        case STATE_EXITED:
+            return wxTHREAD_NOT_RUNNING;
+
+        default:
+            if ( pthread_cancel(p_internal->GetId()) != 0 )
+            {
+                wxLogError(_("Failed to terminate a thread."));
+
+                return wxTHREAD_MISC_ERROR;
+            }
+
+            return wxTHREAD_NO_ERROR;
+    }
 }
 
 void wxThread::Exit(void *status)
 {
-    wxThread* ptr = this;
-
+    wxThread *ptr = this;
     THREAD_SEND_EXIT_MSG(ptr);
-    p_internal->state = STATE_EXITED;
+
+    OnExit();
+
+    p_internal->SetState(STATE_EXITED);
+
+    delete this;
+
     pthread_exit(status);
 }
 
-bool wxThread::TestDestroy()
+bool wxThread::TestDestroy() const
 {
-    if (p_internal->state == STATE_PAUSING) 
-    {
-        p_internal->state = STATE_PAUSED;
-        while (p_internal->state == STATE_PAUSED) 
-       {
-            pthread_testcancel();
-            usleep(1);
-        }
-    }
+    wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
 
-    // VZ: do I understand it correctly that it will terminate the thread all by
-    //     itself if it was cancelled?
-    pthread_testcancel();
-    
-    return FALSE;
+    return p_internal->WasCancelled();
 }
 
-bool wxThread::IsMain()
+wxThread::~wxThread()
 {
-    return (bool)pthread_equal(pthread_self(), p_mainid);
 }
 
+// -----------------------------------------------------------------------------
+// state tests
+// -----------------------------------------------------------------------------
+
 bool wxThread::IsRunning() const
 {
-    return (p_internal->state == STATE_RUNNING);
+    wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
+
+    return p_internal->GetState() == STATE_RUNNING;
 }
 
 bool wxThread::IsAlive() const
 {
-    return (p_internal->state == STATE_RUNNING) ||
-           (p_internal->state == STATE_PAUSING) ||
-           (p_internal->state == STATE_PAUSED);
-}
+    wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
 
-wxThread::wxThread()
-{
-    p_internal = new wxThreadInternal();
-}
-
-wxThread::~wxThread()
-{
-    Destroy();
-    Join();
-    delete p_internal;
-}
+    switch ( p_internal->GetState() )
+    {
+        case STATE_RUNNING:
+        case STATE_PAUSED:
+            return TRUE;
 
-/* The default callback just joins the thread and throws away the result. */
-void wxThread::OnExit()
-{
-    Join();
+        default:
+            return FALSE;
+    }
 }
 
 //--------------------------------------------------------------------
-// wxThreadModule 
+// wxThreadModule
 //--------------------------------------------------------------------
 
 class wxThreadModule : public wxModule
@@ -401,20 +571,29 @@ private:
 
 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
 
-bool wxThreadModule::OnInit() 
+bool wxThreadModule::OnInit()
 {
-    wxMainMutex = new wxMutex();
+    if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 )
+    {
+        wxLogError(_("Thread module initialization failed: "
+                     "failed to create pthread key."));
+
+        return FALSE;
+    }
+
+    gs_mutexGui = new wxMutex();
     wxThreadGuiInit();
-    p_mainid = (int)getpid();
-    wxMainMutex->Lock();
+    gs_pidMain = (int)getpid();
+    gs_mutexGui->Lock();
+
     return TRUE;
 }
 
 void wxThreadModule::OnExit()
 {
-    wxMainMutex->Unlock();
+    gs_mutexGui->Unlock();
     wxThreadGuiExit();
-    delete wxMainMutex;
-}
-
+    delete gs_mutexGui;
 
+    (void)pthread_key_delete(gs_keySelf);
+}