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" 
  39 #include "wx/mac/uma.h" 
  40 #include "wx/mac/macnotfy.h" 
  44 #define INFINITE 0xFFFFFFFF 
  47 // ---------------------------------------------------------------------------- 
  49 // ---------------------------------------------------------------------------- 
  51 // the possible states of the thread ("=>" shows all possible transitions from 
  55     STATE_NEW
,          // didn't start execution yet (=> RUNNING) 
  56     STATE_RUNNING
,      // thread is running (=> PAUSED, CANCELED) 
  57     STATE_PAUSED
,       // thread is temporarily suspended (=> RUNNING) 
  58     STATE_CANCELED
,     // thread should terminate a.s.a.p. (=> EXITED) 
  59     STATE_EXITED        
// thread is terminating 
  62 // ---------------------------------------------------------------------------- 
  63 // this module globals 
  64 // ---------------------------------------------------------------------------- 
  66 static ThreadID gs_idMainThread 
= kNoThreadID 
; 
  67 static bool gs_waitingForThread 
= FALSE 
; 
  68 size_t g_numberOfThreads 
= 0; 
  70 // ============================================================================ 
  71 // MacOS implementation of thread classes 
  72 // ============================================================================ 
  79         if ( UMASystemIsInitialized() ) 
  81             OSErr err 
= ThreadBeginCritical() ; 
  82             wxASSERT( err 
== noErr 
) ; 
  87         if ( UMASystemIsInitialized() ) 
  89             OSErr err 
= ThreadEndCritical() ; 
  90             wxASSERT( err 
== noErr 
) ; 
  95 // ---------------------------------------------------------------------------- 
  96 // wxMutex implementation 
  97 // ---------------------------------------------------------------------------- 
 102     wxMutexInternal(wxMutexType 
WXUNUSED(mutexType
)) 
 104         m_owner 
= kNoThreadID 
; 
 112             wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked
); 
 116     bool IsOk() const { return true; } 
 118     wxMutexError 
Lock() ; 
 119     wxMutexError 
TryLock() ; 
 120     wxMutexError 
Unlock(); 
 123     wxArrayLong m_waiters 
; 
 127 wxMutexError 
wxMutexInternal::Lock() 
 129     wxMacStCritical critical 
; 
 130     if ( UMASystemIsInitialized() ) 
 133         ThreadID current 
= kNoThreadID
; 
 134         err 
= ::MacGetCurrentThread(¤t
); 
 135         // if we are not the owner, add this thread to the list of waiting threads, stop this thread 
 136         // and invoke the scheduler to continue executing the owner's thread 
 137         while ( m_owner 
!= kNoThreadID 
&& m_owner 
!= current
) 
 139             m_waiters
.Add(current
); 
 140             err 
= ::SetThreadStateEndCritical(kCurrentThreadID
, kStoppedThreadState
, m_owner
); 
 141             err 
= ::ThreadBeginCritical(); 
 142             wxASSERT( err 
== noErr 
) ; 
 148     return wxMUTEX_NO_ERROR
; 
 151 wxMutexError 
wxMutexInternal::TryLock() 
 153     wxMacStCritical critical 
; 
 154     if ( UMASystemIsInitialized() ) 
 156         ThreadID current 
= kNoThreadID
; 
 157         ::MacGetCurrentThread(¤t
); 
 158         // if we are not the owner, give an error back 
 159         if ( m_owner 
!= kNoThreadID 
&& m_owner 
!= current 
) 
 166    return wxMUTEX_NO_ERROR
; 
 169 wxMutexError 
wxMutexInternal::Unlock() 
 171     if ( UMASystemIsInitialized() ) 
 174         err 
= ::ThreadBeginCritical(); 
 175         wxASSERT( err 
== noErr 
) ; 
 180         // this mutex is not owned by anybody anmore 
 181         m_owner 
= kNoThreadID
; 
 183         // now pass on to the first waiting thread 
 184         ThreadID firstWaiting 
= kNoThreadID
; 
 186         while (!m_waiters
.IsEmpty() && !found
) 
 188             firstWaiting 
= m_waiters
[0]; 
 189             err 
= ::SetThreadState(firstWaiting
, kReadyThreadState
, kNoThreadID
); 
 190             // in case this was not successful (dead thread), we just loop on and reset the id 
 191             found 
