1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxThread Implementation. For Unix ports, see e.g. src/gtk 
   4 // Author:      Original from Wolfram Gloger/Guilhem Lavaux 
   5 // Modified by: David Webster 
   8 // Copyright:   (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998) 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ---------------------------------------------------------------------------- 
  14 // ---------------------------------------------------------------------------- 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  23 #include "wx/module.h" 
  24 #include "wx/thread.h" 
  26 #define INCL_DOSSEMAPHORES 
  27 #define INCL_DOSPROCESS 
  32 // the possible states of the thread ("=>" shows all possible transitions from 
  36     STATE_NEW
,          // didn't start execution yet (=> RUNNING) 
  37     STATE_RUNNING
,      // thread is running (=> PAUSED, CANCELED) 
  38     STATE_PAUSED
,       // thread is temporarily suspended (=> RUNNING) 
  39     STATE_CANCELED
,     // thread should terminate a.s.a.p. (=> EXITED) 
  40     STATE_EXITED        
// thread is terminating 
  43 // ---------------------------------------------------------------------------- 
  45 // ---------------------------------------------------------------------------- 
  47 // id of the main thread - the one which can call GUI functions without first 
  48 // calling wxMutexGuiEnter() 
  49 static ULONG                        s_ulIdMainThread 
= 0; 
  50 wxMutex
*                            p_wxMainMutex
; 
  52 // OS2 substitute for Tls pointer the current parent thread object 
  53 wxThread
*                           m_pThread
;    // pointer to the wxWindows thread object 
  55 // if it's FALSE, some secondary thread is holding the GUI lock 
  56 static bool gs_bGuiOwnedByMainThread 
= TRUE
; 
  58 // critical section which controls access to all GUI functions: any secondary 
  59 // thread (i.e. except the main one) must enter this crit section before doing 
  61 static wxCriticalSection 
*gs_pCritsectGui 
= NULL
; 
  63 // critical section which protects s_nWaitingForGui variable 
  64 static wxCriticalSection 
*gs_pCritsectWaitingForGui 
= NULL
; 
  66 // number of threads waiting for GUI in wxMutexGuiEnter() 
  67 static size_t gs_nWaitingForGui 
= 0; 
  69 // are we waiting for a thread termination? 
  70 static bool gs_bWaitingForThread 
= FALSE
; 
  72 // ============================================================================ 
  73 // OS/2 implementation of thread classes 
  74 // ============================================================================ 
  76 // ---------------------------------------------------------------------------- 
  77 // wxMutex implementation 
  78 // ---------------------------------------------------------------------------- 
  89     m_internal 
= new wxMutexInternal
; 
  90     ulrc 
= ::DosCreateMutexSem(NULL
, &m_internal
->m_vMutex
, 0L, FALSE
); 
  93         wxLogSysError(_("Can not create mutex.")); 
 101         wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked
); 
 102     ::DosCloseMutexSem(m_internal
->m_vMutex
); 
 103     m_internal
->m_vMutex 
= NULL
; 
 106 wxMutexError 
wxMutex::Lock() 
 110     ulrc 
= ::DosRequestMutexSem(m_internal
->m_vMutex
, SEM_INDEFINITE_WAIT
); 
 114         case ERROR_TOO_MANY_SEM_REQUESTS
: 
 121         case ERROR_INVALID_HANDLE
: 
 122         case ERROR_INTERRUPT
: 
 123         case ERROR_SEM_OWNER_DIED
: 
 124             wxLogSysError(_("Couldn't acquire a mutex lock")); 
 125             return wxMUTEX_MISC_ERROR
; 
 129             wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock")); 
 132     return wxMUTEX_NO_ERROR
; 
 135 wxMutexError 
wxMutex::TryLock() 
 139     ulrc 
