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"
27 #include "wx/thread.h"
29 #define INCL_DOSSEMAPHORES
30 #define INCL_DOSPROCESS
35 // the possible states of the thread ("=>" shows all possible transitions from
39 STATE_NEW
, // didn't start execution yet (=> RUNNING)
40 STATE_RUNNING
, // thread is running (=> PAUSED, CANCELED)
41 STATE_PAUSED
, // thread is temporarily suspended (=> RUNNING)
42 STATE_CANCELED
, // thread should terminate a.s.a.p. (=> EXITED)
43 STATE_EXITED
// thread is terminating
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 // id of the main thread - the one which can call GUI functions without first
51 // calling wxMutexGuiEnter()
52 static ULONG s_ulIdMainThread
= 0;
53 wxMutex
* p_wxMainMutex
;
55 // OS2 substitute for Tls pointer the current parent thread object
56 wxThread
* m_pThread
; // pointer to the wxWindows thread object
58 // if it's FALSE, some secondary thread is holding the GUI lock
59 static bool gs_bGuiOwnedByMainThread
= TRUE
;
61 // critical section which controls access to all GUI functions: any secondary
62 // thread (i.e. except the main one) must enter this crit section before doing
64 static wxCriticalSection
*gs_pCritsectGui
= NULL
;
66 // critical section which protects s_nWaitingForGui variable
67 static wxCriticalSection
*gs_pCritsectWaitingForGui
= NULL
;
69 // number of threads waiting for GUI in wxMutexGuiEnter()
70 static size_t gs_nWaitingForGui
= 0;
72 // are we waiting for a thread termination?
73 static bool gs_bWaitingForThread
= FALSE
;
75 // ============================================================================
76 // OS/2 implementation of thread classes
77 // ============================================================================
79 // ----------------------------------------------------------------------------
80 // wxMutex implementation
81 // ----------------------------------------------------------------------------
89 wxMutexType eMutexType
94 m_internal
= new wxMutexInternal
;
95 ulrc
= ::DosCreateMutexSem(NULL
, &m_internal
->m_vMutex
, 0L, FALSE
);
98 wxLogSysError(_("Can not create mutex."));
104 ::DosCloseMutexSem(m_internal
->m_vMutex
);
105 m_internal
->m_vMutex
= NULL
;
108 wxMutexError
wxMutex::Lock()
112 ulrc
= ::DosRequestMutexSem(m_internal
->m_vMutex
, SEM_INDEFINITE_WAIT
);
116 case ERROR_TOO_MANY_SEM_REQUESTS
:
123 case ERROR_INVALID_HANDLE
:
124 case ERROR_INTERRUPT
:
125 case ERROR_SEM_OWNER_DIED
:
126 wxLogSysError(_("Couldn't acquire a mutex lock"));
127 return wxMUTEX_MISC_ERROR
;
131 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
133 return wxMUTEX_NO_ERROR
;
136 wxMutexError
wxMutex::TryLock()
140 ulrc
= ::DosRequestMutexSem(m_internal
->m_vMutex
, SEM_IMMEDIATE_RETURN
/*0L*/);
141 if (ulrc
== ERROR_TIMEOUT
|| ulrc
== ERROR_TOO_MANY_SEM_REQUESTS
)
144 return wxMUTEX_NO_ERROR
;
147 wxMutexError
wxMutex::Unlock()
151 ulrc
= ::DosReleaseMutexSem(m_internal
->m_vMutex
);
154 wxLogSysError(_("Couldn't release a mutex"));
155 return wxMUTEX_MISC_ERROR
;
157 return wxMUTEX_NO_ERROR
;
160 // ----------------------------------------------------------------------------
161 // wxCondition implementation
162 // ----------------------------------------------------------------------------
164 class wxConditionInternal
167 inline wxConditionInternal (wxMutex
& rMutex
) : m_vMutex(rMutex
)
169 ::DosCreateEventSem(NULL
, &m_vEvent
, DC_SEM_SHARED
, FALSE
);
172 wxLogSysError(_("Can not create event semaphore."));
178 unsigned long ulTimeout
184 ulrc
= ::DosWaitEventSem(m_vEvent
, ulTimeout
);
189 inline ~wxConditionInternal ()
195 ulrc
= ::DosCloseEventSem(m_vEvent
);
198 wxLogLastError("DosCloseEventSem(m_vEvent)");
208 wxCondition::wxCondition(wxMutex
& rMutex
)
213 m_internal
= new wxConditionInternal(rMutex
);
214 ulrc
= ::DosCreateEventSem(NULL
, &m_internal
->m_vEvent
, 0L, FALSE
);
217 wxLogSysError(_("Can not create event object."));
219 m_internal
->m_nWaiters
= 0;
220 // ?? just for good measure?
221 ::DosResetEventSem(m_internal
->m_vEvent
, &ulCount
);
224 wxCondition::~wxCondition()
226 ::DosCloseEventSem(m_internal
->m_vEvent
);
231 wxCondError
wxCondition::Wait()
233 APIRET rc
= m_internal
->Wait(SEM_INDEFINITE_WAIT
);
238 return wxCOND_NO_ERROR
;
239 case ERROR_INVALID_HANDLE
:
240 return wxCOND_INVALID
;
242 return wxCOND_TIMEOUT
;
244 return wxCOND_MISC_ERROR
;
248 wxCondError
wxCondition::WaitTimeout(
249 unsigned long lMilliSec
252 APIRET rc
= m_internal
->Wait(lMilliSec
);
257 return wxCOND_NO_ERROR
;
258 case ERROR_INVALID_HANDLE
:
259 return wxCOND_INVALID
;
261 return wxCOND_TIMEOUT
;
263 return wxCOND_MISC_ERROR
;
267 wxCondError
wxCondition::Signal()
269 APIRET rc
= ::DosPostEventSem(m_internal
->m_vEvent
);
274 return wxCOND_NO_ERROR
;
275 case ERROR_INVALID_HANDLE
:
276 return wxCOND_INVALID
;
278 return wxCOND_MISC_ERROR
;
282 wxCondError
wxCondition::Broadcast()
285 APIRET rc
= NO_ERROR
;
287 for (i
= 0; i
< m_internal
->m_nWaiters
; i
++)
289 if ((rc
= ::DosPostEventSem(m_internal
->m_vEvent
)) != NO_ERROR
)
291 wxLogSysError(_("Couldn't change the state of event object."));
299 return wxCOND_NO_ERROR
;
300 case ERROR_INVALID_HANDLE
:
301 return wxCOND_INVALID
;
303 return wxCOND_MISC_ERROR
;
307 // ----------------------------------------------------------------------------
308 // wxCriticalSection implementation
309 // ----------------------------------------------------------------------------
311 wxCriticalSection::wxCriticalSection()
315 wxCriticalSection::~wxCriticalSection()
319 void wxCriticalSection::Enter()
324 void wxCriticalSection::Leave()
329 // ----------------------------------------------------------------------------
330 // wxThread implementation
331 // ----------------------------------------------------------------------------
333 // wxThreadInternal class
334 // ----------------------
336 class wxThreadInternal
339 inline wxThreadInternal()
342 m_eState
= STATE_NEW
;
360 // create a new (suspended) thread (for the given thread object)
361 bool Create( wxThread
* pThread
362 ,unsigned int uStackSize
365 // suspend/resume/terminate
368 inline void Cancel() { m_eState
= STATE_CANCELED
; }
371 inline void SetState(wxThreadState eState
) { m_eState
= eState
; }
372 inline wxThreadState
GetState() const { return m_eState
; }
375 void SetPriority(unsigned int nPriority
);
376 inline unsigned int GetPriority() const { return m_nPriority
; }
378 // thread handle and id
379 inline TID
GetHandle() const { return m_hThread
; }
380 TID
GetId() const { return m_hThread
; }
383 static DWORD
OS2ThreadStart(wxThread
*thread
);
386 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
387 // PM also has no real Tls mechanism to index pointers by so we'll just
388 // keep track of the wxWindows parent object here.
389 TID m_hThread
; // handle and ID of the thread
390 wxThreadState m_eState
; // state, see wxThreadState enum
391 unsigned int m_nPriority
; // thread priority in "wx" units
394 ULONG
wxThreadInternal::OS2ThreadStart(
400 DWORD dwRet
= (DWORD
)pThread
->Entry();
402 // enter m_critsect before changing the thread state
403 pThread
->m_critsect
.Enter();
405 bool bWasCancelled
= pThread
->m_internal
->GetState() == STATE_CANCELED
;
407 pThread
->m_internal
->SetState(STATE_EXITED
);
408 pThread
->m_critsect
.Leave();
412 // if the thread was cancelled (from Delete()), then it the handle is still
414 if (pThread
->IsDetached() && !bWasCancelled
)
419 //else: the joinable threads handle will be closed when Wait() is done
423 void wxThreadInternal::SetPriority(
424 unsigned int nPriority
427 // translate wxWindows priority to the PM one
428 ULONG ulOS2_Priority
;
431 m_nPriority
= nPriority
;
433 if (m_nPriority
<= 20)
434 ulOS2_Priority
= PRTYC_NOCHANGE
;
435 else if (m_nPriority
<= 40)
436 ulOS2_Priority
= PRTYC_IDLETIME
;
437 else if (m_nPriority
<= 60)
438 ulOS2_Priority
= PRTYC_REGULAR
;
439 else if (m_nPriority
<= 80)
440 ulOS2_Priority
= PRTYC_TIMECRITICAL
;
441 else if (m_nPriority
<= 100)
442 ulOS2_Priority
= PRTYC_FOREGROUNDSERVER
;
445 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
446 ulOS2_Priority
= PRTYC_REGULAR
;
448 ulrc
= ::DosSetPriority( PRTYS_THREAD
455 wxLogSysError(_("Can't set thread priority"));
459 bool wxThreadInternal::Create(
461 , unsigned int uStackSize
466 ulrc
= ::DosCreateThread( &m_hThread
467 ,(PFNTHREAD
)wxThreadInternal::OS2ThreadStart
469 ,CREATE_SUSPENDED
| STACK_SPARSE
474 wxLogSysError(_("Can't create thread"));
478 if (m_nPriority
!= WXTHREAD_DEFAULT_PRIORITY
)
480 SetPriority(m_nPriority
);
485 bool wxThreadInternal::Suspend()
487 ULONG ulrc
= ::DosSuspendThread(m_hThread
);
491 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
494 m_eState
= STATE_PAUSED
;
498 bool wxThreadInternal::Resume()
500 ULONG ulrc
= ::DosResumeThread(m_hThread
);
504 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
507 m_eState
= STATE_PAUSED
;
514 wxThread
*wxThread::This()
516 wxThread
* pThread
= m_pThread
;
520 bool wxThread::IsMain()
525 ::DosGetInfoBlocks(&ptib
, &ppib
);
527 if (ptib
->tib_ptib2
->tib2_ultid
== s_ulIdMainThread
)
536 void wxThread::Yield()
541 void wxThread::Sleep(
542 unsigned long ulMilliseconds
545 ::DosSleep(ulMilliseconds
);
551 wxThread::wxThread(wxThreadKind kind
)
553 m_internal
= new wxThreadInternal();
555 m_isDetached
= kind
== wxTHREAD_DETACHED
;
558 wxThread::~wxThread()
563 // create/start thread
564 // -------------------
566 wxThreadError
wxThread::Create(
567 unsigned int uStackSize
570 if ( !m_internal
->Create(this, uStackSize
) )
571 return wxTHREAD_NO_RESOURCE
;
573 return wxTHREAD_NO_ERROR
;
576 wxThreadError
wxThread::Run()
578 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
580 if ( m_internal
->GetState() != STATE_NEW
)
582 // actually, it may be almost any state at all, not only STATE_RUNNING
583 return wxTHREAD_RUNNING
;
588 // suspend/resume thread
589 // ---------------------
591 wxThreadError
wxThread::Pause()
593 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
595 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
598 wxThreadError
wxThread::Resume()
600 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
602 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
608 wxThread::ExitCode
wxThread::Wait()
610 // although under Windows we can wait for any thread, it's an error to
611 // wait for a detached one in wxWin API
612 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
613 _T("can't wait for detached thread") );
614 ExitCode rc
= (ExitCode
)-1;
620 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
624 // Delete() is always safe to call, so consider all possible states
628 TID hThread
= m_internal
->GetHandle();
634 // set flag for wxIsWaitingForThread()
635 gs_bWaitingForThread
= TRUE
;
642 // ask the thread to terminate
644 wxCriticalSectionLocker
lock(m_critsect
);
645 m_internal
->Cancel();
649 // need a way to finish GUI processing before killing the thread
650 // until then we just exit
652 if ((gs_nWaitingForGui
> 0) && wxGuiOwnedByMainThread())
658 // can't wait for yourself to end under OS/2 so just quit
660 #endif // wxUSE_GUI/!wxUSE_GUI
664 gs_bWaitingForThread
= FALSE
;
673 // probably won't get this far, but
682 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
685 wxThreadError
wxThread::Kill()
688 return wxTHREAD_NOT_RUNNING
;
690 ::DosKillThread(m_internal
->GetHandle());
696 return wxTHREAD_NO_ERROR
;
705 ::DosExit(EXIT_THREAD
, ULONG(pStatus
));
706 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
709 void wxThread::SetPriority(
713 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
715 m_internal
->SetPriority(nPrio
);
718 unsigned int wxThread::GetPriority() const
720 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
722 return m_internal
->GetPriority();
725 unsigned long wxThread::GetId() const
727 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
729 return (unsigned long)m_internal
->GetId();
732 bool wxThread::IsRunning() const
734 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
736 return(m_internal
->GetState() == STATE_RUNNING
);
739 bool wxThread::IsAlive() const
741 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
743 return (m_internal
->GetState() == STATE_RUNNING
) ||
744 (m_internal
->GetState() == STATE_PAUSED
);
747 bool wxThread::IsPaused() const
749 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
751 return (m_internal
->GetState() == STATE_PAUSED
);
754 bool wxThread::TestDestroy()
756 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
758 return m_internal
->GetState() == STATE_CANCELED
;
761 // ----------------------------------------------------------------------------
762 // Automatic initialization for thread module
763 // ----------------------------------------------------------------------------
765 class wxThreadModule
: public wxModule
768 virtual bool OnInit();
769 virtual void OnExit();
772 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
775 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
777 bool wxThreadModule::OnInit()
779 gs_pCritsectWaitingForGui
= new wxCriticalSection();
781 gs_pCritsectGui
= new wxCriticalSection();
782 gs_pCritsectGui
->Enter();
787 ::DosGetInfoBlocks(&ptib
, &ppib
);
789 s_ulIdMainThread
= ptib
->tib_ptib2
->tib2_ultid
;
793 void wxThreadModule::OnExit()
797 gs_pCritsectGui
->Leave();
798 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
799 delete gs_pCritsectGui
;
801 gs_pCritsectGui
= NULL
;
804 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
805 wxDELETE(gs_pCritsectWaitingForGui
);
809 // ----------------------------------------------------------------------------
811 // ----------------------------------------------------------------------------
813 // Does nothing under OS/2 [for now]
814 void WXDLLEXPORT
wxWakeUpMainThread()
818 void WXDLLEXPORT
wxMutexGuiLeave()
820 wxCriticalSectionLocker
enter(*gs_pCritsectWaitingForGui
);
822 if ( wxThread::IsMain() )
824 gs_bGuiOwnedByMainThread
= FALSE
;
828 // decrement the number of waiters now
829 wxASSERT_MSG(gs_nWaitingForGui
> 0,
830 wxT("calling wxMutexGuiLeave() without entering it first?") );
834 wxWakeUpMainThread();
837 gs_pCritsectGui
->Leave();
840 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
842 wxASSERT_MSG( wxThread::IsMain(),
843 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
845 wxCriticalSectionLocker
enter(*gs_pCritsectWaitingForGui
);
847 if (gs_nWaitingForGui
== 0)
849 // no threads are waiting for GUI - so we may acquire the lock without
850 // any danger (but only if we don't already have it)
851 if (!wxGuiOwnedByMainThread())
853 gs_pCritsectGui
->Enter();
855 gs_bGuiOwnedByMainThread
= TRUE
;
857 //else: already have it, nothing to do
861 // some threads are waiting, release the GUI lock if we have it
862 if (wxGuiOwnedByMainThread())
866 //else: some other worker thread is doing GUI
870 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
872 return gs_bGuiOwnedByMainThread
;
875 bool WXDLLEXPORT
wxIsWaitingForThread()
877 return gs_bWaitingForThread
;