= (err 
!= threadNotFoundErr
); 
 193                 firstWaiting 
= kNoThreadID 
; 
 194             m_waiters
.RemoveAt(0) ; 
 196         // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the 
 197         // critical section and invoke the scheduler 
 198         err 
= ::SetThreadStateEndCritical(kCurrentThreadID
, kReadyThreadState
, firstWaiting
); 
 205     return wxMUTEX_NO_ERROR
; 
 208 // -------------------------------------------------------------------------- 
 210 // -------------------------------------------------------------------------- 
 212 // TODO not yet implemented 
 214 class wxSemaphoreInternal
 
 217     wxSemaphoreInternal(int initialcount
, int maxcount
); 
 218     ~wxSemaphoreInternal(); 
 220     bool IsOk() const { return true ; } 
 222     wxSemaError 
Wait() { return WaitTimeout(INFINITE
); } 
 223     wxSemaError 
TryWait() { return WaitTimeout(0); } 
 224     wxSemaError 
WaitTimeout(unsigned long milliseconds
); 
 231 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount
, int maxcount
) 
 235         // make it practically infinite 
 240 wxSemaphoreInternal::~wxSemaphoreInternal() 
 244 wxSemaError 
wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds
) 
 246     return wxSEMA_MISC_ERROR
; 
 249 wxSemaError 
wxSemaphoreInternal::Post() 
 251     return wxSEMA_MISC_ERROR
; 
 254 // ---------------------------------------------------------------------------- 
 255 // wxCondition implementation 
 256 // ---------------------------------------------------------------------------- 
 258 // TODO this is not yet completed 
 260 class wxConditionInternal
 
 263     wxConditionInternal(wxMutex
& mutex
) : m_mutex(mutex
) 
 265         m_excessSignals 
= 0 ; 
 267     ~wxConditionInternal() 
 271     bool IsOk() const { return m_mutex
.IsOk() ; } 
 275         return WaitTimeout(0xFFFFFFFF ); 
 278     wxCondError 
WaitTimeout(unsigned long msectimeout
) 
 280         wxMacStCritical critical 
; 
 281         if ( m_excessSignals 
> 0 ) 
 284             return wxCOND_NO_ERROR 
; 
 286         else if ( msectimeout 
== 0 ) 
 288             return wxCOND_MISC_ERROR 
; 
 296         // FIXME this should be MsgWaitForMultipleObjects() as well probably 
 297         DWORD rc = ::WaitForSingleObject(event, timeout); 
 301         return rc != WAIT_TIMEOUT; 
 303         return wxCOND_NO_ERROR 
; 
 307         wxMacStCritical critical 
; 
 308         return wxCOND_NO_ERROR
; 
 311     wxCondError 
Broadcast() 
 313         wxMacStCritical critical 
; 
 314         return wxCOND_NO_ERROR
; 
 317     wxArrayLong m_waiters 
; 
 318     wxInt32     m_excessSignals 
; 
 322 // ---------------------------------------------------------------------------- 
 323 // wxCriticalSection implementation 
 324 // ---------------------------------------------------------------------------- 
 326 // it's implemented as a mutex on mac os, so it is defined in the headers 
 328 // ---------------------------------------------------------------------------- 
 329 // wxThread implementation 
 330 // ---------------------------------------------------------------------------- 
 332 // wxThreadInternal class 
 333 // ---------------------- 
 335 class wxThreadInternal
 
 340         m_tid 
= kNoThreadID 
; 
 342         m_priority 
= WXTHREAD_DEFAULT_PRIORITY
; 
 353     // create a new (suspended) thread (for the given thread object) 
 354     bool Create(wxThread 
*thread
, unsigned int stackSize
); 
 356     // suspend/resume/terminate 
 359     void Cancel() { m_state 
= STATE_CANCELED
; } 
 362     void SetState(wxThreadState state
) { m_state 
= state
; } 
 363     wxThreadState 
GetState() const { return m_state
; } 
 366     void SetPriority(unsigned int priority
); 
 367     unsigned int GetPriority() const { return m_priority
; } 
 369     void SetResult( void *res 
) { m_result 
= res 
; } 
 370     void *GetResult() { return m_result 
; } 
 372     // thread handle and id 
 373     ThreadID  
GetId() const { return m_tid
; } 
 376     static pascal void*    MacThreadStart(wxThread
* arg
); 
 379     wxThreadState           m_state