= ::DosRequestMutexSem(m_internal
->m_vMutex
, SEM_IMMEDIATE_RETURN 
/*0L*/); 
 140     if (ulrc 
== ERROR_TIMEOUT 
|| ulrc 
== ERROR_TOO_MANY_SEM_REQUESTS
) 
 144     return wxMUTEX_NO_ERROR
; 
 147 wxMutexError 
wxMutex::Unlock() 
 154     ulrc 
= ::DosReleaseMutexSem(m_internal
->m_vMutex
); 
 157         wxLogSysError(_("Couldn't release a mutex")); 
 158         return wxMUTEX_MISC_ERROR
; 
 160     return wxMUTEX_NO_ERROR
; 
 163 // ---------------------------------------------------------------------------- 
 164 // wxCondition implementation 
 165 // ---------------------------------------------------------------------------- 
 167 class wxConditionInternal
 
 170     inline wxConditionInternal () 
 172         ::DosCreateEventSem(NULL
, &m_vEvent
, DC_SEM_SHARED
, FALSE
); 
 175             wxLogSysError(_("Can not create event semaphore.")); 
 181       unsigned long                 ulTimeout
 
 187         ulrc 
= ::DosWaitEventSem(m_vEvent
, ulTimeout
); 
 189         return (ulrc 
!= ERROR_TIMEOUT
); 
 192     inline ~wxConditionInternal () 
 198             ulrc 
= ::DosCloseEventSem(m_vEvent
); 
 201                 wxLogLastError("DosCloseEventSem(m_vEvent)"); 
 210 wxCondition::wxCondition() 
 215     m_internal 
= new wxConditionInternal
; 
 216     ulrc 
= ::DosCreateEventSem(NULL
, &m_internal
->m_vEvent
, 0L, FALSE
); 
 219         wxLogSysError(_("Can not create event object.")); 
 221     m_internal
->m_nWaiters 
= 0; 
 222     // ?? just for good measure? 
 223     ::DosResetEventSem(m_internal
->m_vEvent
, &ulCount
); 
 226 wxCondition::~wxCondition() 
 228     ::DosCloseEventSem(m_internal
->m_vEvent
); 
 233 void wxCondition::Wait() 
 235     (void)m_internal
->Wait(SEM_INDEFINITE_WAIT
); 
 238 bool wxCondition::Wait( 
 240 , unsigned long                     lNsec
) 
 242     return m_internal
->Wait(lSec
*1000 + lNsec
/1000000); 
 245 void wxCondition::Signal() 
 247     ::DosPostEventSem(m_internal
->m_vEvent
); 
 250 void wxCondition::Broadcast() 
 254     for (i 
= 0; i 
< m_internal
->m_nWaiters
; i
++) 
 256         if (::DosPostEventSem(m_internal
->m_vEvent
) != 0) 
 258             wxLogSysError(_("Couldn't change the state of event object.")); 
 263 // ---------------------------------------------------------------------------- 
 264 // wxCriticalSection implementation 
 265 // ---------------------------------------------------------------------------- 
 267 wxCriticalSection::wxCriticalSection() 
 271 wxCriticalSection::~wxCriticalSection() 
 275 void wxCriticalSection::Enter() 
 280 void wxCriticalSection::Leave() 
 285 // ---------------------------------------------------------------------------- 
 286 // wxThread implementation 
 287 // ---------------------------------------------------------------------------- 
 289 // wxThreadInternal class 
 290 // ---------------------- 
 292 class wxThreadInternal
 
 295     inline wxThreadInternal() 
 298         m_eState 
= STATE_NEW
; 
 316     // create a new (suspended) thread (for the given thread object) 
 317     bool Create(wxThread
* pThread
); 
 319     // suspend/resume/terminate 
 322     inline void Cancel() { m_eState 
= STATE_CANCELED
; } 
 325     inline void SetState(wxThreadState eState
) { m_eState 
= eState
; } 
 326     inline wxThreadState 
