/////////////////////////////////////////////////////////////////////////////
#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
// wxMutex (Posix implementation)
//--------------------------------------------------------------------
-class wxMutexInternal
+class wxMutexInternal
{
public:
pthread_mutex_t p_mutex;
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;
{
return wxMUTEX_DEAD_LOCK;
}
-
+
m_locked++;
-
+
return wxMUTEX_NO_ERROR;
}
{
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;
}
{
return wxMUTEX_UNLOCKED;
}
-
+
pthread_mutex_unlock( &(p_internal->p_mutex) );
-
+
return wxMUTEX_NO_ERROR;
}
// wxCondition (Posix implementation)
//--------------------------------------------------------------------
-class wxConditionInternal
+class wxConditionInternal
{
public:
pthread_cond_t p_condition;
wxCondition::~wxCondition()
{
pthread_cond_destroy( &(p_internal->p_condition) );
-
+
delete p_internal;
}
// 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
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);
+}
/////////////////////////////////////////////////////////////////////////////
#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
// wxMutex (Posix implementation)
//--------------------------------------------------------------------
-class wxMutexInternal
+class wxMutexInternal
{
public:
pthread_mutex_t p_mutex;
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;
{
return wxMUTEX_DEAD_LOCK;
}
-
+
m_locked++;
-
+
return wxMUTEX_NO_ERROR;
}
{
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;
}
{
return wxMUTEX_UNLOCKED;
}
-
+
pthread_mutex_unlock( &(p_internal->p_mutex) );
-
+
return wxMUTEX_NO_ERROR;
}
// wxCondition (Posix implementation)
//--------------------------------------------------------------------
-class wxConditionInternal
+class wxConditionInternal
{
public:
pthread_cond_t p_condition;
wxCondition::~wxCondition()
{
pthread_cond_destroy( &(p_internal->p_condition) );
-
+
delete p_internal;
}
// 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
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);
+}