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 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "thread.h"
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/module.h"
31 #include "wx/thread.h"
33 #define INCL_DOSSEMAPHORES
34 #define INCL_DOSPROCESS
40 // the possible states of the thread ("=>" shows all possible transitions from
44 STATE_NEW
, // didn't start execution yet (=> RUNNING)
45 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
46 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
47 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
48 STATE_EXITED
// thread is terminating
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 // id of the main thread - the one which can call GUI functions without first
56 // calling wxMutexGuiEnter()
57 static ULONG s_ulIdMainThread
= 0;
58 wxMutex
* p_wxMainMutex
;
60 // OS2 substitute for Tls pointer the current parent thread object
61 wxThread
* m_pThread
; // pointer to the wxWindows thread object
63 // if it's FALSE, some secondary thread is holding the GUI lock
64 static bool gs_bGuiOwnedByMainThread
= TRUE
;
66 // critical section which controls access to all GUI functions: any secondary
67 // thread (i.e. except the main one) must enter this crit section before doing
69 static wxCriticalSection
*gs_pCritsectGui
= NULL
;
71 // critical section which protects s_nWaitingForGui variable
72 static wxCriticalSection
*gs_pCritsectWaitingForGui
= NULL
;
74 // number of threads waiting for GUI in wxMutexGuiEnter()
75 static size_t gs_nWaitingForGui
= 0;
77 // are we waiting for a thread termination?
78 static bool gs_bWaitingForThread
= FALSE
;
80 // ============================================================================
81 // OS/2 implementation of thread classes
82 // ============================================================================
84 // ----------------------------------------------------------------------------
85 // wxMutex implementation
86 // ----------------------------------------------------------------------------
94 wxMutexType eMutexType
99 m_internal
= new wxMutexInternal
;
100 ulrc
= ::DosCreateMutexSem(NULL
, &m_internal
->m_vMutex
, 0L, FALSE
);
103 wxLogSysError(_("Can not create mutex."));
109 ::DosCloseMutexSem(m_internal
->m_vMutex
);
110 m_internal
->m_vMutex
= NULL
;
113 wxMutexError
wxMutex::Lock()
117 ulrc
= ::DosRequestMutexSem(m_internal
->m_vMutex
, SEM_INDEFINITE_WAIT
);
121 case ERROR_TOO_MANY_SEM_REQUESTS
:
128 case ERROR_INVALID_HANDLE
:
129 case ERROR_INTERRUPT
:
130 case ERROR_SEM_OWNER_DIED
:
131 wxLogSysError(_("Couldn't acquire a mutex lock"));
132 return wxMUTEX_MISC_ERROR
;
136 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
138 return wxMUTEX_NO_ERROR
;
141 wxMutexError
wxMutex::TryLock()
145 ulrc
= ::DosRequestMutexSem(m_internal
->m_vMutex
, SEM_IMMEDIATE_RETURN
/*0L*/);
146 if (ulrc
== ERROR_TIMEOUT
|| ulrc
== ERROR_TOO_MANY_SEM_REQUESTS
)
149 return wxMUTEX_NO_ERROR
;
152 wxMutexError
wxMutex::Unlock()
156 ulrc
= ::DosReleaseMutexSem(m_internal
->m_vMutex
);
159 wxLogSysError(_("Couldn't release a mutex"));
160 return wxMUTEX_MISC_ERROR
;
162 return wxMUTEX_NO_ERROR
;
165 // ----------------------------------------------------------------------------
166 // wxCondition implementation
167 // ----------------------------------------------------------------------------
169 class wxConditionInternal
172 inline wxConditionInternal (wxMutex
& rMutex
) : m_vMutex(rMutex
)
174 ::DosCreateEventSem(NULL
, &m_vEvent
, DC_SEM_SHARED
, FALSE
);
177 wxLogSysError(_("Can not create event semaphore."));
183 unsigned long ulTimeout
189 ulrc
= ::DosWaitEventSem(m_vEvent
, ulTimeout
);
194 inline ~wxConditionInternal ()
200 ulrc
= ::DosCloseEventSem(m_vEvent
);
203 wxLogLastError("DosCloseEventSem(m_vEvent)");
213 wxCondition::wxCondition(wxMutex
& rMutex
)
218 m_internal
= new wxConditionInternal(rMutex
);
219 ulrc
= ::DosCreateEventSem(NULL
, &m_internal
->m_vEvent
, 0L, FALSE
);
222 wxLogSysError(_("Can not create event object."));
224 m_internal
->m_nWaiters
= 0;
225 // ?? just for good measure?
226 ::DosResetEventSem(m_internal
->m_vEvent
, &ulCount
);
229 wxCondition::~wxCondition()
231 ::DosCloseEventSem(m_internal
->m_vEvent
);
236 wxCondError
wxCondition::Wait()
238 APIRET rc
= m_internal
->Wait(SEM_INDEFINITE_WAIT
);
243 return wxCOND_NO_ERROR
;
244 case ERROR_INVALID_HANDLE
:
245 return wxCOND_INVALID
;
247 return wxCOND_TIMEOUT
;
249 return wxCOND_MISC_ERROR
;
253 wxCondError
wxCondition::WaitTimeout(
254 unsigned long lMilliSec
257 APIRET rc
= m_internal
->Wait(lMilliSec
);
262 return wxCOND_NO_ERROR
;
263 case ERROR_INVALID_HANDLE
:
264 return wxCOND_INVALID
;
266 return wxCOND_TIMEOUT
;
268 return wxCOND_MISC_ERROR
;
272 wxCondError
wxCondition::Signal()
274 APIRET rc
= ::DosPostEventSem(m_internal
->m_vEvent
);
279 return wxCOND_NO_ERROR
;
280 case ERROR_INVALID_HANDLE
:
281 return wxCOND_INVALID
;
283 return wxCOND_MISC_ERROR
;
287 wxCondError
wxCondition::Broadcast()
290 APIRET rc
= NO_ERROR
;
292 for (i
= 0; i
< m_internal
->m_nWaiters
; i
++)
294 if ((rc
= ::DosPostEventSem(m_internal
->m_vEvent
)) != NO_ERROR
)
296 wxLogSysError(_("Couldn't change the state of event object."));
304 return wxCOND_NO_ERROR
;
305 case ERROR_INVALID_HANDLE
:
306 return wxCOND_INVALID
;
308 return wxCOND_MISC_ERROR
;
312 // ----------------------------------------------------------------------------
313 // wxCriticalSection implementation
314 // ----------------------------------------------------------------------------
316 wxCriticalSection::wxCriticalSection()
320 wxCriticalSection::~wxCriticalSection()
324 void wxCriticalSection::Enter()
329 void wxCriticalSection::Leave()
334 // ----------------------------------------------------------------------------
335 // wxThread implementation
336 // ----------------------------------------------------------------------------
338 // wxThreadInternal class
339 // ----------------------
341 class wxThreadInternal
344 inline wxThreadInternal()
347 m_eState
= STATE_NEW
;
365 // create a new (suspended) thread (for the given thread object)
366 bool Create( wxThread
* pThread
367 ,unsigned int uStackSize
370 // suspend/resume/terminate
373 inline void Cancel() { m_eState
= STATE_CANCELED
; }
376 inline void SetState(wxThreadState eState
) { m_eState
= eState
; }
377 inline wxThreadState
GetState() const { return m_eState
; }
380 void SetPriority(unsigned int nPriority
);
381 inline unsigned int GetPriority() const { return m_nPriority
; }
383 // thread handle and id
384 inline TID
GetHandle() const { return m_hThread
; }
385 TID
GetId() const { return m_hThread
; }
388 static DWORD
OS2ThreadStart(wxThread
*thread
);
391 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
392 // PM also has no real Tls mechanism to index pointers by so we'll just
393 // keep track of the wxWindows parent object here.
394 TID m_hThread
; // handle and ID of the thread
395 wxThreadState m_eState
; // state, see wxThreadState enum
396 unsigned int m_nPriority
; // thread priority in "wx" units
399 ULONG
wxThreadInternal::OS2ThreadStart(
405 DWORD dwRet
= (DWORD
)pThread
->Entry();
407 // enter m_critsect before changing the thread state
408 pThread
->m_critsect
.Enter();
410 bool bWasCancelled
= pThread
->m_internal
->GetState() == STATE_CANCELED
;
412 pThread
->m_internal
->SetState(STATE_EXITED
);
413 pThread
->m_critsect
.Leave();
417 // if the thread was cancelled (from Delete()), then it the handle is still
419 if (pThread
->IsDetached() && !bWasCancelled
)
424 //else: the joinable threads handle will be closed when Wait() is done
428 void wxThreadInternal::SetPriority(
429 unsigned int nPriority
432 // translate wxWindows priority to the PM one
433 ULONG ulOS2_Priority
;
436 m_nPriority
= nPriority
;
438 if (m_nPriority
<= 20)
439 ulOS2_Priority
= PRTYC_NOCHANGE
;
440 else if (m_nPriority
<= 40)
441 ulOS2_Priority
= PRTYC_IDLETIME
;
442 else if (m_nPriority
<= 60)
443 ulOS2_Priority
= PRTYC_REGULAR
;
444 else if (m_nPriority
<= 80)
445 ulOS2_Priority
= PRTYC_TIMECRITICAL
;
446 else if (m_nPriority
<= 100)
447 ulOS2_Priority
= PRTYC_FOREGROUNDSERVER
;
450 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
451 ulOS2_Priority
= PRTYC_REGULAR
;
453 ulrc
= ::DosSetPriority( PRTYS_THREAD
460 wxLogSysError(_("Can't set thread priority"));
464 bool wxThreadInternal::Create(
466 , unsigned int uStackSize
471 ulrc
= ::DosCreateThread( &m_hThread
472 ,(PFNTHREAD
)wxThreadInternal::OS2ThreadStart
474 ,CREATE_SUSPENDED
| STACK_SPARSE
479 wxLogSysError(_("Can't create thread"));
483 if (m_nPriority
!= WXTHREAD_DEFAULT_PRIORITY
)
485 SetPriority(m_nPriority
);
488 m_eState
= STATE_NEW
;
493 bool wxThreadInternal::Suspend()
495 ULONG ulrc
= ::DosSuspendThread(m_hThread
);
499 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
502 m_eState
= STATE_PAUSED
;
506 bool wxThreadInternal::Resume()
508 ULONG ulrc
= ::DosResumeThread(m_hThread
);
512 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
515 m_eState
= STATE_PAUSED
;
522 wxThread
*wxThread::This()
524 wxThread
* pThread
= m_pThread
;
528 bool wxThread::IsMain()
533 ::DosGetInfoBlocks(&ptib
, &ppib
);
535 if (ptib
->tib_ptib2
->tib2_ultid
== s_ulIdMainThread
)
544 void wxThread::Yield()
549 void wxThread::Sleep(
550 unsigned long ulMilliseconds
553 ::DosSleep(ulMilliseconds
);
559 wxThread::wxThread(wxThreadKind kind
)
561 m_internal
= new wxThreadInternal();
563 m_isDetached
= kind
== wxTHREAD_DETACHED
;
566 wxThread::~wxThread()
571 // create/start thread
572 // -------------------
574 wxThreadError
wxThread::Create(
575 unsigned int uStackSize
578 if ( !m_internal
->Create(this, uStackSize
) )
579 return wxTHREAD_NO_RESOURCE
;
581 return wxTHREAD_NO_ERROR
;
584 wxThreadError
wxThread::Run()
586 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
588 if ( m_internal
->GetState() != STATE_NEW
)
590 // actually, it may be almost any state at all, not only STATE_RUNNING
591 return wxTHREAD_RUNNING
;
596 // suspend/resume thread
597 // ---------------------
599 wxThreadError
wxThread::Pause()
601 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
603 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
606 wxThreadError
wxThread::Resume()
608 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
610 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
616 wxThread::ExitCode
wxThread::Wait()
618 // although under Windows we can wait for any thread, it's an error to
619 // wait for a detached one in wxWin API
620 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
621 _T("can't wait for detached thread") );
622 ExitCode rc
= (ExitCode
)-1;
628 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
632 // Delete() is always safe to call, so consider all possible states
636 TID hThread
= m_internal
->GetHandle();
642 // set flag for wxIsWaitingForThread()
643 gs_bWaitingForThread
= TRUE
;
650 // ask the thread to terminate
652 wxCriticalSectionLocker
lock(m_critsect
);
653 m_internal
->Cancel();
657 // need a way to finish GUI processing before killing the thread
658 // until then we just exit
660 if ((gs_nWaitingForGui
> 0) && wxGuiOwnedByMainThread())
666 // can't wait for yourself to end under OS/2 so just quit
668 #endif // wxUSE_GUI/!wxUSE_GUI
672 gs_bWaitingForThread
= FALSE
;
681 // probably won't get this far, but
690 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
693 wxThreadError
wxThread::Kill()
696 return wxTHREAD_NOT_RUNNING
;
698 ::DosKillThread(m_internal
->GetHandle());
704 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 unsigned long wxThread::GetId() const
735 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
737 return (unsigned long)m_internal
->GetId();
740 bool wxThread::IsRunning() const
742 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
744 return(m_internal
->GetState() == STATE_RUNNING
);
747 bool wxThread::IsAlive() const
749 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
751 return (m_internal
->GetState() == STATE_RUNNING
) ||
752 (m_internal
->GetState() == STATE_PAUSED
);
755 bool wxThread::IsPaused() const
757 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
759 return (m_internal
->GetState() == STATE_PAUSED
);
762 bool wxThread::TestDestroy()
764 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
766 return m_internal
->GetState() == STATE_CANCELED
;
769 // ----------------------------------------------------------------------------
770 // Automatic initialization for thread module
771 // ----------------------------------------------------------------------------
773 class wxThreadModule
: public wxModule
776 virtual bool OnInit();
777 virtual void OnExit();
780 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
783 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
785 bool wxThreadModule::OnInit()
787 gs_pCritsectWaitingForGui
= new wxCriticalSection();
789 gs_pCritsectGui
= new wxCriticalSection();
790 gs_pCritsectGui
->Enter();
795 ::DosGetInfoBlocks(&ptib
, &ppib
);
797 s_ulIdMainThread
= ptib
->tib_ptib2
->tib2_ultid
;
801 void wxThreadModule::OnExit()
805 gs_pCritsectGui
->Leave();
806 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
807 delete gs_pCritsectGui
;
809 gs_pCritsectGui
= NULL
;
812 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
813 wxDELETE(gs_pCritsectWaitingForGui
);
817 // ----------------------------------------------------------------------------
819 // ----------------------------------------------------------------------------
821 // Does nothing under OS/2 [for now]
822 void WXDLLEXPORT
wxWakeUpMainThread()
826 void WXDLLEXPORT
wxMutexGuiLeave()
828 wxCriticalSectionLocker
enter(*gs_pCritsectWaitingForGui
);
830 if ( wxThread::IsMain() )
832 gs_bGuiOwnedByMainThread
= FALSE
;
836 // decrement the number of waiters now
837 wxASSERT_MSG(gs_nWaitingForGui
> 0,
838 wxT("calling wxMutexGuiLeave() without entering it first?") );
842 wxWakeUpMainThread();
845 gs_pCritsectGui
->Leave();
848 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
850 wxASSERT_MSG( wxThread::IsMain(),
851 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
853 wxCriticalSectionLocker
enter(*gs_pCritsectWaitingForGui
);
855 if (gs_nWaitingForGui
== 0)
857 // no threads are waiting for GUI - so we may acquire the lock without
858 // any danger (but only if we don't already have it)
859 if (!wxGuiOwnedByMainThread())
861 gs_pCritsectGui
->Enter();
863 gs_bGuiOwnedByMainThread
= TRUE
;
865 //else: already have it, nothing to do
869 // some threads are waiting, release the GUI lock if we have it
870 if (wxGuiOwnedByMainThread())
874 //else: some other worker thread is doing GUI
878 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
880 return gs_bGuiOwnedByMainThread
;
883 bool WXDLLEXPORT
wxIsWaitingForThread()
885 return gs_bWaitingForThread
;