GetState() const { return m_eState
; } 
 329     void                SetPriority(unsigned int nPriority
); 
 330     inline unsigned int GetPriority() const { return m_nPriority
; } 
 332     // thread handle and id 
 333     inline TID 
GetHandle() const { return m_hThread
; } 
 334     TID  
GetId() const { return m_hThread
; } 
 337     static DWORD 
OS2ThreadStart(wxThread 
*thread
); 
 340     // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID 
 341     // PM also has no real Tls mechanism to index pointers by so we'll just 
 342     // keep track of the wxWindows parent object here. 
 343     TID                             m_hThread
;    // handle and ID of the thread 
 344     wxThreadState                   m_eState
;     // state, see wxThreadState enum 
 345     unsigned int                    m_nPriority
;  // thread priority in "wx" units 
 348 ULONG 
wxThreadInternal::OS2ThreadStart( 
 354     DWORD                           dwRet 
= (DWORD
)pThread
->Entry(); 
 356     // enter m_critsect before changing the thread state 
 357     pThread
->m_critsect
.Enter(); 
 359     bool                            bWasCancelled 
= pThread
->m_internal
->GetState() == STATE_CANCELED
; 
 361     pThread
->m_internal
->SetState(STATE_EXITED
); 
 362     pThread
->m_critsect
.Leave(); 
 366     // if the thread was cancelled (from Delete()), then it the handle is still 
 368     if (pThread
->IsDetached() && !bWasCancelled
) 
 373     //else: the joinable threads handle will be closed when Wait() is done 
 377 void wxThreadInternal::SetPriority( 
 378   unsigned int                      nPriority
 
 381     // translate wxWindows priority to the PM one 
 382     ULONG                           ulOS2_Priority
; 
 385     m_nPriority 
= nPriority
; 
 387     if (m_nPriority 
<= 20) 
 388         ulOS2_Priority 
= PRTYC_NOCHANGE
; 
 389     else if (m_nPriority 
<= 40) 
 390         ulOS2_Priority 
= PRTYC_IDLETIME
; 
 391     else if (m_nPriority 
<= 60) 
 392         ulOS2_Priority 
= PRTYC_REGULAR
; 
 393     else if (m_nPriority 
<= 80) 
 394         ulOS2_Priority 
= PRTYC_TIMECRITICAL
; 
 395     else if (m_nPriority 
<= 100) 
 396         ulOS2_Priority 
= PRTYC_FOREGROUNDSERVER
; 
 399         wxFAIL_MSG(wxT("invalid value of thread priority parameter")); 
 400         ulOS2_Priority 
= PRTYC_REGULAR
; 
 402     ulrc 
= ::DosSetPriority( PRTYS_THREAD
 
 409         wxLogSysError(_("Can't set thread priority")); 
 413 bool wxThreadInternal::Create( 
 419     ulrc 
= ::DosCreateThread( &m_hThread
 
 420                              ,(PFNTHREAD
)wxThreadInternal::OS2ThreadStart
 
 422                              ,CREATE_SUSPENDED 
| STACK_SPARSE
 
 427         wxLogSysError(_("Can't create thread")); 
 431     if (m_nPriority 
!= WXTHREAD_DEFAULT_PRIORITY
) 
 433         SetPriority(m_nPriority
); 
 438 bool wxThreadInternal::Suspend() 
 440     ULONG                           ulrc 
= ::DosSuspendThread(m_hThread
); 
 444         wxLogSysError(_("Can not suspend thread %lu"), m_hThread
); 
 447     m_eState 
= STATE_PAUSED
; 
 451 bool wxThreadInternal::Resume() 
 453     ULONG                           ulrc 
= ::DosResumeThread(m_hThread
); 
 457         wxLogSysError(_("Can not suspend thread %lu"), m_hThread
); 
 460     m_eState 
= STATE_PAUSED
; 
 467 wxThread 
*wxThread::This() 
 469     wxThread
*                       pThread 
= m_pThread
; 
 473 bool wxThread::IsMain() 
 478     ::DosGetInfoBlocks(&ptib
, &ppib
); 
 480     if (ptib
->tib_ptib2
->tib2_ultid 
== s_ulIdMainThread
) 
 489 void wxThread::Yield() 
 494 void wxThread::Sleep( 
 495   unsigned long                     ulMilliseconds
 
 498     ::DosSleep(ulMilliseconds
); 
 504 wxThread::wxThread(wxThreadKind kind
) 
 506     m_internal 
= new wxThreadInternal(); 
 508     m_isDetached 
= kind 
== wxTHREAD_DETACHED
; 
 511 wxThread::~wxThread() 
 516 // create/start thread 
 517 // ------------------- 
 519 wxThreadError 
wxThread::Create() 
 521     if ( !m_internal
->Create(this) ) 
 522         return wxTHREAD_NO_RESOURCE
; 
 524     return wxTHREAD_NO_ERROR
; 
 527 wxThreadError 
wxThread::Run() 
 529     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 531     if ( m_internal
->GetState() != STATE_NEW 
) 
 533         // actually, it may be almost any state at all, not only STATE_RUNNING 
 534         return wxTHREAD_RUNNING
; 
 539 // suspend/resume thread 
 540 // --------------------- 
 542 wxThreadError 
wxThread::Pause() 
 544     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 546     return m_internal
->Suspend() ? wxTHREAD_NO_ERROR 
: wxTHREAD_MISC_ERROR
; 
 549 wxThreadError 
wxThread::Resume() 
 551     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 553     return m_internal
->Resume() ? wxTHREAD_NO_ERROR 
: wxTHREAD_MISC_ERROR
; 
 559 wxThread::ExitCode 
wxThread::Wait() 
 561     // although under Windows we can wait for any thread, it's an error to 
 562     // wait for a detached one in wxWin API 
 563     wxCHECK_MSG( !IsDetached(), (ExitCode
)-1, 
 564                  _T("can't wait for detached thread") ); 
 565     ExitCode rc 
= (ExitCode
)-1; 
 571 wxThreadError 
wxThread::Delete(ExitCode 
*pRc
) 
 575     // Delete() is always safe to call, so consider all possible states 
 579     TID                             hThread 
= m_internal
->GetHandle(); 
 585             // set flag for wxIsWaitingForThread() 
 586             gs_bWaitingForThread 
= TRUE
; 
 593         // ask the thread to terminate 
 595             wxCriticalSectionLocker 
lock(m_critsect
); 
 596             m_internal
->Cancel(); 
 600         // need a way to finish GUI processing before killing the thread 
 601         // until then we just exit 
 603         if ((gs_nWaitingForGui 
> 0) && wxGuiOwnedByMainThread()) 
 609         // can't wait for yourself to end under OS/2 so just quit 
 611 #endif // wxUSE_GUI/!wxUSE_GUI 
 615             gs_bWaitingForThread 
= FALSE
; 
 624     // probably won't get this far, but 
 633     return rc 
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR 
: wxTHREAD_NO_ERROR
; 
 636 wxThreadError 
wxThread::Kill() 
 639         return wxTHREAD_NOT_RUNNING
; 
 641     ::DosKillThread(m_internal
->GetHandle()); 
 647     return wxTHREAD_NO_ERROR
; 
 656     ::DosExit(EXIT_THREAD
, ULONG(pStatus
)); 
 657     wxFAIL_MSG(wxT("Couldn't return from DosExit()!")); 
 660 void wxThread::SetPriority( 
 664     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 666     m_internal
->SetPriority(nPrio
); 
 669 unsigned int wxThread::GetPriority() const 
 671     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 673     return m_internal
->GetPriority(); 
 676 unsigned long wxThread::GetId() const 
 678     wxCriticalSectionLocker 
lock((wxCriticalSection 
&)m_critsect
); // const_cast 
 680     return (unsigned long)m_internal
->GetId(); 
 683 bool wxThread::IsRunning() const 
 685     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 687     return(m_internal
->GetState() == STATE_RUNNING
); 
 690 bool wxThread::IsAlive() const 
 692     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 694     return (m_internal
->GetState() == STATE_RUNNING
) || 
 695            (m_internal
->GetState() == STATE_PAUSED
); 
 698 bool wxThread::IsPaused() const 
 700     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 702     return (m_internal
->GetState() == STATE_PAUSED
); 
 705 bool wxThread::TestDestroy() 
 707     wxCriticalSectionLocker         
lock((wxCriticalSection 
&)m_critsect
); 
 709     return m_internal
->GetState() == STATE_CANCELED
; 
 712 // ---------------------------------------------------------------------------- 
 713 // Automatic initialization for thread module 
 714 // ---------------------------------------------------------------------------- 
 716 class wxThreadModule 
: public wxModule
 
 719     virtual bool OnInit(); 
 720     virtual void OnExit(); 
 723     DECLARE_DYNAMIC_CLASS(wxThreadModule
) 
 726 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
) 
 728 bool wxThreadModule::OnInit() 
 730     gs_pCritsectWaitingForGui 
= new wxCriticalSection(); 
 732     gs_pCritsectGui 
= new wxCriticalSection(); 
 733     gs_pCritsectGui
->Enter(); 
 738     ::DosGetInfoBlocks(&ptib
, &ppib
); 
 740     s_ulIdMainThread 
= ptib
->tib_ptib2
->tib2_ultid
; 
 744 void wxThreadModule::OnExit() 
 748         gs_pCritsectGui
->Leave(); 
 749 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ))) 
 750         delete gs_pCritsectGui
; 
 752         gs_pCritsectGui 
= NULL
; 
 755 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ))) 
 756     wxDELETE(gs_pCritsectWaitingForGui
); 
 760 // ---------------------------------------------------------------------------- 
 762 // ---------------------------------------------------------------------------- 
 764 // Does nothing under OS/2 [for now] 
 765 void WXDLLEXPORT 
