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 // ----------------------------------------------------------------------------
92 m_internal
= new wxMutexInternal
;
93 ulrc
= ::DosCreateMutexSem(NULL
, &m_internal
->m_vMutex
, 0L, FALSE
);
96 wxLogSysError(_("Can not create mutex."));
104 wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked
);
105 ::DosCloseMutexSem(m_internal
->m_vMutex
);
106 m_internal
->m_vMutex
= NULL
;
109 wxMutexError
wxMutex::Lock()
113 ulrc
= ::DosRequestMutexSem(m_internal
->m_vMutex
, SEM_INDEFINITE_WAIT
);
117 case ERROR_TOO_MANY_SEM_REQUESTS
:
124 case ERROR_INVALID_HANDLE
:
125 case ERROR_INTERRUPT
:
126 case ERROR_SEM_OWNER_DIED
:
127 wxLogSysError(_("Couldn't acquire a mutex lock"));
128 return wxMUTEX_MISC_ERROR
;
132 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
135 return wxMUTEX_NO_ERROR
;
138 wxMutexError
wxMutex::TryLock()
142 ulrc
= ::DosRequestMutexSem(m_internal
->m_vMutex
, SEM_IMMEDIATE_RETURN
/*0L*/);
143 if (ulrc
== ERROR_TIMEOUT
|| ulrc
== ERROR_TOO_MANY_SEM_REQUESTS
)
147 return wxMUTEX_NO_ERROR
;
150 wxMutexError
wxMutex::Unlock()
157 ulrc
= ::DosReleaseMutexSem(m_internal
->m_vMutex
);
160 wxLogSysError(_("Couldn't release a mutex"));
161 return wxMUTEX_MISC_ERROR
;
163 return wxMUTEX_NO_ERROR
;
166 // ----------------------------------------------------------------------------
167 // wxCondition implementation
168 // ----------------------------------------------------------------------------
170 class wxConditionInternal
173 inline wxConditionInternal (wxMutex
& rMutex
) : m_vMutex(rMutex
)
175 ::DosCreateEventSem(NULL
, &m_vEvent
, DC_SEM_SHARED
, FALSE
);
178 wxLogSysError(_("Can not create event semaphore."));
184 unsigned long ulTimeout
190 ulrc
= ::DosWaitEventSem(m_vEvent
, ulTimeout
);
192 return (ulrc
!= ERROR_TIMEOUT
);
195 inline ~wxConditionInternal ()
201 ulrc
= ::DosCloseEventSem(m_vEvent
);
204 wxLogLastError("DosCloseEventSem(m_vEvent)");
214 wxCondition::wxCondition(wxMutex
& rMutex
)
219 m_internal
= new wxConditionInternal(rMutex
);
220 ulrc
= ::DosCreateEventSem(NULL
, &m_internal
->m_vEvent
, 0L, FALSE
);
223 wxLogSysError(_("Can not create event object."));
225 m_internal
->m_nWaiters
= 0;
226 // ?? just for good measure?
227 ::DosResetEventSem(m_internal
->m_vEvent
, &ulCount
);
230 wxCondition::~wxCondition()
232 ::DosCloseEventSem(m_internal
->m_vEvent
);
237 void wxCondition::Wait()
239 (void)m_internal
->Wait(SEM_INDEFINITE_WAIT
);
242 bool wxCondition::Wait(
243 unsigned long lMilliSec
246 return m_internal
->Wait(lMilliSec
);
249 void wxCondition::Signal()
251 ::DosPostEventSem(m_internal
->m_vEvent
);
254 void wxCondition::Broadcast()
258 for (i
= 0; i
< m_internal
->m_nWaiters
; i
++)
260 if (::DosPostEventSem(m_internal
->m_vEvent
) != 0)
262 wxLogSysError(_("Couldn't change the state of event object."));
267 // ----------------------------------------------------------------------------
268 // wxCriticalSection implementation
269 // ----------------------------------------------------------------------------
271 wxCriticalSection::wxCriticalSection()
275 wxCriticalSection::~wxCriticalSection()
279 void wxCriticalSection::Enter()
284 void wxCriticalSection::Leave()
289 // ----------------------------------------------------------------------------
290 // wxThread implementation
291 // ----------------------------------------------------------------------------
293 // wxThreadInternal class
294 // ----------------------
296 class wxThreadInternal
299 inline wxThreadInternal()
302 m_eState
= STATE_NEW
;
320 // create a new (suspended) thread (for the given thread object)
321 bool Create( wxThread
* pThread
322 ,unsigned int uStackSize
325 // suspend/resume/terminate
328 inline void Cancel() { m_eState
= STATE_CANCELED
; }
331 inline void SetState(wxThreadState eState
) { m_eState
= eState
; }
332 inline wxThreadState
GetState() const { return m_eState
; }
335 void SetPriority(unsigned int nPriority
);
336 inline unsigned int GetPriority() const { return m_nPriority
; }
338 // thread handle and id
339 inline TID
GetHandle() const { return m_hThread
; }
340 TID
GetId() const { return m_hThread
; }
343 static DWORD
OS2ThreadStart(wxThread
*thread
);
346 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
347 // PM also has no real Tls mechanism to index pointers by so we'll just
348 // keep track of the wxWindows parent object here.
349 TID m_hThread
; // handle and ID of the thread
350 wxThreadState m_eState
; // state, see wxThreadState enum
351 unsigned int m_nPriority
; // thread priority in "wx" units
354 ULONG
wxThreadInternal::OS2ThreadStart(
360 DWORD dwRet
= (DWORD
)pThread
->Entry();
362 // enter m_critsect before changing the thread state
363 pThread
->m_critsect
.Enter();
365 bool bWasCancelled
= pThread
->m_internal
->GetState() == STATE_CANCELED
;
367 pThread
->m_internal
->SetState(STATE_EXITED
);
368 pThread
->m_critsect
.Leave();
372 // if the thread was cancelled (from Delete()), then it the handle is still
374 if (pThread
->IsDetached() && !bWasCancelled
)
379 //else: the joinable threads handle will be closed when Wait() is done
383 void wxThreadInternal::SetPriority(
384 unsigned int nPriority
387 // translate wxWindows priority to the PM one
388 ULONG ulOS2_Priority
;
391 m_nPriority
= nPriority
;
393 if (m_nPriority
<= 20)
394 ulOS2_Priority
= PRTYC_NOCHANGE
;
395 else if (m_nPriority
<= 40)
396 ulOS2_Priority
= PRTYC_IDLETIME
;
397 else if (m_nPriority
<= 60)
398 ulOS2_Priority
= PRTYC_REGULAR
;
399 else if (m_nPriority
<= 80)
400 ulOS2_Priority
= PRTYC_TIMECRITICAL
;
401 else if (m_nPriority
<= 100)
402 ulOS2_Priority
= PRTYC_FOREGROUNDSERVER
;
405 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
406 ulOS2_Priority
= PRTYC_REGULAR
;
408 ulrc
= ::DosSetPriority( PRTYS_THREAD
415 wxLogSysError(_("Can't set thread priority"));
419 bool wxThreadInternal::Create(
421 , unsigned int uStackSize
426 ulrc
= ::DosCreateThread( &m_hThread
427 ,(PFNTHREAD
)wxThreadInternal::OS2ThreadStart
429 ,CREATE_SUSPENDED
| STACK_SPARSE
434 wxLogSysError(_("Can't create thread"));
438 if (m_nPriority
!= WXTHREAD_DEFAULT_PRIORITY
)
440 SetPriority(m_nPriority
);
445 bool wxThreadInternal::Suspend()
447 ULONG ulrc
= ::DosSuspendThread(m_hThread
);
451 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
454 m_eState
= STATE_PAUSED
;
458 bool wxThreadInternal::Resume()
460 ULONG ulrc
= ::DosResumeThread(m_hThread
);
464 wxLogSysError(_("Can not suspend thread %lu"), m_hThread
);
467 m_eState
= STATE_PAUSED
;
474 wxThread
*wxThread::This()
476 wxThread
* pThread
= m_pThread
;
480 bool wxThread::IsMain()
485 ::DosGetInfoBlocks(&ptib
, &ppib
);
487 if (ptib
->tib_ptib2
->tib2_ultid
== s_ulIdMainThread
)
496 void wxThread::Yield()
501 void wxThread::Sleep(
502 unsigned long ulMilliseconds
505 ::DosSleep(ulMilliseconds
);
511 wxThread::wxThread(wxThreadKind kind
)
513 m_internal
= new wxThreadInternal();
515 m_isDetached
= kind
== wxTHREAD_DETACHED
;
518 wxThread::~wxThread()
523 // create/start thread
524 // -------------------
526 wxThreadError
wxThread::Create(
527 unsigned int uStackSize
530 if ( !m_internal
->Create(this, uStackSize
) )
531 return wxTHREAD_NO_RESOURCE
;
533 return wxTHREAD_NO_ERROR
;
536 wxThreadError
wxThread::Run()
538 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
540 if ( m_internal
->GetState() != STATE_NEW
)
542 // actually, it may be almost any state at all, not only STATE_RUNNING
543 return wxTHREAD_RUNNING
;
548 // suspend/resume thread
549 // ---------------------
551 wxThreadError
wxThread::Pause()
553 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
555 return m_internal
->Suspend() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
558 wxThreadError
wxThread::Resume()
560 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
562 return m_internal
->Resume() ? wxTHREAD_NO_ERROR
: wxTHREAD_MISC_ERROR
;
568 wxThread::ExitCode
wxThread::Wait()
570 // although under Windows we can wait for any thread, it's an error to
571 // wait for a detached one in wxWin API
572 wxCHECK_MSG( !IsDetached(), (ExitCode
)-1,
573 _T("can't wait for detached thread") );
574 ExitCode rc
= (ExitCode
)-1;
580 wxThreadError
wxThread::Delete(ExitCode
*pRc
)
584 // Delete() is always safe to call, so consider all possible states
588 TID hThread
= m_internal
->GetHandle();
594 // set flag for wxIsWaitingForThread()
595 gs_bWaitingForThread
= TRUE
;
602 // ask the thread to terminate
604 wxCriticalSectionLocker
lock(m_critsect
);
605 m_internal
->Cancel();
609 // need a way to finish GUI processing before killing the thread
610 // until then we just exit
612 if ((gs_nWaitingForGui
> 0) && wxGuiOwnedByMainThread())
618 // can't wait for yourself to end under OS/2 so just quit
620 #endif // wxUSE_GUI/!wxUSE_GUI
624 gs_bWaitingForThread
= FALSE
;
633 // probably won't get this far, but
642 return rc
== (ExitCode
)-1 ? wxTHREAD_MISC_ERROR
: wxTHREAD_NO_ERROR
;
645 wxThreadError
wxThread::Kill()
648 return wxTHREAD_NOT_RUNNING
;
650 ::DosKillThread(m_internal
->GetHandle());
656 return wxTHREAD_NO_ERROR
;
665 ::DosExit(EXIT_THREAD
, ULONG(pStatus
));
666 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
669 void wxThread::SetPriority(
673 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
675 m_internal
->SetPriority(nPrio
);
678 unsigned int wxThread::GetPriority() const
680 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
682 return m_internal
->GetPriority();
685 unsigned long wxThread::GetId() const
687 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
); // const_cast
689 return (unsigned long)m_internal
->GetId();
692 bool wxThread::IsRunning() const
694 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
696 return(m_internal
->GetState() == STATE_RUNNING
);
699 bool wxThread::IsAlive() const
701 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
703 return (m_internal
->GetState() == STATE_RUNNING
) ||
704 (m_internal
->GetState() == STATE_PAUSED
);
707 bool wxThread::IsPaused() const
709 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
711 return (m_internal
->GetState() == STATE_PAUSED
);
714 bool wxThread::TestDestroy()
716 wxCriticalSectionLocker
lock((wxCriticalSection
&)m_critsect
);
718 return m_internal
->GetState() == STATE_CANCELED
;
721 // ----------------------------------------------------------------------------
722 // Automatic initialization for thread module
723 // ----------------------------------------------------------------------------
725 class wxThreadModule
: public wxModule
728 virtual bool OnInit();
729 virtual void OnExit();
732 DECLARE_DYNAMIC_CLASS(wxThreadModule
)
735 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule
, wxModule
)
737 bool wxThreadModule::OnInit()
739 gs_pCritsectWaitingForGui
= new wxCriticalSection();
741 gs_pCritsectGui
= new wxCriticalSection();
742 gs_pCritsectGui
->Enter();
747 ::DosGetInfoBlocks(&ptib
, &ppib
);
749 s_ulIdMainThread
= ptib
->tib_ptib2
->tib2_ultid
;
753 void wxThreadModule::OnExit()
757 gs_pCritsectGui
->Leave();
758 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
759 delete gs_pCritsectGui
;
761 gs_pCritsectGui
= NULL
;
764 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
765 wxDELETE(gs_pCritsectWaitingForGui
);
769 // ----------------------------------------------------------------------------
771 // ----------------------------------------------------------------------------
773 // Does nothing under OS/2 [for now]
774 void WXDLLEXPORT
wxWakeUpMainThread()
778 void WXDLLEXPORT
wxMutexGuiLeave()
780 wxCriticalSectionLocker
enter(*gs_pCritsectWaitingForGui
);
782 if ( wxThread::IsMain() )
784 gs_bGuiOwnedByMainThread
= FALSE
;
788 // decrement the number of waiters now
789 wxASSERT_MSG(gs_nWaitingForGui
> 0,
790 wxT("calling wxMutexGuiLeave() without entering it first?") );
794 wxWakeUpMainThread();
797 gs_pCritsectGui
->Leave();
800 void WXDLLEXPORT
wxMutexGuiLeaveOrEnter()
802 wxASSERT_MSG( wxThread::IsMain(),
803 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
805 wxCriticalSectionLocker
enter(*gs_pCritsectWaitingForGui
);
807 if (gs_nWaitingForGui
== 0)
809 // no threads are waiting for GUI - so we may acquire the lock without
810 // any danger (but only if we don't already have it)
811 if (!wxGuiOwnedByMainThread())
813 gs_pCritsectGui
->Enter();
815 gs_bGuiOwnedByMainThread
= TRUE
;
817 //else: already have it, nothing to do
821 // some threads are waiting, release the GUI lock if we have it
822 if (wxGuiOwnedByMainThread())
826 //else: some other worker thread is doing GUI
830 bool WXDLLEXPORT
wxGuiOwnedByMainThread()
832 return gs_bGuiOwnedByMainThread
;
835 bool WXDLLEXPORT
wxIsWaitingForThread()
837 return gs_bWaitingForThread
;