1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxThread Implementation 
   4 // Author:      Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin 
   5 // Modified by: Stefan Csomor 
   8 // Copyright:   (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998), 
   9 //                  Vadim Zeitlin (1999) , Stefan Csomor (2000) 
  10 // Licence:     wxWindows licence 
  11 ///////////////////////////////////////////////////////////////////////////// 
  14     #pragma implementation "thread.h" 
  17 // ---------------------------------------------------------------------------- 
  19 // ---------------------------------------------------------------------------- 
  21 // For compilers that support precompilation, includes "wx.h". 
  22 #include "wx/wxprec.h" 
  24 #if defined(__BORLANDC__) 
  34 #include "wx/module.h" 
  35 #include "wx/thread.h" 
  37 // ---------------------------------------------------------------------------- 
  39 // ---------------------------------------------------------------------------- 
  41 // the possible states of the thread ("=>" shows all possible transitions from 
  45     STATE_NEW
,          // didn't start execution yet (=> RUNNING) 
  46     STATE_RUNNING
,      // thread is running (=> PAUSED, CANCELED) 
  47     STATE_PAUSED
,       // thread is temporarily suspended (=> RUNNING) 
  48     STATE_CANCELED
,     // thread should terminate a.s.a.p. (=> EXITED) 
  49     STATE_EXITED        
// thread is terminating 
  52 // ---------------------------------------------------------------------------- 
  53 // this module globals 
  54 // ---------------------------------------------------------------------------- 
  56 static ThreadID gs_idMainThread 
= kNoThreadID 
; 
  57 static bool gs_waitingForThread 
= FALSE 
; 
  59 // ============================================================================ 
  60 // MacOS implementation of thread classes 
  61 // ============================================================================ 
  68                 ThreadBeginCritical() ; 
  76 // ---------------------------------------------------------------------------- 
  77 // wxMutex implementation 
  78 // ---------------------------------------------------------------------------- 
  85         m_owner 
= kNoThreadID 
; 
  94     wxArrayLong m_waiters 
; 
  99     m_internal 
= new wxMutexInternal
; 
 108         wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked
); 
 114 wxMutexError 
wxMutex::Lock() 
 116         wxMacStCritical critical 
; 
 119         ThreadID current 
= kNoThreadID
; 
 120         err 
= ::MacGetCurrentThread(¤t
); 
 121         // if we are not the owner, add this thread to the list of waiting threads, stop this thread 
 122         // and invoke the scheduler to continue executing the owner's thread 
 123         while ( m_internal
->m_owner 
!= kNoThreadID 
&& m_internal
->m_owner 
!= current
)  
 125                 m_internal
->m_waiters
.Add(current
); 
 126                 err 
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_internal
->m_owner
); 
 127                 err 
= ::ThreadBeginCritical(); 
 129         m_internal
->m_owner 
= current
; 
 132     return wxMUTEX_NO_ERROR
; 
 135 wxMutexError 
wxMutex::TryLock() 
 137         wxMacStCritical critical 
; 
 140         ThreadID current 
= kNoThreadID
; 
 141         ::MacGetCurrentThread(¤t
); 
 142         // if we are not the owner, give an error back 
 143         if ( m_internal
->m_owner 
!= kNoThreadID 
&& m_internal
->m_owner 
!= current 
)  
 146         m_internal
->m_owner 
= current
; 
 149    return wxMUTEX_NO_ERROR
; 
 152 wxMutexError 
wxMutex::Unlock() 
 155         err 
= ::ThreadBeginCritical(); 
 160         // this mutex is not owned by anybody anmore 
 161         m_internal
->m_owner 
= kNoThreadID
; 
 163         // now pass on to the first waiting thread 
 164         ThreadID firstWaiting 
= kNoThreadID
; 
 166         while (!m_internal
->m_waiters
.IsEmpty() && !found
)  
 168                 firstWaiting 
