+ wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ;
+ g_numberOfThreads--;
+
+#ifdef __WXDEBUG__
+ m_critsect.Enter();
+
+ // check that the thread either exited or couldn't be created
+ if ( m_internal->GetState() != STATE_EXITED &&
+ m_internal->GetState() != STATE_NEW )
+ {
+ wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId());
+ }
+
+ m_critsect.Leave();
+#endif // __WXDEBUG__
+
+ wxDELETE( m_internal ) ;
+}
+
+
+wxThreadError wxThread::Create(unsigned int stackSize)
+{
+ wxCriticalSectionLocker lock(m_critsect);
+
+ if ( m_isDetached )
+ {
+ m_internal->Detach() ;
+ }
+ if ( m_internal->Create(this, stackSize) == false )
+ {
+ m_internal->SetState(STATE_EXITED);
+ return wxTHREAD_NO_RESOURCE;
+ }
+
+ return wxTHREAD_NO_ERROR;
+}
+
+wxThreadError wxThread::Run()
+{
+ wxCriticalSectionLocker lock(m_critsect);
+
+ wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
+ wxT("must call wxThread::Create() first") );
+
+ return m_internal->Run();
+}
+
+// -----------------------------------------------------------------------------
+// pause/resume
+// -----------------------------------------------------------------------------
+
+wxThreadError wxThread::Pause()
+{
+ wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
+ _T("a thread can't pause itself") );
+
+ wxCriticalSectionLocker lock(m_critsect);
+
+ if ( m_internal->GetState() != STATE_RUNNING )
+ {
+ wxLogDebug(wxT("Can't pause thread which is not running."));
+
+ return wxTHREAD_NOT_RUNNING;
+ }
+
+ // just set a flag, the thread will be really paused only during the next
+ // call to TestDestroy()
+ m_internal->SetState(STATE_PAUSED);
+
+ return wxTHREAD_NO_ERROR;
+}
+
+wxThreadError wxThread::Resume()
+{
+ wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
+ _T("a thread can't resume itself") );
+
+ wxCriticalSectionLocker lock(m_critsect);
+
+ wxThreadState state = m_internal->GetState();
+
+ switch ( state )
+ {
+ case STATE_PAUSED:
+ m_internal->Resume();
+ return wxTHREAD_NO_ERROR;
+ case STATE_EXITED:
+ return wxTHREAD_NO_ERROR;
+
+ default:
+ wxLogDebug(_T("Attempt to resume a thread which is not paused."));
+
+ return wxTHREAD_MISC_ERROR;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// exiting thread
+// -----------------------------------------------------------------------------
+
+wxThread::ExitCode wxThread::Wait()
+{
+ wxCHECK_MSG( This() != this, (ExitCode)-1,
+ _T("a thread can't wait for itself") );
+
+ wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
+ _T("can't wait for detached thread") );
+
+ m_internal->Wait();
+
+ return m_internal->GetExitCode();
+}
+
+wxThreadError wxThread::Delete(ExitCode *rc)
+{
+ wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
+ _T("a thread can't delete itself") );
+
+ bool isDetached = m_isDetached;
+
+ m_critsect.Enter();
+ wxThreadState state = m_internal->GetState();
+
+ // ask the thread to stop
+ m_internal->SetCancelFlag();
+
+ m_critsect.Leave();
+
+ switch ( state )
+ {
+ case STATE_NEW:
+ // we need to wake up the thread so that PthreadStart() will
+ // terminate - right now it's blocking on run semaphore in
+ // PthreadStart()
+ m_internal->SignalRun();
+
+ // fall through
+
+ case STATE_EXITED:
+ // nothing to do
+ break;
+
+ case STATE_PAUSED:
+ // resume the thread first
+ m_internal->Resume();
+
+ // fall through
+
+ default:
+ if ( !isDetached )
+ {
+ // wait until the thread stops
+ m_internal->Wait();
+
+ if ( rc )
+ {
+ // return the exit code of the thread
+ *rc = m_internal->GetExitCode();
+ }
+ }
+ }
+
+ return wxTHREAD_NO_ERROR;
+}
+
+wxThreadError wxThread::Kill()
+{
+ wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
+ _T("a thread can't kill itself") );
+
+ switch ( m_internal->GetState() )
+ {
+ case STATE_NEW:
+ case STATE_EXITED:
+ return wxTHREAD_NOT_RUNNING;
+
+ case STATE_PAUSED:
+ // resume the thread first
+ Resume();
+
+ // fall through
+
+ default:
+ OSStatus err = MPTerminateTask( m_internal->GetId() , -1 ) ;
+ if ( err )
+ {
+ wxLogError(_("Failed to terminate a thread."));
+
+ return wxTHREAD_MISC_ERROR;
+ }
+
+ if ( m_isDetached )
+ {
+ delete this ;
+ }
+ else
+ {
+ // this should be retrieved by Wait actually
+ m_internal->SetExitCode((void*)-1);
+ }
+
+ return wxTHREAD_NO_ERROR;
+ }
+}
+
+void wxThread::Exit(ExitCode status)
+{
+ wxASSERT_MSG( This() == this,
+ _T("wxThread::Exit() can only be called in the context of the same thread") );
+
+ // don't enter m_critsect before calling OnExit() because the user code
+ // might deadlock if, for example, it signals a condition in OnExit() (a
+ // common case) while the main thread calls any of functions entering
+ // m_critsect on us (almost all of them do)
+ OnExit();
+
+ MPTaskID threadid = m_internal->GetId() ;
+
+ if ( IsDetached() )
+ {
+ delete this;
+ }
+ else // joinable
+ {
+ // update the status of the joinable thread
+ wxCriticalSectionLocker lock(m_critsect);
+ m_internal->SetState(STATE_EXITED);
+ }
+ MPTerminateTask( threadid , (long) status) ;
+}
+
+// also test whether we were paused
+bool wxThread::TestDestroy()
+{
+ wxASSERT_MSG( This() == this,
+ _T("wxThread::TestDestroy() can only be called in the context of the same thread") );
+
+ m_critsect.Enter();
+
+ if ( m_internal->GetState() == STATE_PAUSED )
+ {
+ m_internal->SetReallyPaused(TRUE);
+
+ // leave the crit section or the other threads will stop too if they
+ // try to call any of (seemingly harmless) IsXXX() functions while we
+ // sleep
+ m_critsect.Leave();
+
+ m_internal->Pause();
+ }
+ else
+ {
+ // thread wasn't requested to pause, nothing to do
+ m_critsect.Leave();
+ }
+
+ return m_internal->WasCancelled();
+}
+
+// -----------------------------------------------------------------------------
+// priority setting
+// -----------------------------------------------------------------------------
+
+void wxThread::SetPriority(unsigned int prio)
+{
+ wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
+ ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
+ wxT("invalid thread priority") );
+
+ wxCriticalSectionLocker lock(m_critsect);
+
+ switch ( m_internal->GetState() )
+ {
+ case STATE_RUNNING:
+ case STATE_PAUSED:
+ case STATE_NEW:
+ // thread not yet started, priority will be set when it is
+ m_internal->SetPriority(prio);
+ break;
+
+ case STATE_EXITED:
+ default:
+ wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
+ }
+}
+
+unsigned int wxThread::GetPriority() const
+{
+ wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
+
+ return m_internal->GetPriority();
+}
+
+unsigned long wxThread::GetId() const
+{
+ wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
+
+ return (unsigned long)m_internal->GetId();