]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk1/threadpsx.cpp
image update
[wxWidgets.git] / src / gtk1 / threadpsx.cpp
index ce5396c6d7d052f0a376f09b98e372fce91eb375..f4fd5908db566e78ab7ed3acd809f9f4e6fc465b 100644 (file)
 // Modified by:
 // Created:     04/22/98
 // RCS-ID:      $Id$
-// Copyright:   (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998)
+// Copyright:   (c) Wolfram Gloger (1996, 1997)
+//                  Guilhem Lavaux (1998)
+//                  Robert Roebling (1999)
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
+
 #ifdef __GNUG__
 #pragma implementation "thread.h"
 #endif
 
 #include <stdio.h>
 #include <unistd.h>
-#include <sched.h>
 #include <pthread.h>
+#include <errno.h>
+#include "wx/thread.h"
+#include "wx/module.h"
+#include "wx/utils.h"
+#include "wx/log.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
 };
 
-/////////////////////////////////////////////////////////////////////////////
-// Static variables
-/////////////////////////////////////////////////////////////////////////////
-
-#include "thread.h"
+//--------------------------------------------------------------------
+// global data
+//--------------------------------------------------------------------
 
 static pthread_t p_mainid;
-wxMutex wxMainMutex; // controls access to all GUI functions
 
-/////////////////////////////////////////////////////////////////////////////
-// GUI thread manager
-/////////////////////////////////////////////////////////////////////////////
+wxMutex *wxMainMutex; /* controls access to all GUI functions */
+
+//--------------------------------------------------------------------
+// common GUI thread code
+//--------------------------------------------------------------------
+
 #include "threadgui.inc"
 
-/////////////////////////////////////////////////////////////////////////////
-// wxThread: Posix Thread implementation (Mutex)
-/////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------
+// wxMutex (Posix implementation)
+//--------------------------------------------------------------------
 
-class wxMutexInternal {
+class wxMutexInternal 
+{
 public:
   pthread_mutex_t p_mutex;
 };
 
 wxMutex::wxMutex()
 {
-  p_internal = new wxMutexInternal;
-  pthread_mutex_init(&(p_internal->p_mutex), NULL);
-  m_locked = false;
+    p_internal = new wxMutexInternal;
+    pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL );
+    m_locked = 0;
 }
 
 wxMutex::~wxMutex()
 {
-  if (m_locked)
-    pthread_mutex_unlock(&(p_internal->p_mutex));
-  pthread_mutex_destroy(&(p_internal->p_mutex));
-  delete p_internal;
+    if (m_locked > 0)
+        wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)\n", m_locked );
+
+    pthread_mutex_destroy( &(p_internal->p_mutex) );
+    delete p_internal;
 }
 
 wxMutexError wxMutex::Lock()
 {
-  int err;
-
-  err = pthread_mutex_lock(&(p_internal->p_mutex));
-  switch (err) {
-  case EDEADLK: return MUTEX_DEAD_LOCK;
-  }
-  m_locked++;
-  return MUTEX_NO_ERROR;
+    int err = pthread_mutex_lock( &(p_internal->p_mutex) );
+    if (err == EDEADLK)
+    {
+        return wxMUTEX_DEAD_LOCK;
+    }
+       
+    m_locked++;
+    
+    return wxMUTEX_NO_ERROR;
 }
 
 wxMutexError wxMutex::TryLock()
 {
-  int err;
-
-  if (m_locked)
-    return MUTEX_BUSY;
-  err = pthread_mutex_trylock(&(p_internal->p_mutex));
-  switch (err) {
-  case EBUSY: return MUTEX_BUSY;
-  }
-  m_locked++;
-  return MUTEX_NO_ERROR;
+    if (m_locked)
+    {
+        return wxMUTEX_BUSY;
+    }
+       
+    int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
+    switch (err) 
+    {
+        case EBUSY: return wxMUTEX_BUSY;
+    }
+    
+    m_locked++;
+    
+    return wxMUTEX_NO_ERROR;
 }
 
 wxMutexError wxMutex::Unlock()
 {
-  if (m_locked > 0) m_locked--;
-  pthread_mutex_unlock(&(p_internal->p_mutex));
-  return MUTEX_NO_ERROR;
+    if (m_locked > 0)
+    {
+        m_locked--;
+    }
+    else
+    {
+        return wxMUTEX_UNLOCKED;
+    }
+       
+    pthread_mutex_unlock( &(p_internal->p_mutex) );
+    
+    return wxMUTEX_NO_ERROR;
 }
 
-/////////////////////////////////////////////////////////////////////////////
-// wxThread: Posix Thread implementation (Condition)
-/////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------
+// wxCondition (Posix implementation)
+//--------------------------------------------------------------------
 