= m_internal
->m_waiters
[0]; 
 169                 err 
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
); 
 170                 // in case this was not successful (dead thread), we just loop on and reset the id 
 171                 found 
= (err 
!= threadNotFoundErr
);      
 173                         firstWaiting 
= kNoThreadID 
; 
 174                 m_internal
->m_waiters
.RemoveAt(0) ; 
 176         // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the 
 177         // critical section and invoke the scheduler 
 178         err 
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
); 
 180     return wxMUTEX_NO_ERROR
; 
 183 // ---------------------------------------------------------------------------- 
 184 // wxCondition implementation 
 185 // ---------------------------------------------------------------------------- 
 187 class wxConditionInternal
 
 190     wxConditionInternal() 
 192         m_excessSignals 
= 0 ; 
 194     ~wxConditionInternal() 
 198     bool Wait(unsigned long msectimeout
) 
 200                 wxMacStCritical critical 
; 
 201         if ( m_excessSignals 
> 0 ) 
 206         else if ( msectimeout 
== 0 ) 
 216         // FIXME this should be MsgWaitForMultipleObjects() as well probably 
 217         DWORD rc = ::WaitForSingleObject(event, timeout); 
 221         return rc != WAIT_TIMEOUT; 
 227                 wxMacStCritical critical 
; 
 230     wxArrayLong m_waiters 
; 
 231     wxInt32             m_excessSignals 
; 
 234 wxCondition::wxCondition() 
 236     m_internal 
= new wxConditionInternal
; 
 239 wxCondition::~wxCondition() 
 244 void wxCondition::Wait() 
 246     (void)m_internal
->Wait(0xFFFFFFFFL 
); 
 249 bool wxCondition::Wait(unsigned long sec
, 
 252     return m_internal
->Wait(sec
*1000 + nsec
/1000000); 
 255 void wxCondition::Signal() 
 257     // set the event to signaled: if a thread is already waiting on it, it will 
 258     // be woken up, otherwise the event will remain in the signaled state until 
 259     // someone waits on it. In any case, the system will return it to a non 
 260     // signalled state afterwards. If multiple threads are waiting, only one 
 262         m_internal
->Signal() ; 
 265 void wxCondition::Broadcast() 
 267     // this works because all these threads are already waiting and so each 
 268     // SetEvent() inside Signal() is really a PulseEvent() because the event 
 269     // state is immediately returned to non-signaled 
 270     for ( int i 
= 0; i 
< m_internal
->m_waiters
.Count(); i
++ ) 
 276 // ---------------------------------------------------------------------------- 
 277 // wxCriticalSection implementation 
 278 // ---------------------------------------------------------------------------- 
 280 // it's implemented as a mutex on mac os, so it is defined in the headers 
 282 // ---------------------------------------------------------------------------- 
 283 // wxThread implementation 
 284 // ---------------------------------------------------------------------------- 
 286 // wxThreadInternal class 
 287 // ---------------------- 
 289 class wxThreadInternal
 
 294         m_tid 
= kNoThreadID 
; 
 296         m_priority 
= WXTHREAD_DEFAULT_PRIORITY
; 
 307     // create a new (suspended) thread (for the given thread object) 
 308     bool Create(wxThread 
*thread
); 
 310     // suspend/resume/terminate 
 313     void Cancel() { m_state 
= STATE_CANCELED
; } 
 316     void SetState(wxThreadState state
) { m_state 
= state
; } 
 317     wxThreadState 
GetState() const { return m_state
; } 
 320     void SetPriority(unsigned int priority
); 
 321     unsigned int GetPriority() const { return m_priority
; } 
 323     void SetResult( void *res 
) { m_result 
= res 
; } 
 324     void *GetResult() { return m_result 
; } 
 326     // thread handle and id 
 327     ThreadID  
GetId() const { return m_tid
; } 
 330         static pascal void*     MacThreadStart(wxThread
* arg
); 
 333     wxThreadState       m_state
;      // state, see wxThreadState enum 
 334     unsigned int        m_priority
;   // thread priority in "wx" units 
 335     ThreadID        m_tid
;        // thread id 
 337     static ThreadEntryUPP s_threadEntry 
; 
 341 static wxArrayPtrVoid s_threads 
; 
 343 ThreadEntryUPP 
wxThreadInternal::s_threadEntry 
= NULL 
; 
 344 pascal void* wxThreadInternal::MacThreadStart(wxThread 
*thread
) 
 346     // first of all, check whether we hadn't been cancelled already 
 347     if ( thread
->m_internal
->GetState() == STATE_EXITED 
) 
 352     void* rc 
= thread
->Entry(); 
 354     // enter m_critsect before changing the thread state 
 355     thread
->m_critsect
.Enter(); 
 356     bool wasCancelled 
= thread
->m_internal
->GetState() == STATE_CANCELED
; 
 357     thread
->m_internal
->SetState(STATE_EXITED
); 
 358     thread
->m_critsect
.Leave(); 
 362     // if the thread was cancelled (from Delete()), then it the handle is still 
 364     if ( thread
->IsDetached() && !wasCancelled 
) 
 369     //else: the joinable threads handle will be closed when Wait() is done 
 373 void wxThreadInternal::SetPriority(unsigned int priority
) 
 375         // Priorities don't exist on Mac 
 378 bool wxThreadInternal::Create(wxThread 
*thread
) 
 380         if ( s_threadEntry 
== NULL 
) 
 382                 s_threadEntry 
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart 
) ; 
 384         OSErr err 