;      // state, see wxThreadState enum 
 380     unsigned int            m_priority
;   // thread priority in "wx" units 
 381     ThreadID                m_tid
;        // thread id 
 383     static ThreadEntryUPP   s_threadEntry 
; 
 386 static wxArrayPtrVoid s_threads 
; 
 388 ThreadEntryUPP 
wxThreadInternal::s_threadEntry 
= NULL 
; 
 389 pascal void* wxThreadInternal::MacThreadStart(wxThread 
*thread
) 
 391     // first of all, check whether we hadn't been cancelled already 
 392     if ( thread
->m_internal
->GetState() == STATE_EXITED 
) 
 397     void* rc 
= thread
->Entry(); 
 399     // enter m_critsect before changing the thread state 
 400     thread
->m_critsect
.Enter(); 
 401     bool wasCancelled 
= thread
->m_internal
->GetState() == STATE_CANCELED
; 
 402     thread
->m_internal
->SetState(STATE_EXITED
); 
 403     thread
->m_critsect
.Leave(); 
 407     // if the thread was cancelled (from Delete()), then it the handle is still 
 409     if ( thread
->IsDetached() && !wasCancelled 
) 
 414     //else: the joinable threads handle will be closed when Wait() is done 
 418 void wxThreadInternal::SetPriority(unsigned int priority
) 
 420     // Priorities don't exist on Mac 
 423 bool wxThreadInternal::Create(wxThread 
*thread
, unsigned int stackSize
) 
 425     if ( s_threadEntry 
== NULL 
) 
 427         s_threadEntry 
= NewThreadEntryUPP( (ThreadEntryProcPtr
) MacThreadStart 
) ; 
 429     OSErr err 
= NewThread( kCooperativeThread
, 
 439         wxLogSysError(_("Can't create thread")); 
 443     if ( m_priority 
!= WXTHREAD_DEFAULT_PRIORITY 
) 
 445         SetPriority(m_priority
); 
 453 bool wxThreadInternal::Suspend() 
 457     err 
= ::ThreadBeginCritical(); 
 458     wxASSERT( err 
== noErr 
) ; 
 460     if ( m_state 
!= STATE_RUNNING 
) 
 462         err 
= ::ThreadEndCritical() ; 
 463         wxASSERT( err 
== noErr 
) ; 
 464         wxLogSysError(_("Can not suspend thread %x"), m_tid
); 
 468     m_state 
= STATE_PAUSED
; 
 470     err 
= ::SetThreadStateEndCritical(m_tid
, kStoppedThreadState
, kNoThreadID
); 
 475 bool wxThreadInternal::Resume() 
 479     err 
= MacGetCurrentThread( ¤t 
) ; 
 481     wxASSERT( err 
== noErr 
) ; 
 482     wxASSERT( current 
!= m_tid 
) ; 
 484     err 
= ::ThreadBeginCritical(); 
 485     wxASSERT( err 
== noErr 
) ; 
 487     if ( m_state 
!= STATE_PAUSED 
&& m_state 
!= STATE_NEW 
) 
 489         err 
= ::ThreadEndCritical() ; 
 490         wxASSERT( err 
== noErr 
) ; 
 491         wxLogSysError(_("Can not resume thread %x"), m_tid
); 
 495     err 
= ::SetThreadStateEndCritical(m_tid
, kReadyThreadState
, kNoThreadID
); 
 497     m_state 
= STATE_RUNNING
; 
 498     err 
= ::ThreadEndCritical() ; 
 499     wxASSERT( err 
== noErr 
) ; 
 500     ::YieldToAnyThread() ; 
 506 wxThread 
*wxThread::This() 
 508     wxMacStCritical critical 
; 
 513     err 
= MacGetCurrentThread( ¤t 
) ; 
 515     for ( size_t i 
= 0 ; i 
< s_threads
.Count() ; ++i 
) 
 517         if ( ( (wxThread
*) s_threads
[i
] )->GetId() == current 
) 
 518             return (wxThread
*) s_threads
[i
] ; 
 521     wxLogSysError(_("Couldn't get the current thread pointer")); 
 525 bool wxThread::IsMain() 
 530     err 
= MacGetCurrentThread( ¤t 
) ; 
 531     return current 
== gs_idMainThread
; 
 538 void wxThread::Yield() 
 540     ::YieldToAnyThread() ; 
 543 void wxThread::Sleep(unsigned long milliseconds
) 
 545     UnsignedWide start
, now
; 
 547     Microseconds(&start
); 
 549     double mssleep 
= milliseconds 
* 1000 ; 
 550     double msstart
, msnow 
; 
 551     msstart 
= (start
.hi 
* 4294967296.0 + start
.lo
) ; 
 557         msnow 
= (now
.hi 
* 4294967296.0 + now
.lo
) ; 
 558     } while( msnow 
- msstart 
< mssleep 
); 
 561 int wxThread::GetCPUCount() 
 563     // we will use whatever MP API will be used for the new MP Macs 
 567 unsigned long wxThread::GetCurrentId() 
 570     MacGetCurrentThread( ¤t 
) ; 
 571     return (unsigned long)current