-class wxConditionInternal {
+class wxConditionInternal 
+{
 public:
   pthread_cond_t p_condition;
 };
 
 wxCondition::wxCondition()
 {
-  p_internal = new wxConditionInternal;
-  pthread_cond_init(&(p_internal->p_condition), NULL);
+    p_internal = new wxConditionInternal;
+    pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
 }
 
 wxCondition::~wxCondition()
 {
-  pthread_cond_destroy(&(p_internal->p_condition));
-  delete p_internal;
+    pthread_cond_destroy( &(p_internal->p_condition) );
+    
+    delete p_internal;
 }
 
 void wxCondition::Wait(wxMutex& mutex)
 {
-  pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex));
+    pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
 }
 
 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
 {
-  struct timespec tspec;
+    struct timespec tspec;
 
-  tspec.tv_sec = time(NULL)+sec;
-  tspec.tv_nsec = nsec;
-  return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
+    tspec.tv_sec = time(0L)+sec;
+    tspec.tv_nsec = nsec;
+    return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
 }
 
 void wxCondition::Signal()
 {
-  pthread_cond_signal(&(p_internal->p_condition));
+    pthread_cond_signal( &(p_internal->p_condition) );
 }
 
 void wxCondition::Broadcast()
 {
-  pthread_cond_broadcast(&(p_internal->p_condition));
+    pthread_cond_broadcast( &(p_internal->p_condition) );
 }
 
-/////////////////////////////////////////////////////////////////////////////
-// wxThread: Posix Thread implementation (Thread)
-/////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------
+// wxThread (Posix implementation)
+//--------------------------------------------------------------------
 
-class wxThreadInternal {
+class wxThreadInternal 
+{
 public:
   wxThreadInternal() { state = STATE_IDLE; }
   ~wxThreadInternal() {}
@@ -152,166 +184,237 @@ public:
   pthread_t thread_id;
   int state;
   int prio;
+  int defer_destroy;
 };
 
 void *wxThreadInternal::PthreadStart(void *ptr)
 {
-  wxThread *thread = (wxThread *)ptr;
+    wxThread *thread = (wxThread *)ptr;
 
-  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
-  void* status = thread->Entry();
-  thread->Exit(status);
+    /* Call the main entry */
+    pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, (int*) NULL );
+    void* status = thread->Entry();
 
-  return NULL;
+    thread->Exit(status);
+
+    return NULL;
 }
 
 wxThreadError wxThread::Create()
 {
-  pthread_attr_t a;
-  int min_prio, max_prio, p;
-  struct sched_param sp;
+    pthread_attr_t a;
+    int min_prio, max_prio, p;
+    struct sched_param sp;
 
-  if (p_internal->state != STATE_IDLE)
-    return THREAD_RUNNING;
+    if (p_internal->state != STATE_IDLE)
+        return wxTHREAD_RUNNING;
 
-  // Change thread priority
-  pthread_attr_init(&a);
-  pthread_attr_getschedpolicy(&a, &p);
+    /* Change thread priority */
+    pthread_attr_init(&a);
+    pthread_attr_getschedpolicy(&a, &p);
 
-  min_prio = sched_get_priority_min(p);
-  max_prio = sched_get_priority_max(p);
+    min_prio = sched_get_priority_min(p);
+    max_prio = sched_get_priority_max(p);
 
-  pthread_attr_getschedparam(&a, &sp);
-  sp.sched_priority = min_prio +
+    pthread_attr_getschedparam(&a, &sp);
+    sp.sched_priority = min_prio +
                (p_internal->prio*(max_prio-min_prio))/100;
-  pthread_attr_setschedparam(&a, &sp);
-
-  // 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_setschedparam(&a, &sp);
+
+    // 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);
-    return THREAD_NO_RESOURCE;
-  }
-  pthread_attr_destroy(&a);
-  return THREAD_NO_ERROR;
+
+    return wxTHREAD_NO_ERROR;
 }
 
 void wxThread::SetPriority(int prio)
 {
-  if (p_internal->state == STATE_RUNNING)
-    return;
-
-  if (prio > 100)
-    prio = 100;
-  if (prio < 0)
-    prio = 0;
-  p_internal->prio = prio;
+    if (p_internal->state == STATE_RUNNING)
+        return;
+
+    if (prio > 100) prio = 100;
+       
+    if (prio < 0) prio = 0;
+    
+    p_internal->prio = prio;
 }
 
 int wxThread::GetPriority() const
 {
-  return p_internal->prio;
+    return p_internal->prio;
 }
 
 void wxThread::DeferDestroy(bool on)
 {
-  if (on)
-    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
-  else
-    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+    if (on)
+        pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, (int*) NULL);
+    else
+        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, (int*) NULL);
 }
 
 wxThreadError wxThread::Destroy()
 {
-  int res = 0;
+    int res = 0;
+
+    if (p_internal->state == STATE_RUNNING) 
+    {
+        res = pthread_cancel(p_internal->thread_id);
+        if (res == 0)
+           p_internal->state = STATE_CANCELED;
+    }
+
+    return wxTHREAD_NO_ERROR;
+}
+
+wxThreadError wxThread::Pause()
+{
+    if (p_internal->state != STATE_RUNNING)
+        return wxTHREAD_NOT_RUNNING;
+
+    if (!p_internal->defer_destroy)
+        return wxTHREAD_MISC_ERROR;
+
+    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;
 
-  if (p_internal->state == STATE_RUNNING) {
-    res = pthread_cancel(p_internal->thread_id);
-    if (res == 0)
-      p_internal->state = STATE_CANCELED;
-  }
-  return THREAD_NO_ERROR;
+    return wxTHREAD_NO_ERROR;
 }
 
 void *wxThread::Join()
 {
-  void* status = 0;
+    void* status = 0;
+
+    if (p_internal->state != STATE_IDLE) 
+    {
+        bool do_unlock = wxThread::IsMain();
 
-  if (p_internal->state != STATE_IDLE) {
-    bool do_unlock = wxThread::IsMain();
+        while (p_internal->state == STATE_RUNNING)
+            wxYield();
 
-    while (p_internal->state == STATE_RUNNING)
-      wxYield();
+        if (do_unlock) wxMainMutex->Unlock();
+      
+        pthread_join(p_internal->thread_id, &status);
+      
+        if (do_unlock) wxMainMutex->Lock();
 
-    if (do_unlock)
-      wxMainMutex.Unlock();
-    pthread_join(p_internal->thread_id, &status);
-    if (do_unlock)
-      wxMainMutex.Lock();
-    p_internal->state = STATE_IDLE;
-  }
-  return status;
+        p_internal->state = STATE_IDLE;
+    }
+    
+    return status;
 }
 
 unsigned long wxThread::GetID() const
 {
-  return (unsigned long)p_internal->thread_id;
+    return p_internal->thread_id;
 }
 
 void wxThread::Exit(void *status)
 {
-  wxThread* ptr = this;
+    wxThread* ptr = this;
 
-  THREAD_SEND_EXIT_MSG(ptr);
-  p_internal->state = STATE_EXITED;
-  pthread_exit(status);
+    THREAD_SEND_EXIT_MSG(ptr);
+    p_internal->state = STATE_EXITED;
+    pthread_exit(status);
 }
 