= NewThread(kCooperativeThread
, 
 394         wxLogSysError(_("Can't create thread")); 
 398     if ( m_priority 
!= WXTHREAD_DEFAULT_PRIORITY 
) 
 400         SetPriority(m_priority
); 
 406 bool wxThreadInternal::Suspend() 
 410         ::ThreadBeginCritical(); 
 412         if ( m_state 
!= STATE_RUNNING 
) 
 414         ::ThreadEndCritical() ; 
 415         wxLogSysError(_("Can not suspend thread %x"), m_tid
); 
 419     m_state 
= STATE_PAUSED
; 
 421         err 
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
); 
 426 bool wxThreadInternal::Resume() 
 430         err 
= MacGetCurrentThread( ¤t 
) ; 
 432         wxASSERT( err 
== noErr 
) ; 
 433         wxASSERT( current 
!= m_tid 
) ; 
 435         ::ThreadBeginCritical(); 
 436         if ( m_state 
!= STATE_PAUSED 
&& m_state 
!= STATE_NEW 
) 
 438         ::ThreadEndCritical() ; 
 439         wxLogSysError(_("Can not resume thread %x"), m_tid
); 
 443         err 
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
); 
 444         wxASSERT( err 
== noErr 
) ; 
 446     m_state 
= STATE_RUNNING
; 
 447         ::ThreadEndCritical() ; 
 448         ::YieldToAnyThread() ; 
 454 wxThread 
*wxThread::This() 
 456         wxMacStCritical critical 
; 
 461         err 
= MacGetCurrentThread( ¤t 
) ; 
 463         for ( int i 
= 0 ; i 
< s_threads
.Count() ; ++i 
) 
 465                 if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current 
) 
 466                         return (wxThread
*) s_threads
[i
] ; 
 469     wxLogSysError(_("Couldn't get the current thread pointer")); 
 473 bool wxThread::IsMain() 
 478         err 
= MacGetCurrentThread( ¤t 
) ; 
 479     return current 
== gs_idMainThread
; 
 486 void wxThread::Yield() 
 488         ::YieldToAnyThread() ; 
 491 void wxThread::Sleep(unsigned long milliseconds
) 
 493                 clock_t start 
