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 p_internal
= new wxMutexInternal
;
90 ulrc
= ::DosCreateMutexSem(NULL
, &p_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(p_internal
->m_vMutex
);
103 p_internal
->m_vMutex
= NULL
;
106 wxMutexError
wxMutex::Lock()
110 ulrc
= ::DosRequestMutexSem(p_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(p_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(p_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
174 wxCondition::wxCondition()
179 p_internal
= new wxConditionInternal
;
180 ulrc
= ::DosCreateEventSem(NULL
, &p_internal
->m_vEvent
, 0L, FALSE
);
183 wxLogSysError(_("Can not create event object."));
185 p_internal
->m_nWaiters
= 0;
186 // ?? just for good measure?
187 ::DosResetEventSem(p_internal
->m_vEvent
, &ulCount
);
190 wxCondition::~wxCondition()
192 ::DosCloseEventSem(p_internal
->m_vEvent
);
197 void wxCondition::Wait(
202 p_internal
->m_nWaiters
++;
203 ::DosWaitEventSem(p_internal
->m_vEvent
, SEM_INDEFINITE_WAIT
);
204 p_internal
->m_nWaiters
--;
208 bool wxCondition::Wait(
210 , unsigned long ulSec
211 , unsigned long ulMillisec
)
216 p_internal
->m_nWaiters
++;
217 ulrc
= ::DosWaitEventSem(p_internal
->m_vEvent
, ULONG((ulSec
* 1000L) + ulMillisec
));
218 p_internal
->m_nWaiters
--;
221 return (ulrc
!= ERROR_TIMEOUT
);
224 void wxCondition::Signal()
226 ::DosPostEventSem(p_internal
->m_vEvent
);
229 void wxCondition::Broadcast()
233 for (i
= 0; i
< p_internal
->m_nWaiters
; i
++)
235 if (::DosPostEventSem(p_internal
->m_vEvent
) != 0)
237 wxLogSysError(_("Couldn't change the state of event object."));
242 // ----------------------------------------------------------------------------
243 // wxCriticalSection implementation
244 // ----------------------------------------------------------------------------
246 class wxCriticalSectionInternal
249 // init the critical section object
250 wxCriticalSectionInternal()
253 // free the associated ressources
254 ~wxCriticalSectionInternal()
260 // ----------------------------------------------------------------------------
261 // wxCriticalSection implementation
262 // ----------------------------------------------------------------------------
264 wxCriticalSection::wxCriticalSection()
266 m_critsect
= new wxCriticalSectionInternal
;
269 wxCriticalSection::~wxCriticalSection()
274 void wxCriticalSection::Enter()
279 void wxCriticalSection::Leave()
284 // ----------------------------------------------------------------------------
285 // wxThread implementation
286 // ----------------------------------------------------------------------------
288 // wxThreadInternal class
289 // ----------------------
291 class wxThreadInternal
294 inline wxThreadInternal()
297 m_eState
= STATE_NEW
;
301 // create a new (suspended) thread (for the given thread object)
302 bool Create(wxThread
* pThread
);
304 // suspend/resume/terminate
307 inline void Cancel() { m_eState
= STATE_CANCELED
; }
310 inline void SetState(wxThreadState eState
) { m_eState
= eState
; }
311 inline wxThreadState
GetState() const { return m_eState
; }
314 inline void SetPriority(unsigned int nPriority
) { m_nPriority
= nPriority
; }
315 inline unsigned int GetPriority() const { return m_nPriority
; }
317 // thread handle and id
318 inline TID
GetHandle() const { return m_hThread
; }
319 TID
GetId() const { return m_hThread
; }
322 static DWORD
OS2ThreadStart(wxThread
*thread
);
325 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
326 // PM also has no real Tls mechanism to index pointers by so we'll just
327 // keep track of the wxWindows parent object here.
328 TID m_hThread
; // handle and ID of the thread
329 wxThreadState m_eState
; // state, see wxThreadState enum
330 unsigned int m_nPriority
; // thread priority in "wx" units
333 ULONG
wxThreadInternal::OS2ThreadStart(
339 DWORD dwRet
= (DWORD
)pThread
->Entry();
341 pThread
->p_internal
->SetState(STATE_EXITED
);
349 bool wxThreadInternal::Create(
355 ulrc
= ::DosCreateThread( &m_hThread
356 ,(PFNTHREAD
)wxThreadInternal::OS2ThreadStart
358 ,CREATE_SUSPENDED
| STACK_SPARSE
363 wxLogSysError(_("Can't create thread"));
368 // translate wxWindows priority to the PM one
369 ULONG ulOS2_Priority
;
371 if (m_nPriority
<= 20)
372 ulOS2_Priority
= PRTYC_NOCHANGE
;
373 else if (m_nPriority
<= 40)
374 ulOS2_Priority
= PRTYC_IDLETIME
;
375 else if (m_nPriority
<= 60)
376 ulOS2_Priority
= PRTYC_REGULAR
;
377 else if (m_nPriority
<= 80)
378 ulOS2_Priority
= PRTYC_TIMECRITICAL
;
379 else if (m_nPriority
<= 100)
380 ulOS2_Priority
= PRTYC_FOREGROUNDSERVER
;
383 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
384 ulOS2_Priority
= PRTYC_REGULAR
;
386 ulrc
= ::DosSetPriority( PRTYS_THREAD
393 wxLogSysError(_("Can't set thread priority"));
398 bool wxThreadInternal::Suspend()
400 ULONG ulrc
= ::DosSuspendThread(m_hThread
);
404 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
407 m_eState
= STATE_PAUSED
;
411 bool wxThreadInternal::Resume()
413 ULONG ulrc
= ::DosResumeThread(m_hThread
);
417 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
420 m_eState
= STATE_PAUSED
;
427 wxThread
*wxThread::This()
429 wxThread
* pThread
= m_pThread
;
433 bool wxThread::IsMain()
438 ::DosGetInfoBlocks(&ptib
, &ppib
);
440 if (ptib
->tib_ptib2
->tib2_ultid
== s_ulIdMainThread
)
449 void wxThread::Yield()
454 void wxThread::Sleep(
455 unsigned long ulMilliseconds
458 ::DosSleep(ulMilliseconds
);
461 // create/start thread
462 // -------------------
464 wxThreadError
wxThread::Create()
466 if ( !p_internal
->Create(this) )
467 return wxTHREAD_NO_RESOURCE
;
469 return wxTHREAD_NO_ERROR
;
472 wxThreadError
wxThread::Run()
474 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
476 if ( p_internal
->GetState() != STATE_NEW
)
478 // actually, it may be almost any state at all, not only STATE_RUNNING
479 return wxTHREAD_RUNNING
;
484 // suspend/resume thread
485 // ---------------------
487 wxThreadError
wxThread::Pause()
489 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
491 return p_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
494 wxThreadError
wxThread::Resume()
496 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
498 return p_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
504 wxThread::ExitCode
wxThread::Delete()
509 // Delete() is always safe to call, so consider all possible states
517 // set flag for wxIsWaitingForThread()
518 s_bWaitingForThread
= TRUE
;
525 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
527 p_internal
->Cancel();
528 hThread
= p_internal
->GetHandle();
531 // we can't just wait for the thread to terminate because it might be
532 // calling some GUI functions and so it will never terminate before we
533 // process the Windows messages that result from these functions
537 ulrc
= ::DosWaitThread( &hThread
542 case ERROR_INTERRUPT
:
543 case ERROR_INVALID_THREADID
:
545 wxLogSysError(_("Can not wait for thread termination"));
550 // thread we're waiting for terminated
553 case ERROR_THREAD_NOT_TERMINATED
:
554 // new message arrived, process it
555 if (!wxTheApp
->DoMessage())
557 // WM_QUIT received: kill the thread
563 // give the thread we're waiting for chance to exit
564 // from the GUI call it might have been in
565 if ((s_nWaitingForGui
> 0) && wxGuiOwnedByMainThread())
573 wxFAIL_MSG(wxT("unexpected result of DosWatiThread"));
579 s_bWaitingForThread
= FALSE
;
583 ::DosExit(EXIT_THREAD
, ulrc
);
589 wxThreadError
wxThread::Kill()
592 return wxTHREAD_NOT_RUNNING
;
594 ::DosKillThread(p_internal
->GetHandle());
596 return wxTHREAD_NO_ERROR
;
604 ::DosExit(EXIT_THREAD
, ULONG(pStatus
));
605 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
608 void wxThread::SetPriority(
612 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
614 p_internal
->SetPriority(nPrio
);
617 unsigned int wxThread::GetPriority() const
619 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
621 return p_internal
->GetPriority();
624 unsigned long wxThread::GetID() const
626 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
628 return (unsigned long)p_internal
->GetId();
631 bool wxThread::IsRunning() const
633 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
635 return p_internal
->GetState() == STATE_RUNNING
;
638 bool wxThread::IsAlive() const
640 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
642 return (p_internal
->GetState() == STATE_RUNNING
) ||
643 (p_internal
->GetState() == STATE_PAUSED
);
646 bool wxThread::IsPaused() const
648 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
650 return (p_internal
->GetState() == STATE_PAUSED
);
653 bool wxThread::TestDestroy()
655 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
657 return p_internal
->GetState() == STATE_CANCELED
;
662 p_internal
= new wxThreadInternal();
665 wxThread::~wxThread()
670 // ----------------------------------------------------------------------------
671 // Automatic initialization for thread module
672 // ----------------------------------------------------------------------------
674 class wxThreadModule
: public wxModule
677 virtual bool OnInit();
678 virtual void OnExit();
681 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
684 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
686 bool wxThreadModule::OnInit()
688 s_pCritsectWaitingForGui
= new wxCriticalSection();
690 s_pCritsectGui
= new wxCriticalSection();
691 s_pCritsectGui
->Enter();
696 ::DosGetInfoBlocks(&ptib
, &ppib
);
698 s_ulIdMainThread
= ptib
->tib_ptib2
->tib2_ultid
;
702 void wxThreadModule::OnExit()
706 s_pCritsectGui
->Leave();
707 delete s_pCritsectGui
;
708 s_pCritsectGui
= NULL
;
711 wxDELETE(s_pCritsectWaitingForGui
);
714 // ----------------------------------------------------------------------------
716 // ----------------------------------------------------------------------------
718 // Does nothing under OS/2 [for now]
719 void WXDLLEXPORT
wxWakeUpMainThread()
723 void WXDLLEXPORT
wxMutexGuiLeave()
725 wxCriticalSectionLocker
enter(*s_pCritsectWaitingForGui
);
727 if ( wxThread::IsMain() )
729 s_bGuiOwnedByMainThread
= FALSE
;
733 // decrement the number of waiters now
734 wxASSERT_MSG( s_nWaitingForGui
> 0,
735 wxT("calling wxMutexGuiLeave() without entering it first?") );
739 wxWakeUpMainThread();
742 s_pCritsectGui
->Leave();
745 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
747 wxASSERT_MSG( wxThread::IsMain(),
748 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
750 wxCriticalSectionLocker
enter(*s_pCritsectWaitingForGui
);
752 if ( s_nWaitingForGui
== 0 )
754 // no threads are waiting for GUI - so we may acquire the lock without
755 // any danger (but only if we don't already have it)
756 if (!wxGuiOwnedByMainThread())
758 s_pCritsectGui
->Enter();
760 s_bGuiOwnedByMainThread
= TRUE
;
762 //else: already have it, nothing to do
766 // some threads are waiting, release the GUI lock if we have it
767 if (wxGuiOwnedByMainThread())
771 //else: some other worker thread is doing GUI
775 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
777 return s_bGuiOwnedByMainThread
;