X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/34f8c26e93e775036baf1bd9e50d08f0d38f6232..9d2f3c71d83c52fc4db6c8041de533562816b1d6:/src/unix/threadpsx.cpp diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp index 81a93b2ac5..475d0b72b8 100644 --- a/src/unix/threadpsx.cpp +++ b/src/unix/threadpsx.cpp @@ -24,12 +24,13 @@ #pragma implementation "thread.h" #endif -#include "wx/thread.h" +// With simple makefiles, we must ignore the file body if not using +// threads. +#include "wx/setup.h" -#if !wxUSE_THREADS - #error This file needs wxUSE_THREADS -#endif +#if wxUSE_THREADS +#include "wx/thread.h" #include "wx/module.h" #include "wx/utils.h" #include "wx/log.h" @@ -42,7 +43,7 @@ #include #include -#ifdef HAVE_SCHED_H +#if HAVE_SCHED_H #include #endif @@ -50,15 +51,19 @@ // constants // ---------------------------------------------------------------------------- -enum thread_state +// the possible states of the thread and transitions from them +enum wxThreadState { STATE_NEW, // didn't start execution yet (=> RUNNING) - STATE_RUNNING, - STATE_PAUSED, - STATE_CANCELED, - STATE_EXITED + STATE_RUNNING, // running (=> PAUSED or EXITED) + STATE_PAUSED, // suspended (=> RUNNING or EXITED) + STATE_EXITED // thread doesn't exist any more }; +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + WX_DEFINE_ARRAY(wxThread *, wxArrayThread); // ----------------------------------------------------------------------------- @@ -224,7 +229,7 @@ public: // start the thread wxThreadError Run(); // ask the thread to terminate - void Cancel(); + void Wait(); // wake up threads waiting for our termination void SignalExit(); // go to sleep until Resume() is called @@ -237,19 +242,19 @@ public: 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; } + wxThreadState GetState() const { return m_state; } + void SetState(wxThreadState state) { m_state = state; } // id - pthread_t GetId() const { return thread_id; } + pthread_t GetId() const { return m_threadId; } + pthread_t *GetIdPtr() { return &m_threadId; } // "cancelled" flag + void SetCancelFlag() { m_cancelled = TRUE; } 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 + pthread_t m_threadId; // id of the thread + wxThreadState m_state; // see wxThreadState enum + int m_prio; // in wxWindows units: from 0 to 100 // set when the thread should terminate bool m_cancelled; @@ -257,7 +262,7 @@ private: // this (mutex, cond) pair is used to synchronize the main thread and this // thread in several situations: // 1. The thread function blocks until condition is signaled by Run() when - // it's initially created - this allows create thread in "suspended" + // it's initially created - this allows thread creation in "suspended" // state // 2. The Delete() function blocks until the condition is signaled when the // thread exits. @@ -279,9 +284,10 @@ void *wxThreadInternal::PthreadStart(void *ptr) wxThread *thread = (wxThread *)ptr; wxThreadInternal *pthread = thread->p_internal; - if ( pthread_setspecific(gs_keySelf, thread) != 0 ) + int rc = pthread_setspecific(gs_keySelf, thread); + if ( rc != 0 ) { - wxLogError(_("Can not start thread: error writing TLS.")); + wxLogSysError(rc, _("Cannot start thread: error writing TLS")); return (void *)-1; } @@ -345,17 +351,15 @@ wxThreadError wxThreadInternal::Run() // starts executing and the mutex is still locked } -void wxThreadInternal::Cancel() +void wxThreadInternal::Wait() { + wxCHECK_RET( WasCancelled(), "thread should have been cancelled first" ); + // 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(); - // nobody ever writes this variable so it's safe to not use any - // synchronization here - m_cancelled = TRUE; - // entering Wait() releases the mutex thus allowing SignalExit() to acquire // it and to signal us its termination m_cond.Wait(m_mutex); @@ -384,9 +388,17 @@ void wxThreadInternal::SignalExit() void wxThreadInternal::Pause() { + // the state is set from the thread which pauses us first, this function + // is called later so the state should have been already set wxCHECK_RET( m_state == STATE_PAUSED, "thread must first be paused with wxThread::Pause()." ); + // don't pause the thread which is being terminated - this would lead to + // deadlock if the thread is paused after Delete() had called Resume() but + // before it had time to call Wait() + if ( WasCancelled() ) + return; + // wait until the condition is signaled from Resume() m_condSuspend.Wait(m_mutexSuspend); } @@ -441,26 +453,28 @@ wxThread::wxThread() wxThreadError wxThread::Create() { - if (p_internal->GetState() != STATE_NEW) + // Maybe we could think about recreate the thread once it has exited. + if (p_internal->GetState() != STATE_NEW && + p_internal->GetState() != STATE_EXITED) return wxTHREAD_RUNNING; // set up the thread attribute: right now, we only set thread priority pthread_attr_t attr; pthread_attr_init(&attr); +#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS int prio; if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 ) { - wxLogError(_("Can not retrieve thread scheduling policy.")); + wxLogError(_("Cannot retrieve thread scheduling policy.")); } -#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS 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."), + wxLogError(_("Cannot get priority range for scheduling policy %d."), prio); } else @@ -473,8 +487,13 @@ wxThreadError wxThread::Create() } #endif // HAVE_THREAD_PRIORITY_FUNCTIONS +#ifdef HAVE_PTHREAD_ATTR_SETSCOPE + // this will make the threads created by this process really concurrent + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); +#endif // HAVE_PTHREAD_ATTR_SETSCOPE + // create the new OS thread object - int rc = pthread_create(&p_internal->thread_id, &attr, + int rc = pthread_create(p_internal->GetIdPtr(), &attr, wxThreadInternal::PthreadStart, (void *)this); pthread_attr_destroy(&attr); @@ -542,7 +561,7 @@ unsigned int wxThread::GetPriority() const unsigned long wxThread::GetID() const { - return (unsigned long)p_internal->thread_id; + return (unsigned long)p_internal->GetId(); } // ----------------------------------------------------------------------------- @@ -590,9 +609,12 @@ wxThreadError wxThread::Resume() wxThread::ExitCode wxThread::Delete() { m_critsect.Enter(); - thread_state state = p_internal->GetState(); + wxThreadState state = p_internal->GetState(); m_critsect.Leave(); + // ask the thread to stop + p_internal->SetCancelFlag(); + switch ( state ) { case STATE_NEW: @@ -607,8 +629,8 @@ wxThread::ExitCode wxThread::Delete() // fall through default: - // set the flag telling to the thread to stop and wait - p_internal->Cancel(); + // wait until the thread stops + p_internal->Wait(); } return NULL; @@ -648,14 +670,15 @@ void wxThread::Exit(void *status) p_internal->SetState(STATE_EXITED); // delete both C++ thread object and terminate the OS thread object - delete this; + // GL: This is very ugly and buggy ... +// delete this; pthread_exit(status); } // also test whether we were paused bool wxThread::TestDestroy() { - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); + wxCriticalSectionLocker lock(m_critsect); if ( p_internal->GetState() == STATE_PAUSED ) { @@ -722,10 +745,11 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) bool wxThreadModule::OnInit() { - if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 ) + int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */); + if ( rc != 0 ) { - wxLogError(_("Thread module initialization failed: " - "failed to create pthread key.")); + wxLogSysError(rc, _("Thread module initialization failed: " + "failed to create thread key")); return FALSE; } @@ -778,3 +802,6 @@ void wxMutexGuiLeave() { gs_mutexGui->Unlock(); } + +#endif + // wxUSE_THREADS