= clock() ; 
 497                 } while( clock() - start 
< milliseconds 
/ CLOCKS_PER_SEC 
) ; 
 500 int wxThread::GetCPUCount() 
 502         // we will use whatever MP API will be used for the new MP Macs 
 506 bool wxThread::SetConcurrency(size_t level
) 
 508     wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") ); 
 510     // ok only for the default one 
 514     // how many CPUs have we got? 
 515     if ( GetCPUCount() == 1 ) 
 517         // don't bother with all this complicated stuff - on a single 
 518         // processor system it doesn't make much sense anyhow 
 528 wxThread::wxThread(wxThreadKind kind
) 
 530     m_internal 
= new wxThreadInternal(); 
 532     m_isDetached 
= kind 
== wxTHREAD_DETACHED
; 
 533     s_threads
.Add( (void*) this ) ; 
 536 wxThread::~wxThread() 
 538         s_threads
.Remove( (void*) this ) ; 
 542 // create/start thread 
 543 // ------------------- 
 545 wxThreadError 
wxThread::Create() 
 547     wxCriticalSectionLocker 
lock(m_critsect
); 
 549     if ( !m_internal
->Create(this) ) 
 550         return wxTHREAD_NO_RESOURCE
; 
 552     return wxTHREAD_NO_ERROR
; 
 555 wxThreadError 
wxThread::Run() 
 557     wxCriticalSectionLocker 
lock(m_critsect
); 
 559     if ( m_internal
->GetState() != STATE_NEW 
) 
 561         // actually, it may be almost any state at all, not only STATE_RUNNING 
 562         return wxTHREAD_RUNNING
; 
 565     // the thread has just been created and is still suspended - let it run 
 569 // suspend/resume thread 
 570 // --------------------- 
 572 wxThreadError 
wxThread::Pause() 
 574     wxCriticalSectionLocker 
lock(m_critsect
); 
 576     return m_internal
->Suspend() ? wxTHREAD_NO_ERROR 
: wxTHREAD_MISC_ERROR
; 
 579 wxThreadError 
wxThread::Resume() 
 581     wxCriticalSectionLocker 
lock(m_critsect
); 
 583     return m_internal
->Resume() ? wxTHREAD_NO_ERROR 
: wxTHREAD_MISC_ERROR
; 
 589 wxThread::ExitCode 
wxThread::Wait() 
 591     // although under MacOS we can wait for any thread, it's an error to 
 592     // wait for a detached one in wxWin API 
 593     wxCHECK_MSG( !IsDetached(), (ExitCode
)-1, 
 594                  _T("can't wait for detached thread") ); 
 596     ExitCode rc 
= (ExitCode
)-1; 
 605 wxThreadError 
wxThread::Delete(ExitCode 
*pRc
) 
 609     // Delete() is always safe to call, so consider all possible states 
 611     // has the thread started to run? 
 612     bool shouldResume 
= FALSE
; 
 615         wxCriticalSectionLocker 
lock(m_critsect
); 
 617         if ( m_internal
->GetState() == STATE_NEW 
) 
 619             // WinThreadStart() will see it and terminate immediately 
 620             m_internal
->SetState(STATE_EXITED
); 
 626     // is the thread paused? 
 627     if ( shouldResume 
|| IsPaused() ) 
 630     // does is still run? 
 635             // set flag for wxIsWaitingForThread() 
 636             gs_waitingForThread 
= TRUE
; 
 643         // ask the thread to terminate 
 645             wxCriticalSectionLocker 
lock(m_critsect
); 
 647             m_internal
->Cancel(); 
 651         // simply wait for the thread to terminate 
 652                 while( TestDestroy() ) 
 654                         ::YieldToAnyThread() ; 
 657         // simply wait for the thread to terminate 
 658                 while( TestDestroy() ) 
 660                         ::YieldToAnyThread() ; 
 662 #endif // wxUSE_GUI/!wxUSE_GUI 
 666             gs_waitingForThread 
