+// ----------------------------------------------------------------------------
+// thread startup and exit functions
+// ----------------------------------------------------------------------------
+
+void *wxPthreadStart(void *ptr)
+{
+ return wxThreadInternal::PthreadStart((wxThread *)ptr);
+}
+
+void *wxThreadInternal::PthreadStart(wxThread *thread)
+{
+ wxThreadInternal *pthread = thread->m_internal;
+
+ wxLogTrace(TRACE_THREADS, wxT("Thread %p started."), THR_ID(pthread));
+
+ // associate the thread pointer with the newly created thread so that
+ // wxThread::This() will work
+ int rc = pthread_setspecific(gs_keySelf, thread);
+ if ( rc != 0 )
+ {
+ wxLogSysError(rc, _("Cannot start thread: error writing TLS."));
+
+ return (void *)-1;
+ }
+
+ // have to declare this before pthread_cleanup_push() which defines a
+ // block!
+ bool dontRunAtAll;
+
+#ifdef wxHAVE_PTHREAD_CLEANUP
+ // install the cleanup handler which will be called if the thread is
+ // cancelled
+ pthread_cleanup_push(wxPthreadCleanup, thread);
+#endif // wxHAVE_PTHREAD_CLEANUP
+
+ // wait for the semaphore to be posted from Run()
+ pthread->m_semRun.Wait();
+
+ // test whether we should run the run at all - may be it was deleted
+ // before it started to Run()?
+ {
+ wxCriticalSectionLocker lock(thread->m_critsect);
+
+ dontRunAtAll = pthread->GetState() == STATE_NEW &&
+ pthread->WasCancelled();
+ }
+
+ if ( !dontRunAtAll )
+ {
+ // call the main entry
+ wxLogTrace(TRACE_THREADS,
+ wxT("Thread %p about to enter its Entry()."),
+ THR_ID(pthread));
+
+ wxTRY
+ {
+ pthread->m_exitcode = thread->Entry();
+
+ wxLogTrace(TRACE_THREADS,
+ wxT("Thread %p Entry() returned %lu."),
+ THR_ID(pthread), wxPtrToUInt(pthread->m_exitcode));
+ }
+#ifdef HAVE_ABI_FORCEDUNWIND
+ // When using common C++ ABI under Linux we must always rethrow this
+ // special exception used to unwind the stack when the thread was
+ // cancelled, otherwise the thread library would simply terminate the
+ // program, see http://udrepper.livejournal.com/21541.html
+ catch ( abi::__forced_unwind& )
+ {
+ wxCriticalSectionLocker lock(thread->m_critsect);
+ pthread->SetState(STATE_EXITED);
+ throw;
+ }
+#endif // HAVE_ABI_FORCEDUNWIND
+ wxCATCH_ALL( wxTheApp->OnUnhandledException(); )
+
+ {
+ wxCriticalSectionLocker lock(thread->m_critsect);
+
+ // change the state of the thread to "exited" so that
+ // wxPthreadCleanup handler won't do anything from now (if it's
+ // called before we do pthread_cleanup_pop below)
+ pthread->SetState(STATE_EXITED);
+ }
+ }
+
+ // NB: pthread_cleanup_push/pop() are macros and pop contains the matching
+ // '}' for the '{' in push, so they must be used in the same block!
+#ifdef wxHAVE_PTHREAD_CLEANUP
+ #ifdef __DECCXX
+ // under Tru64 we get a warning from macro expansion
+ #pragma message save
+ #pragma message disable(declbutnotref)
+ #endif
+
+ // remove the cleanup handler without executing it
+ pthread_cleanup_pop(FALSE);
+
+ #ifdef __DECCXX
+ #pragma message restore
+ #endif
+#endif // wxHAVE_PTHREAD_CLEANUP
+
+ if ( dontRunAtAll )
+ {
+ // FIXME: deleting a possibly joinable thread here???
+ delete thread;
+
+ return EXITCODE_CANCELLED;
+ }
+ else
+ {
+ // terminate the thread
+ thread->Exit(pthread->m_exitcode);
+
+ wxFAIL_MSG(wxT("wxThread::Exit() can't return."));
+
+ return NULL;
+ }
+}
+
+#ifdef wxHAVE_PTHREAD_CLEANUP
+
+// this handler is called when the thread is cancelled
+extern "C" void wxPthreadCleanup(void *ptr)
+{
+ wxThreadInternal::Cleanup((wxThread *)ptr);
+}
+
+void wxThreadInternal::Cleanup(wxThread *thread)
+{
+ if (pthread_getspecific(gs_keySelf) == 0) return;
+ {
+ wxCriticalSectionLocker lock(thread->m_critsect);
+ if ( thread->m_internal->GetState() == STATE_EXITED )
+ {
+ // thread is already considered as finished.
+ return;
+ }
+ }
+
+ // exit the thread gracefully
+ thread->Exit(EXITCODE_CANCELLED);
+}
+
+#endif // wxHAVE_PTHREAD_CLEANUP
+
+// ----------------------------------------------------------------------------
+// wxThreadInternal
+// ----------------------------------------------------------------------------
+
+wxThreadInternal::wxThreadInternal()
+{
+ m_state = STATE_NEW;
+ m_created = false;
+ m_cancelled = false;
+ m_prio = wxPRIORITY_DEFAULT;
+ m_threadId = 0;
+ m_exitcode = 0;
+
+ // set to true only when the thread starts waiting on m_semSuspend
+ m_isPaused = false;
+
+ // defaults for joinable threads
+ m_shouldBeJoined = true;
+ m_isDetached = false;
+}
+
+wxThreadInternal::~wxThreadInternal()
+{
+}
+
+#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
+ #define WXUNUSED_STACKSIZE(identifier) identifier
+#else
+ #define WXUNUSED_STACKSIZE(identifier) WXUNUSED(identifier)
+#endif
+
+wxThreadError wxThreadInternal::Create(wxThread *thread,
+ unsigned int WXUNUSED_STACKSIZE(stackSize))
+{
+ if ( GetState() != STATE_NEW )
+ {
+ // don't recreate thread
+ 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_PTHREAD_ATTR_SETSTACKSIZE
+ if (stackSize)
+ pthread_attr_setstacksize(&attr, stackSize);
+#endif