-void wxThread::TestDestroy()
+bool wxThread::TestDestroy()
 {
-  pthread_testcancel();
+    if (p_internal->state == STATE_PAUSING) 
+    {
+        p_internal->state = STATE_PAUSED;
+        while (p_internal->state == STATE_PAUSED) 
+       {
+            pthread_testcancel();
+            usleep(1);
+        }
+    }
+
+    // VZ: do I understand it correctly that it will terminate the thread all by
+    //     itself if it was cancelled?
+    pthread_testcancel();
+    
+    return FALSE;
 }
 
-bool wxThread::IsMain() const
+bool wxThread::IsMain()
 {
-  return (bool)pthread_equal(pthread_self(), p_mainid);
+    return (bool)pthread_equal(pthread_self(), p_mainid);
+}
+
+bool wxThread::IsRunning() const
+{
+    return (p_internal->state == STATE_RUNNING);
+}
+
+bool wxThread::IsAlive() const
+{
+    return (p_internal->state == STATE_RUNNING) ||
+           (p_internal->state == STATE_PAUSING) ||
+           (p_internal->state == STATE_PAUSED);
 }
 
 wxThread::wxThread()
 {
-  p_internal = new wxThreadInternal();
+    p_internal = new wxThreadInternal();
 }
 
 wxThread::~wxThread()
 {
-  Destroy();
-  Join();
-  delete p_internal;
+    Destroy();
+    Join();
+    delete p_internal;
 }
 
-// The default callback just joins the thread and throws away the result.
+/* The default callback just joins the thread and throws away the result. */
 void wxThread::OnExit()
 {
+    Join();
 }
 
-// Automatic initialization
-class wxThreadModule : public wxModule {
-  DECLARE_DYNAMIC_CLASS(wxThreadModule)
+//--------------------------------------------------------------------
+// wxThreadModule 
+//--------------------------------------------------------------------
+
+class wxThreadModule : public wxModule
+{
 public:
-  virtual bool OnInit() {
-    wxThreadGuiInit();
-    p_mainid = pthread_self();
-    wxMainMutex.Lock();
+    virtual bool OnInit();
+    virtual void OnExit();
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxThreadModule)
+};
 
+IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
+
+bool wxThreadModule::OnInit() 
+{
+    wxMainMutex = new wxMutex();
+    wxThreadGuiInit();
+    p_mainid = (int)getpid();
+    wxMainMutex->Lock();
     return TRUE;
-  }
+}
 
-  virtual void OnExit() {
-    wxMainMutex.Unlock();
+void wxThreadModule::OnExit()
+{
+    wxMainMutex->Unlock();
     wxThreadGuiExit();
-  }
-};
+    delete wxMainMutex;
+}
+
 
-IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)