+ IncrementAtomic( &m_numWaiters );
+
+ m_mutex.Unlock();
+
+ // a race condition can occur at this point in the code
+ //
+ // please see the comments in Wait(), for details
+
+ wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
+
+ if ( err == wxSEMA_TIMEOUT )
+ {
+ // another potential race condition exists here it is caused when a
+ // 'waiting' thread timesout, and returns from WaitForSingleObject, but
+ // has not yet decremented 'nwaiters'.
+ //
+ // at this point if another thread calls signal() then the semaphore
+ // will be incremented, but the waiting thread will miss it.
+ //
+ // to handle this particular case, the waiting thread calls
+ // WaitForSingleObject again with a timeout of 0, after locking
+ // 'nwaiters_mutex'. this call does not block because of the zero
+ // timeout, but will allow the waiting thread to catch the missed
+ // signals.
+ wxCriticalSectionLocker lock(m_csWaiters);
+
+ err = m_semaphore.WaitTimeout(0);
+
+ if ( err != wxSEMA_NO_ERROR )
+ {
+ m_numWaiters--;
+ }
+ }
+
+ m_mutex.Lock();
+
+ return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
+}
+
+wxCondError wxConditionInternal::Signal()
+{
+ wxCriticalSectionLocker lock(m_csWaiters);
+
+ if ( m_numWaiters > 0 )
+ {
+ // increment the semaphore by 1
+ if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
+ return wxCOND_MISC_ERROR;
+
+ m_numWaiters--;
+ }
+
+ return wxCOND_NO_ERROR;
+}
+
+wxCondError wxConditionInternal::Broadcast()
+{
+ wxCriticalSectionLocker lock(m_csWaiters);
+
+ while ( m_numWaiters > 0 )
+ {
+ if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
+ return wxCOND_MISC_ERROR;
+
+ m_numWaiters--;
+ }
+
+ return wxCOND_NO_ERROR;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// wxCriticalSection implementation
+// ----------------------------------------------------------------------------
+
+// XXX currently implemented as mutex in headers. Change to critical section.
+
+// ----------------------------------------------------------------------------
+// wxThread implementation
+// ----------------------------------------------------------------------------
+
+// wxThreadInternal class
+// ----------------------
+
+class wxThreadInternal
+{
+public:
+ wxThreadInternal()
+ {
+ m_tid = kInvalidID;
+ m_state = STATE_NEW;
+ m_prio = WXTHREAD_DEFAULT_PRIORITY;
+ m_notifyQueueId = kInvalidID;
+ m_exitcode = 0;
+ m_cancelled = false ;
+
+ // 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;
+ }
+
+ virtual ~wxThreadInternal()
+ {
+ if ( m_notifyQueueId)
+ {
+ MPDeleteQueue( m_notifyQueueId );
+ m_notifyQueueId = kInvalidID ;
+ }
+ }
+
+ // thread function
+ static OSStatus MacThreadStart(void* arg);
+
+ // create a new (suspended) thread (for the given thread object)
+ bool Create(wxThread *thread, unsigned int stackSize);
+
+ // thread actions
+
+ // start the thread
+ wxThreadError Run();
+
+ // unblock the thread allowing it to run
+ void SignalRun() { m_semRun.Post(); }
+
+ // ask the thread to terminate
+ void Wait();
+
+ // go to sleep until Resume() is called
+ void Pause();
+
+ // resume the thread
+ void Resume();
+
+ // accessors
+ // priority
+ int GetPriority() const
+ { return m_prio; }
+ void SetPriority(int prio);
+
+ // state
+ wxThreadState GetState() const
+ { return m_state; }
+ void SetState(wxThreadState state)
+ { m_state = state; }
+
+ // Get the ID of this thread's underlying MP Services task.
+ MPTaskID GetId() const
+ { return m_tid; }
+
+ void SetCancelFlag()
+ { m_cancelled = true; }
+
+ bool WasCancelled() const
+ { return m_cancelled; }
+
+ // exit code
+ void SetExitCode(wxThread::ExitCode exitcode)
+ { m_exitcode = exitcode; }
+ wxThread::ExitCode GetExitCode() const
+ { return m_exitcode; }
+
+ // the pause flag
+ void SetReallyPaused(bool paused)
+ { m_isPaused = paused; }
+ bool IsReallyPaused() const
+ { return m_isPaused; }
+
+ // tell the thread that it is a detached one
+ void Detach()
+ {
+ wxCriticalSectionLocker lock(m_csJoinFlag);
+
+ m_shouldBeJoined = false;
+ m_isDetached = true;
+ }
+
+private:
+ // the thread we're associated with
+ wxThread * m_thread;
+
+ MPTaskID m_tid; // thread id
+ MPQueueID m_notifyQueueId; // its notification queue
+
+ wxThreadState m_state; // see wxThreadState enum
+ int m_prio; // in wxWidgets units: from 0 to 100
+
+ // this flag is set when the thread should terminate
+ bool m_cancelled;
+
+ // this flag is set when the thread is blocking on m_semSuspend
+ bool m_isPaused;
+
+ // the thread exit code - only used for joinable (!detached) threads and
+ // is only valid after the thread termination
+ wxThread::ExitCode m_exitcode;
+
+ // many threads may call Wait(), but only one of them should call
+ // pthread_join(), so we have to keep track of this
+ wxCriticalSection m_csJoinFlag;
+ bool m_shouldBeJoined;
+ bool m_isDetached;
+
+ // this semaphore is posted by Run() and the threads Entry() is not
+ // called before it is done
+ wxSemaphore m_semRun;
+
+ // this one is signaled when the thread should resume after having been
+ // Pause()d
+ wxSemaphore m_semSuspend;
+};
+
+OSStatus wxThreadInternal::MacThreadStart(void *parameter)
+{
+ wxThread* thread = (wxThread*) parameter ;
+ wxThreadInternal *pthread = thread->m_internal;
+
+ // add to TLS so that This() will work
+ verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , (TaskStorageValue) thread ) ) ;
+
+ // have to declare this before pthread_cleanup_push() which defines a
+ // block!
+ bool dontRunAtAll;
+
+ // 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 )
+ {
+ pthread->m_exitcode = thread->Entry();
+
+ {
+ wxCriticalSectionLocker lock(thread->m_critsect);
+ pthread->SetState( STATE_EXITED );
+ }
+ }
+
+ if ( dontRunAtAll )
+ {
+ if ( pthread->m_isDetached )
+ delete thread;
+
+ return -1;
+ }
+ else
+ {
+ // on Mac for the running code,
+ // the correct thread termination is to return
+
+ // terminate the thread
+ thread->Exit( pthread->m_exitcode );
+
+ return (OSStatus) NULL; // pthread->m_exitcode;
+ }
+}
+
+bool wxThreadInternal::Create( wxThread *thread, unsigned int stackSize )
+{
+ wxASSERT_MSG( m_state == STATE_NEW && !m_tid,
+ wxT("Create()ing thread twice?") );
+
+ OSStatus err = noErr;
+ m_thread = thread;
+
+ if ( m_notifyQueueId == kInvalidID )
+ {
+ OSStatus err = MPCreateQueue( &m_notifyQueueId );
+ if (err != noErr)
+ {
+ wxLogSysError( wxT("Cant create the thread event queue") );
+
+ return false;
+ }
+ }
+
+ m_state = STATE_NEW;
+
+ err = MPCreateTask(
+ MacThreadStart, (void*)m_thread, stackSize,
+ m_notifyQueueId, &m_exitcode, 0, 0, &m_tid );
+
+ if (err != noErr)
+ {
+ wxLogSysError( wxT("Can't create thread") );
+
+ return false;
+ }
+
+ if ( m_prio != WXTHREAD_DEFAULT_PRIORITY )
+ SetPriority( m_prio );
+
+ return true;
+}
+
+void wxThreadInternal::SetPriority( int priority )
+{
+ m_prio = priority;
+
+ if (m_tid)
+ {
+ // Mac priorities range from 1 to 10,000, with a default of 100.
+ // wxWidgets priorities range from 0 to 100 with a default of 50.
+ // We can map wxWidgets to Mac priorities easily by assuming
+ // the former uses a logarithmic scale.
+ const unsigned int macPriority = (int)( exp( priority / 25.0 * log( 10.0)) + 0.5);
+
+ MPSetTaskWeight( m_tid, macPriority );
+ }
+}
+
+wxThreadError wxThreadInternal::Run()
+{
+ wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
+ wxT("thread may only be started once after Create()") );
+
+ SetState( STATE_RUNNING );
+
+ // wake up threads waiting for our start
+ SignalRun();
+