wxWakeUpMainThread() 
 769 void WXDLLEXPORT 
wxMutexGuiLeave() 
 771     wxCriticalSectionLocker 
enter(*gs_pCritsectWaitingForGui
); 
 773     if ( wxThread::IsMain() ) 
 775         gs_bGuiOwnedByMainThread 
= FALSE
; 
 779         // decrement the number of waiters now 
 780         wxASSERT_MSG(gs_nWaitingForGui 
> 0, 
 781                       wxT("calling wxMutexGuiLeave() without entering it first?") ); 
 785         wxWakeUpMainThread(); 
 788     gs_pCritsectGui
->Leave(); 
 791 void WXDLLEXPORT 
wxMutexGuiLeaveOrEnter() 
 793     wxASSERT_MSG( wxThread::IsMain(), 
 794                   wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); 
 796     wxCriticalSectionLocker 
enter(*gs_pCritsectWaitingForGui
); 
 798     if (gs_nWaitingForGui 
== 0) 
 800         // no threads are waiting for GUI - so we may acquire the lock without 
 801         // any danger (but only if we don't already have it) 
 802         if (!wxGuiOwnedByMainThread()) 
 804             gs_pCritsectGui
->Enter(); 
 806             gs_bGuiOwnedByMainThread 
= TRUE
; 
 808         //else: already have it, nothing to do 
 812         // some threads are waiting, release the GUI lock if we have it 
 813         if (wxGuiOwnedByMainThread()) 
 817         //else: some other worker thread is doing GUI 
 821 bool WXDLLEXPORT 
wxGuiOwnedByMainThread() 
 823     return gs_bGuiOwnedByMainThread
; 
 826 bool WXDLLEXPORT 
wxIsWaitingForThread() 
 828     return gs_bWaitingForThread
;