+void wxThreadInternal::Wait()
+{
+ wxCHECK_RET( !m_isDetached, wxT("can't wait for a detached thread") );
+
+ // 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() )
+ {
+#ifdef __WXOSX__
+ // give the thread we're waiting for chance to do the GUI call
+ // it might be in, we don't do this conditionally as the to be waited on
+ // thread might have to acquire the mutex later but before terminating
+ if ( wxGuiOwnedByMainThread() )
+ wxMutexGuiLeave();
+#else
+ wxMutexGuiLeave();
+#endif
+ }
+
+ wxLogTrace(TRACE_THREADS,
+ wxT("Starting to wait for thread %p to exit."),
+ THR_ID(this));
+
+ // to avoid memory leaks we should call pthread_join(), but it must only be
+ // done once so use a critical section to serialize the code below
+ {
+ wxCriticalSectionLocker lock(m_csJoinFlag);
+
+ if ( m_shouldBeJoined )
+ {
+ // FIXME shouldn't we set cancellation type to DISABLED here? If
+ // we're cancelled inside pthread_join(), things will almost
+ // certainly break - but if we disable the cancellation, we
+ // might deadlock
+ if ( pthread_join(GetId(), &m_exitcode) != 0 )
+ {
+ // this is a serious problem, so use wxLogError and not
+ // wxLogDebug: it is possible to bring the system to its knees
+ // by creating too many threads and not joining them quite
+ // easily
+ wxLogError(_("Failed to join a thread, potential memory leak detected - please restart the program"));
+ }
+
+ m_shouldBeJoined = false;
+ }
+ }
+
+#ifndef __WXOSX__
+ // reacquire GUI mutex
+ if ( wxThread::IsMain() )
+ wxMutexGuiEnter();
+#endif
+}
+
+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,
+ wxT("thread must first be paused with wxThread::Pause().") );
+
+ wxLogTrace(TRACE_THREADS,
+ wxT("Thread %p goes to sleep."), THR_ID(this));
+
+ // wait until the semaphore is Post()ed from Resume()
+ m_semSuspend.Wait();
+}
+
+void wxThreadInternal::Resume()
+{
+ wxCHECK_RET( m_state == STATE_PAUSED,
+ wxT("can't resume thread which is not suspended.") );
+
+ // the thread might be not actually paused yet - if there were no call to
+ // TestDestroy() since the last call to Pause() for example
+ if ( IsReallyPaused() )
+ {
+ wxLogTrace(TRACE_THREADS,
+ wxT("Waking up thread %p"), THR_ID(this));
+
+ // wake up Pause()
+ m_semSuspend.Post();
+
+ // reset the flag
+ SetReallyPaused(false);
+ }
+ else
+ {
+ wxLogTrace(TRACE_THREADS,
+ wxT("Thread %p is not yet really paused"), THR_ID(this));
+ }
+
+ SetState(STATE_RUNNING);
+}
+
+// -----------------------------------------------------------------------------
+// wxThread static functions
+// -----------------------------------------------------------------------------
+
+wxThread *wxThread::This()
+{
+ return (wxThread *)pthread_getspecific(gs_keySelf);
+}
+
+void wxThread::Yield()
+{
+#ifdef HAVE_SCHED_YIELD
+ sched_yield();
+#endif
+}
+
+int wxThread::GetCPUCount()
+{
+#if defined(_SC_NPROCESSORS_ONLN)
+ // this works for Solaris and Linux 2.6
+ int rc = sysconf(_SC_NPROCESSORS_ONLN);
+ if ( rc != -1 )
+ {
+ return rc;
+ }
+#elif defined(__LINUX__) && wxUSE_FFILE
+ // read from proc (can't use wxTextFile here because it's a special file:
+ // it has 0 size but still can be read from)
+ wxLogNull nolog;
+
+ wxFFile file(wxT("/proc/cpuinfo"));
+ if ( file.IsOpened() )
+ {
+ // slurp the whole file
+ wxString s;
+ if ( file.ReadAll(&s) )
+ {
+ // (ab)use Replace() to find the number of "processor: num" strings
+ size_t count = s.Replace(wxT("processor\t:"), wxT(""));
+ if ( count > 0 )
+ {
+ return count;
+ }
+
+ wxLogDebug(wxT("failed to parse /proc/cpuinfo"));
+ }
+ else
+ {
+ wxLogDebug(wxT("failed to read /proc/cpuinfo"));
+ }
+ }
+#endif // different ways to get number of CPUs
+
+ // unknown
+ return -1;
+}
+
+wxThreadIdType wxThread::GetCurrentId()
+{
+ return (wxThreadIdType)pthread_self();
+}
+
+
+bool wxThread::SetConcurrency(size_t level)
+{
+#ifdef HAVE_PTHREAD_SET_CONCURRENCY
+ int rc = pthread_setconcurrency( level );
+#elif defined(HAVE_THR_SETCONCURRENCY)
+ int rc = thr_setconcurrency(level);
+#else // !HAVE_THR_SETCONCURRENCY
+ // ok only for the default value
+ int rc = level == 0 ? 0 : -1;
+#endif // HAVE_THR_SETCONCURRENCY/!HAVE_THR_SETCONCURRENCY
+
+ if ( rc != 0 )
+ {
+ wxLogSysError(rc, _("Failed to set thread concurrency level to %lu"),
+ static_cast<unsigned long>(level));
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// creating thread
+// -----------------------------------------------------------------------------
+
+wxThread::wxThread(wxThreadKind kind)
+{
+ // add this thread to the global list of all threads
+ {
+ wxMutexLocker lock(*gs_mutexAllThreads);
+
+ gs_allThreads.Add(this);
+ }
+
+ m_internal = new wxThreadInternal();
+
+ m_isDetached = kind == wxTHREAD_DETACHED;
+}
+
+wxThreadError wxThread::Create(unsigned int stackSize)
+{
+ wxCriticalSectionLocker lock(m_critsect);
+
+ return m_internal->Create(this, stackSize);
+}
+