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 s_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
*s_pCritsectGui
= NULL
;
63 // critical section which protects s_nWaitingForGui variable
64 static wxCriticalSection
*s_pCritsectWaitingForGui
= NULL
;
66 // number of threads waiting for GUI in wxMutexGuiEnter()
67 static size_t s_nWaitingForGui
= 0;
69 // are we waiting for a thread termination?
70 static bool s_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_INFINITE_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
= thread
->m_internal
->GetState() == STATE_CANCELED
;
361 pThread
->m_internal
->SetState(STATE_EXITED
);
362 thread
->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
;
384 m_nPriority
= nPriority
;
386 if (m_nPriority
<= 20)
387 ulOS2_Priority
= PRTYC_NOCHANGE
;
388 else if (m_nPriority
<= 40)
389 ulOS2_Priority
= PRTYC_IDLETIME
;
390 else if (m_nPriority
<= 60)
391 ulOS2_Priority
= PRTYC_REGULAR
;
392 else if (m_nPriority
<= 80)
393 ulOS2_Priority
= PRTYC_TIMECRITICAL
;
394 else if (m_nPriority
<= 100)
395 ulOS2_Priority
= PRTYC_FOREGROUNDSERVER
;
398 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
399 ulOS2_Priority
= PRTYC_REGULAR
;
401 ulrc
= ::DosSetPriority( PRTYS_THREAD
408 wxLogSysError(_("Can't set thread priority"));
412 bool wxThreadInternal::Create(
418 ulrc
= ::DosCreateThread( &m_hThread
419 ,(PFNTHREAD
)wxThreadInternal::OS2ThreadStart
421 ,CREATE_SUSPENDED
| STACK_SPARSE
426 wxLogSysError(_("Can't create thread"));
430 if (m_nPriority
!= WXTHREAD_DEFAULT_PRIORITY
)
432 SetPriority(m_nPriority
);
437 bool wxThreadInternal::Suspend()
439 ULONG ulrc
= ::DosSuspendThread(m_hThread
);
443 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
446 m_eState
= STATE_PAUSED
;
450 bool wxThreadInternal::Resume()
452 ULONG ulrc
= ::DosResumeThread(m_hThread
);
456 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
459 m_eState
= STATE_PAUSED
;
466 wxThread
*wxThread::This()
468 wxThread
* pThread
= m_pThread
;
472 bool wxThread::IsMain()
477 ::DosGetInfoBlocks(&ptib
, &ppib
);
479 if (ptib
->tib_ptib2
->tib2_ultid
== s_ulIdMainThread
)
488 void wxThread::Yield()
493 void wxThread::Sleep(
494 unsigned long ulMilliseconds
497 ::DosSleep(ulMilliseconds
);
503 wxThread::wxThread(wxThreadKind kind
)
505 m_internal
= new wxThreadInternal();
507 m_isDetached
= kind
== wxTHREAD_DETACHED
;
510 wxThread::~wxThread()
515 // create/start thread
516 // -------------------
518 wxThreadError
wxThread::Create()
520 if ( !m_internal
->Create(this) )
521 return wxTHREAD_NO_RESOURCE
;
523 return wxTHREAD_NO_ERROR
;
526 wxThreadError
wxThread::Run()
528 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
530 if ( m_internal
->GetState() != STATE_NEW
)
532 // actually, it may be almost any state at all, not only STATE_RUNNING
533 return wxTHREAD_RUNNING
;
538 // suspend/resume thread
539 // ---------------------
541 wxThreadError
wxThread::Pause()
543 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
545 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
548 wxThreadError
wxThread::Resume()
550 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
552 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
558 wxThread::ExitCode
wxThread::Wait()
560 // although under Windows we can wait for any thread, it's an error to
561 // wait for a detached one in wxWin API
562 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
563 _T("can't wait for detached thread") );
564 ExitCode rc
= (ExitCode
)-1;
570 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
574 // Delete() is always safe to call, so consider all possible states
578 TID hThread
= m_internal
->GetHandle();
584 // set flag for wxIsWaitingForThread()
585 gs_waitingForThread
= TRUE
;
592 // ask the thread to terminate
594 wxCriticalSectionLocker
lock(m_critsect
);
595 m_internal
->Cancel();
599 // we can't just wait for the thread to terminate because it might be
600 // calling some GUI functions and so it will never terminate before we
601 // process the Windows messages that result from these functions
605 ulrc
= ::MsgWaitForMultipleObjects
607 1, // number of objects to wait for
608 &hThread
, // the objects
609 FALSE
, // don't wait for all objects
610 INFINITE
, // no timeout
611 QS_ALLEVENTS
// return as soon as there are any events
618 wxLogSysError(_("Can not wait for thread termination"));
620 return wxTHREAD_KILLED
;
623 // thread we're waiting for terminated
626 case WAIT_OBJECT_0
+ 1:
627 // new message arrived, process it
628 if ( !wxTheApp
->DoMessage() )
630 // WM_QUIT received: kill the thread
633 return wxTHREAD_KILLED
;
638 // give the thread we're waiting for chance to exit
639 // from the GUI call it might have been in
640 if ( (gs_nWaitingForGui
> 0) && wxGuiOwnedByMainThread() )
649 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
651 } while ( result
!= WAIT_OBJECT_0
);
653 // simply wait for the thread to terminate
655 // OTOH, even console apps create windows (in wxExecute, for WinSock
656 // &c), so may be use MsgWaitForMultipleObject() too here?
657 if ( WaitForSingleObject(hThread
, INFINITE
) != WAIT_OBJECT_0
)
659 wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
661 #endif // wxUSE_GUI/!wxUSE_GUI
665 gs_waitingForThread
= FALSE
;
673 if ( !::GetExitCodeThread(hThread
, (LPDWORD
)&rc
) )
675 wxLogLastError("GetExitCodeThread");
682 // if the thread exits normally, this is done in WinThreadStart, but in
683 // this case it would have been too early because
684 // MsgWaitForMultipleObject() would fail if the therad handle was
685 // closed while we were waiting on it, so we must do it here
689 wxASSERT_MSG( (DWORD
)rc
!= STILL_ACTIVE
,
690 wxT("thread must be already terminated.") );
695 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
698 wxThreadError
wxThread::Kill()
701 return wxTHREAD_NOT_RUNNING
;
703 ::DosKillThread(m_internal
->GetHandle());
705 return wxTHREAD_NO_ERROR
;
713 ::DosExit(EXIT_THREAD
, ULONG(pStatus
));
714 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
717 void wxThread::SetPriority(
721 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
723 m_internal
->SetPriority(nPrio
);
726 unsigned int wxThread::GetPriority() const
728 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
730 return m_internal
->GetPriority();
733 bool wxThread::IsRunning() const
735 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
737 return m_internal
->GetState() == STATE_RUNNING
;
740 bool wxThread::IsAlive() const
742 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
744 return (m_internal
->GetState() == STATE_RUNNING
) ||
745 (m_internal
->GetState() == STATE_PAUSED
);
748 bool wxThread::IsPaused() const
750 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
752 return (m_internal
->GetState() == STATE_PAUSED
);
755 bool wxThread::TestDestroy()
757 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
759 return m_internal
->GetState() == STATE_CANCELED
;
762 wxThread::~wxThread()
767 // ----------------------------------------------------------------------------
768 // Automatic initialization for thread module
769 // ----------------------------------------------------------------------------
771 class wxThreadModule
: public wxModule
774 virtual bool OnInit();
775 virtual void OnExit();
778 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
781 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
783 bool wxThreadModule::OnInit()
785 s_pCritsectWaitingForGui
= new wxCriticalSection();
787 s_pCritsectGui
= new wxCriticalSection();
788 s_pCritsectGui
->Enter();
793 ::DosGetInfoBlocks(&ptib
, &ppib
);
795 s_ulIdMainThread
= ptib
->tib_ptib2
->tib2_ultid
;
799 void wxThreadModule::OnExit()
803 s_pCritsectGui
->Leave();
804 delete s_pCritsectGui
;
805 s_pCritsectGui
= NULL
;
808 wxDELETE(s_pCritsectWaitingForGui
);
811 // ----------------------------------------------------------------------------
813 // ----------------------------------------------------------------------------
815 // Does nothing under OS/2 [for now]
816 void WXDLLEXPORT
wxWakeUpMainThread()
820 void WXDLLEXPORT
wxMutexGuiLeave()
822 wxCriticalSectionLocker
enter(*s_pCritsectWaitingForGui
);
824 if ( wxThread::IsMain() )
826 s_bGuiOwnedByMainThread
= FALSE
;
830 // decrement the number of waiters now
831 wxASSERT_MSG( s_nWaitingForGui
> 0,
832 wxT("calling wxMutexGuiLeave() without entering it first?") );
836 wxWakeUpMainThread();
839 s_pCritsectGui
->Leave();
842 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
844 wxASSERT_MSG( wxThread::IsMain(),
845 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
847 wxCriticalSectionLocker
enter(*s_pCritsectWaitingForGui
);
849 if ( s_nWaitingForGui
== 0 )
851 // no threads are waiting for GUI - so we may acquire the lock without
852 // any danger (but only if we don't already have it)
853 if (!wxGuiOwnedByMainThread())
855 s_pCritsectGui
->Enter();
857 s_bGuiOwnedByMainThread
= TRUE
;
859 //else: already have it, nothing to do
863 // some threads are waiting, release the GUI lock if we have it
864 if (wxGuiOwnedByMainThread())
868 //else: some other worker thread is doing GUI
872 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
874 return s_bGuiOwnedByMainThread
;
877 bool WXDLLEXPORT
wxIsWaitingForThread()
879 return s_bWaitingForThread
;