; 
 574 bool wxThread::SetConcurrency(size_t level
) 
 576     wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") ); 
 578     // ok only for the default one 
 582     // how many CPUs have we got? 
 583     if ( GetCPUCount() == 1 ) 
 585         // don't bother with all this complicated stuff - on a single 
 586         // processor system it doesn't make much sense anyhow 
 596 wxThread::wxThread(wxThreadKind kind
) 
 599     m_internal 
= new wxThreadInternal(); 
 601     m_isDetached 
= kind 
== wxTHREAD_DETACHED
; 
 602     s_threads
.Add( (void*) this ) ; 
 605 wxThread::~wxThread() 
 607     if (g_numberOfThreads
>0) 
 614         wxFAIL_MSG(wxT("More threads deleted than created.")); 
 618     s_threads
.Remove( (void*) this ) ; 
 619     if (m_internal 
!= NULL
) { 
 625 // create/start thread 
 626 // ------------------- 
 628 wxThreadError 
wxThread::Create(unsigned int stackSize
) 
 630     wxCriticalSectionLocker 
lock(m_critsect
); 
 632     if ( !m_internal
->Create(this, stackSize
) ) 
 633         return wxTHREAD_NO_RESOURCE
; 
 635     return wxTHREAD_NO_ERROR
; 
 638 wxThreadError 
wxThread::Run() 
 640     wxCriticalSectionLocker 
lock(m_critsect
); 
 642     if ( m_internal
->GetState() != STATE_NEW 
) 
 644         // actually, it may be almost any state at all, not only STATE_RUNNING 
 645         return wxTHREAD_RUNNING
; 
 648     // the thread has just been created and is still suspended - let it run 
 652 // suspend/resume thread 
 653 // --------------------- 
 655 wxThreadError 
wxThread::Pause() 
 657     wxCriticalSectionLocker 
lock(m_critsect
); 
 659     return m_internal
->Suspend() ? wxTHREAD_NO_ERROR 
: wxTHREAD_MISC_ERROR
; 
 662 wxThreadError 
wxThread::Resume() 
 664     wxCriticalSectionLocker 
lock(m_critsect
); 
 666     return m_internal
->Resume() ? wxTHREAD_NO_ERROR 
: wxTHREAD_MISC_ERROR
; 
 672 wxThread::ExitCode 
wxThread::Wait() 
 674     // although under MacOS we can wait for any thread, it's an error to 
 675     // wait for a detached one in wxWin API 
 676     wxCHECK_MSG( !IsDetached(), (ExitCode
)-1, 
 677                  _T("can't wait for detached thread") ); 
 679     ExitCode rc 
= (ExitCode
)-1; 
 688 wxThreadError 
wxThread::Delete(ExitCode 
*pRc
) 
 692     // Delete() is always safe to call, so consider all possible states 
 694     // has the thread started to run? 
 695     bool shouldResume 
= FALSE
; 
 698         wxCriticalSectionLocker 
lock(m_critsect
); 
 700         if ( m_internal
->GetState() == STATE_NEW 
) 
 702             // WinThreadStart() will see it and terminate immediately 
 703             m_internal
->SetState(STATE_EXITED
); 
 709     // is the thread paused? 
 710     if ( shouldResume 
|| IsPaused() ) 
 713     // does is still run? 
 718             // set flag for wxIsWaitingForThread() 
 719             gs_waitingForThread 
= TRUE
; 
 726         // ask the thread to terminate 
 728             wxCriticalSectionLocker 
lock(m_critsect
); 
 730             m_internal
->Cancel(); 
 734         // simply wait for the thread to terminate 
 735         while( TestDestroy() ) 
 737             ::YieldToAnyThread() ; 
 740         // simply wait for the thread to terminate 
 741         while( TestDestroy() ) 
 743             ::YieldToAnyThread() ; 
 745 #endif // wxUSE_GUI/!wxUSE_GUI 
 749             gs_waitingForThread 
= FALSE
; 
 759         // if the thread exits normally, this is done in WinThreadStart, but in 
 760         // this case it would have been too early because 
 761         // MsgWaitForMultipleObject() would fail if the therad handle was 
 762         // closed while we were waiting on it, so we must do it here 
 769     return rc 
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR 
: wxTHREAD_NO_ERROR
; 
 772 wxThreadError 
wxThread::Kill() 
 775         return wxTHREAD_NOT_RUNNING
; 
 777 //    if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) ) 
 779         wxLogSysError(_("Couldn't terminate thread")); 
 781         return wxTHREAD_MISC_ERROR
; 
 791     return wxTHREAD_NO_ERROR
; 
 794 void wxThread::Exit(ExitCode status
) 
 803     m_internal
->SetResult( status 
) ; 
 806 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) 
 807     _endthreadex((unsigned)status); 
 809     ::ExitThread((DWORD)status); 
 812     wxFAIL_MSG(wxT("Couldn't return from ExitThread()!")); 
 818 // since all these calls are execute cooperatively we don't have to use the critical section 
 820 void wxThread::SetPriority(unsigned int prio
) 
 822     m_internal