= FALSE
; 
 674  //   if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) ) 
 676         wxLogLastError("GetExitCodeThread"); 
 683         // if the thread exits normally, this is done in WinThreadStart, but in 
 684         // this case it would have been too early because 
 685         // MsgWaitForMultipleObject() would fail if the therad handle was 
 686         // closed while we were waiting on it, so we must do it here 
 690  //   wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE, 
 691  //                 wxT("thread must be already terminated.") ); 
 696     return rc 
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR 
: wxTHREAD_NO_ERROR
; 
 699 wxThreadError 
wxThread::Kill() 
 702         return wxTHREAD_NOT_RUNNING
; 
 704 //    if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) ) 
 706         wxLogSysError(_("Couldn't terminate thread")); 
 708         return wxTHREAD_MISC_ERROR
; 
 718     return wxTHREAD_NO_ERROR
; 
 721 void wxThread::Exit(ExitCode status
) 
 730         m_internal
->SetResult( status 
) ; 
 733 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) 
 734     _endthreadex((unsigned)status); 
 736     ::ExitThread((DWORD)status); 
 739     wxFAIL_MSG(wxT("Couldn't return from ExitThread()!")); 
 745 // since all these calls are execute cooperatively we don't have to use the critical section 
 747 void wxThread::SetPriority(unsigned int prio
) 
 749     m_internal
->SetPriority(prio
); 
 752 unsigned int wxThread::GetPriority() const 
 754     return m_internal
->GetPriority(); 
 757 unsigned long wxThread::GetId() const 
 759     return (unsigned long)m_internal
->GetId(); 
 762 bool wxThread::IsRunning() const 
 764     return m_internal
->GetState() == STATE_RUNNING
; 
 767 bool wxThread::IsAlive() const 
 769     return (m_internal
->GetState() == STATE_RUNNING
) || 
 770            (m_internal
->GetState() == STATE_PAUSED
); 
 773 bool wxThread::IsPaused() const 
 775     return m_internal
->GetState() == STATE_PAUSED
; 
 778 bool wxThread::TestDestroy() 
 780     return m_internal
->GetState() == STATE_CANCELED
; 
 783 // ---------------------------------------------------------------------------- 
 784 // Automatic initialization for thread module 
 785 // ---------------------------------------------------------------------------- 
 787 class wxThreadModule 
: public wxModule
 
 790     virtual bool OnInit(); 
 791     virtual void OnExit(); 
 794     DECLARE_DYNAMIC_CLASS(wxThreadModule
) 
 797 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
) 
 799 bool wxThreadModule::OnInit() 
 802         bool hasThreadManager 
; 
 803         hasThreadManager 
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr 
&& response 
& 1; 
 806         // verify presence of shared library 
 807         hasThreadManager 
= hasThreadManager 
&& ((Ptr
)NewThread 
!= (Ptr
)kUnresolvedCFragSymbolAddress
); 
 810         if ( !hasThreadManager 
) 
 812                 wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK 
) ; 
 816     // no error return for GetCurrentThreadId() 
 817     MacGetCurrentThread( &gs_idMainThread 
) ; 
 822 void wxThreadModule::OnExit() 
 826 // ---------------------------------------------------------------------------- 
 827 // under MacOS we don't have currently preemptive threads, so any thread may access 
 828 // the GUI at any time 
 829 // ---------------------------------------------------------------------------- 
 831 void WXDLLEXPORT 
wxMutexGuiEnter() 
 835 void WXDLLEXPORT 
wxMutexGuiLeave() 
 839 void WXDLLEXPORT 
wxMutexGuiLeaveOrEnter() 
 843 bool WXDLLEXPORT 
wxGuiOwnedByMainThread() 
 848 // wake up the main thread  
 849 void WXDLLEXPORT 
wxWakeUpMainThread() 
 854 bool WXDLLEXPORT 
wxIsWaitingForThread() 
 859 #endif // wxUSE_THREADS