///////////////////////////////////////////////////////////////////////////// // Name: threadpsx.cpp // Purpose: wxThread (Posix) Implementation // Author: Original from Wolfram Gloger/Guilhem Lavaux // Modified by: // Created: 04/22/98 // RCS-ID: $Id$ // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998) // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "thread.h" #endif #include #include #include #include #include "wx/thread.h" #include "wx/module.h" #include "wx/utils.h" #include "wx/log.h" enum thread_state { STATE_IDLE = 0, STATE_RUNNING, STATE_PAUSING, STATE_PAUSED, STATE_CANCELED, STATE_EXITED }; ///////////////////////////////////////////////////////////////////////////// // Static variables ///////////////////////////////////////////////////////////////////////////// static pthread_t p_mainid; static wxMutex p_list_mutex; static wxList p_threads_list; wxMutex *wxMainMutex; // controls access to all GUI functions ///////////////////////////////////////////////////////////////////////////// // GUI thread manager ///////////////////////////////////////////////////////////////////////////// #include "threadgui.inc" ///////////////////////////////////////////////////////////////////////////// // wxThread: Posix Thread implementation (Mutex) ///////////////////////////////////////////////////////////////////////////// class wxMutexInternal { public: pthread_mutex_t p_mutex; }; wxMutex::wxMutex() { p_internal = new wxMutexInternal; pthread_mutex_init(&(p_internal->p_mutex), NULL); m_locked = 0; } wxMutex::~wxMutex() { 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)); if (err == EDEADLK) return MUTEX_DEAD_LOCK; m_locked++; return MUTEX_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; } wxMutexError wxMutex::Unlock() { if (m_locked > 0) m_locked--; else return MUTEX_UNLOCKED; pthread_mutex_unlock(&(p_internal->p_mutex)); return MUTEX_NO_ERROR; } ///////////////////////////////////////////////////////////////////////////// // wxThread: Posix Thread implementation (Condition) ///////////////////////////////////////////////////////////////////////////// class wxConditionInternal { public: pthread_cond_t p_condition; }; wxCondition::wxCondition() { p_internal = new wxConditionInternal; pthread_cond_init(&(p_internal->p_condition), NULL); } wxCondition::~wxCondition() { 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)); } bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec) { 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); } void wxCondition::Signal() { pthread_cond_signal(&(p_internal->p_condition)); } void wxCondition::Broadcast() { pthread_cond_broadcast(&(p_internal->p_condition)); } ///////////////////////////////////////////////////////////////////////////// // wxThread: Posix Thread implementation (Thread) ///////////////////////////////////////////////////////////////////////////// class wxThreadInternal { public: wxThreadInternal() { state = STATE_IDLE; } ~wxThreadInternal() {} static void *PthreadStart(void *ptr); pthread_t thread_id; int state; int prio; int defer_destroy; int id; }; void *wxThreadInternal::PthreadStart(void *ptr) { wxThread *thread = (wxThread *)ptr; // Add the current thread to the list p_list_mutex.Lock(); thread->p_internal->id = p_threads_list.Number(); p_threads_list.Append((wxObject *)thread); p_list_mutex.Unlock(); // Call the main entry pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); void* status = thread->Entry(); thread->Exit(status); return NULL; } wxThreadError wxThread::Create() { pthread_attr_t a; int min_prio, max_prio, p; struct sched_param sp; if (p_internal->state != STATE_IDLE) return THREAD_RUNNING; // 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); 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_destroy(&a); return THREAD_NO_RESOURCE; } pthread_attr_destroy(&a); return THREAD_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; } int wxThread::GetPriority() const { return p_internal->prio; } void wxThread::DeferDestroy(bool on) { if (on) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); else pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); } wxThreadError wxThread::Destroy() { 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 THREAD_NO_ERROR; } wxThreadError wxThread::Pause() { if (p_internal->state != STATE_RUNNING) return THREAD_NOT_RUNNING; if (!p_internal->defer_destroy) return THREAD_MISC_ERROR; p_internal->state = STATE_PAUSING; return THREAD_NO_ERROR; } wxThreadError wxThread::Resume() { if (p_internal->state == STATE_PAUSING || p_internal->state == STATE_PAUSED) p_internal->state = STATE_RUNNING; return THREAD_NO_ERROR; } void *wxThread::Join() { void* status = 0; if (p_internal->state != STATE_IDLE) { bool do_unlock = wxThread::IsMain(); while (p_internal->state == STATE_RUNNING) wxYield(); if (do_unlock) wxMainMutex->Unlock(); pthread_join(p_internal->thread_id, &status); if (do_unlock) wxMainMutex->Lock(); p_list_mutex.Lock(); delete p_threads_list.Nth(p_internal->id); p_list_mutex.Unlock(); p_internal->state = STATE_IDLE; } return status; } unsigned long wxThread::GetID() const { return p_internal->id; } wxThread *wxThread::GetThreadFromID(unsigned long id) { wxNode *node = p_threads_list.Nth(id); if (!node) return NULL; return (wxThread *)node->Data(); } void wxThread::Exit(void *status) { wxThread* ptr = this; THREAD_SEND_EXIT_MSG(ptr); p_internal->state = STATE_EXITED; pthread_exit(status); } void wxThread::TestDestroy() { if (p_internal->state == STATE_PAUSING) { p_internal->state = STATE_PAUSED; while (p_internal->state == STATE_PAUSED) { pthread_testcancel(); usleep(1); } } pthread_testcancel(); } bool wxThread::IsMain() { 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(); } wxThread::~wxThread() { Destroy(); Join(); delete p_internal; } // 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) public: virtual bool OnInit() { wxMainMutex = new wxMutex(); wxThreadGuiInit(); p_mainid = pthread_self(); // p_threads_list = wxList(wxKEY_INTEGER); wxMainMutex->Lock(); return TRUE; } virtual void OnExit() { wxMainMutex->Unlock(); wxThreadGuiExit(); delete wxMainMutex; } }; IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)