->SetPriority(prio
); 
 825 unsigned int wxThread::GetPriority() const 
 827     return m_internal
->GetPriority(); 
 830 unsigned long wxThread::GetId() const 
 832     return (unsigned long)m_internal
->GetId(); 
 835 bool wxThread::IsRunning() const 
 837     return m_internal
->GetState() == STATE_RUNNING
; 
 840 bool wxThread::IsAlive() const 
 842     return (m_internal
->GetState() == STATE_RUNNING
) || 
 843            (m_internal
->GetState() == STATE_PAUSED
); 
 846 bool wxThread::IsPaused() const 
 848     return m_internal
->GetState() == STATE_PAUSED
; 
 851 bool wxThread::TestDestroy() 
 853     return m_internal
->GetState() == STATE_CANCELED
; 
 856 // ---------------------------------------------------------------------------- 
 857 // Automatic initialization for thread module 
 858 // ---------------------------------------------------------------------------- 
 860 class wxThreadModule 
: public wxModule
 
 863     virtual bool OnInit(); 
 864     virtual void OnExit(); 
 867     DECLARE_DYNAMIC_CLASS(wxThreadModule
) 
 870 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
) 
 872 bool wxThreadModule::OnInit() 
 875     bool hasThreadManager 
; 
 876     hasThreadManager 
= Gestalt( gestaltThreadMgrAttr
, &response
) == noErr 
&& response 
& 1; 
 879     // verify presence of shared library 
 880     hasThreadManager 
= hasThreadManager 
&& ((Ptr
)NewThread 
!= (Ptr
)kUnresolvedCFragSymbolAddress
); 
 883     if ( !hasThreadManager 
) 
 885         wxLogSysError( wxT("Thread Support is not available on this System") ); 
 889     // no error return for GetCurrentThreadId() 
 890     MacGetCurrentThread( &gs_idMainThread 
) ; 
 895 void wxThreadModule::OnExit() 
 899 // ---------------------------------------------------------------------------- 
 900 // under MacOS we don't have currently preemptive threads, so any thread may access 
 901 // the GUI at any time 
 902 // ---------------------------------------------------------------------------- 
 904 void WXDLLEXPORT 
wxMutexGuiEnter() 
 908 void WXDLLEXPORT 
wxMutexGuiLeave() 
 912 void WXDLLEXPORT 
wxMutexGuiLeaveOrEnter() 
 916 bool WXDLLEXPORT 
wxGuiOwnedByMainThread() 
 921 // wake up the main thread 
 922 void WXDLLEXPORT 
wxWakeUpMainThread() 
 927 bool WXDLLEXPORT 
wxIsWaitingForThread() 
 932 #include "wx/thrimpl.cpp" 
 934 #endif // wxUSE_THREADS