X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5d4b632ba3c0e5e5c43412d2d7a2b485b8fcebf2..331a0b6b7aeb8b41d4ac27aeedbdca11b6f0b38e:/src/os2/thread.cpp diff --git a/src/os2/thread.cpp b/src/os2/thread.cpp index 80eef6b2e2..db6ba06510 100644 --- a/src/os2/thread.cpp +++ b/src/os2/thread.cpp @@ -21,6 +21,9 @@ #include #include "wx/module.h" +#include "wx/intl.h" +#include "wx/utils.h" +#include "wx/log.h" #include "wx/thread.h" #define INCL_DOSSEMAPHORES @@ -53,21 +56,21 @@ wxMutex* p_wxMainMutex; wxThread* m_pThread; // pointer to the wxWindows thread object // if it's FALSE, some secondary thread is holding the GUI lock -static bool s_bGuiOwnedByMainThread = TRUE; +static bool gs_bGuiOwnedByMainThread = TRUE; // critical section which controls access to all GUI functions: any secondary // thread (i.e. except the main one) must enter this crit section before doing // any GUI calls -static wxCriticalSection *s_pCritsectGui = NULL; +static wxCriticalSection *gs_pCritsectGui = NULL; // critical section which protects s_nWaitingForGui variable -static wxCriticalSection *s_pCritsectWaitingForGui = NULL; +static wxCriticalSection *gs_pCritsectWaitingForGui = NULL; // number of threads waiting for GUI in wxMutexGuiEnter() -static size_t s_nWaitingForGui = 0; +static size_t gs_nWaitingForGui = 0; // are we waiting for a thread termination? -static bool s_bWaitingForThread = FALSE; +static bool gs_bWaitingForThread = FALSE; // ============================================================================ // OS/2 implementation of thread classes @@ -82,32 +85,31 @@ public: HMTX m_vMutex; }; -wxMutex::wxMutex() +wxMutex::wxMutex( + wxMutexType eMutexType +) { APIRET ulrc; - p_internal = new wxMutexInternal; - ulrc = ::DosCreateMutexSem(NULL, &p_internal->m_vMutex, 0L, FALSE); + m_internal = new wxMutexInternal; + ulrc = ::DosCreateMutexSem(NULL, &m_internal->m_vMutex, 0L, FALSE); if (ulrc != 0) { wxLogSysError(_("Can not create mutex.")); } - m_locked = 0; } wxMutex::~wxMutex() { - if (m_locked > 0) - wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked); - ::DosCloseMutexSem(p_internal->m_vMutex); - p_internal->m_vMutex = NULL; + ::DosCloseMutexSem(m_internal->m_vMutex); + m_internal->m_vMutex = NULL; } wxMutexError wxMutex::Lock() { APIRET ulrc; - ulrc = ::DosRequestMutexSem(p_internal->m_vMutex, SEM_INDEFINITE_WAIT); + ulrc = ::DosRequestMutexSem(m_internal->m_vMutex, SEM_INDEFINITE_WAIT); switch (ulrc) { @@ -128,7 +130,6 @@ wxMutexError wxMutex::Lock() default: wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock")); } - m_locked++; return wxMUTEX_NO_ERROR; } @@ -136,11 +137,10 @@ wxMutexError wxMutex::TryLock() { ULONG ulrc; - ulrc = ::DosRequestMutexSem(p_internal->m_vMutex, SEM_IMMEDIATE_RETURN /*0L*/); + ulrc = ::DosRequestMutexSem(m_internal->m_vMutex, SEM_IMMEDIATE_RETURN /*0L*/); if (ulrc == ERROR_TIMEOUT || ulrc == ERROR_TOO_MANY_SEM_REQUESTS) return wxMUTEX_BUSY; - m_locked++; return wxMUTEX_NO_ERROR; } @@ -148,10 +148,7 @@ wxMutexError wxMutex::Unlock() { APIRET ulrc; - if (m_locked > 0) - m_locked--; - - ulrc = ::DosReleaseMutexSem(p_internal->m_vMutex); + ulrc = ::DosReleaseMutexSem(m_internal->m_vMutex); if (ulrc != 0) { wxLogSysError(_("Couldn't release a mutex")); @@ -167,95 +164,145 @@ wxMutexError wxMutex::Unlock() class wxConditionInternal { public: + inline wxConditionInternal (wxMutex& rMutex) : m_vMutex(rMutex) + { + ::DosCreateEventSem(NULL, &m_vEvent, DC_SEM_SHARED, FALSE); + if (!m_vEvent) + { + wxLogSysError(_("Can not create event semaphore.")); + } + m_nWaiters = 0; + } + + inline APIRET Wait( + unsigned long ulTimeout + ) + { + APIRET ulrc; + + m_nWaiters++; + ulrc = ::DosWaitEventSem(m_vEvent, ulTimeout); + m_nWaiters--; + return (ulrc); + } + + inline ~wxConditionInternal () + { + APIRET ulrc; + + if (m_vEvent) + { + ulrc = ::DosCloseEventSem(m_vEvent); + if (!ulrc) + { + wxLogLastError("DosCloseEventSem(m_vEvent)"); + } + } + } + HEV m_vEvent; int m_nWaiters; + wxMutex& m_vMutex; }; -wxCondition::wxCondition() +wxCondition::wxCondition(wxMutex& rMutex) { APIRET ulrc; ULONG ulCount; - p_internal = new wxConditionInternal; - ulrc = ::DosCreateEventSem(NULL, &p_internal->m_vEvent, 0L, FALSE); + m_internal = new wxConditionInternal(rMutex); + ulrc = ::DosCreateEventSem(NULL, &m_internal->m_vEvent, 0L, FALSE); if (ulrc != 0) { wxLogSysError(_("Can not create event object.")); } - p_internal->m_nWaiters = 0; + m_internal->m_nWaiters = 0; // ?? just for good measure? - ::DosResetEventSem(p_internal->m_vEvent, &ulCount); + ::DosResetEventSem(m_internal->m_vEvent, &ulCount); } wxCondition::~wxCondition() { - ::DosCloseEventSem(p_internal->m_vEvent); - delete p_internal; - p_internal = NULL; + ::DosCloseEventSem(m_internal->m_vEvent); + delete m_internal; + m_internal = NULL; } -void wxCondition::Wait( - wxMutex& rMutex -) +wxCondError wxCondition::Wait() { - rMutex.Unlock(); - p_internal->m_nWaiters++; - ::DosWaitEventSem(p_internal->m_vEvent, SEM_INDEFINITE_WAIT); - p_internal->m_nWaiters--; - rMutex.Lock(); + APIRET rc = m_internal->Wait(SEM_INDEFINITE_WAIT); + + switch(rc) + { + case NO_ERROR: + return wxCOND_NO_ERROR; + case ERROR_INVALID_HANDLE: + return wxCOND_INVALID; + case ERROR_TIMEOUT: + return wxCOND_TIMEOUT; + default: + return wxCOND_MISC_ERROR; + } } -bool wxCondition::Wait( - wxMutex& rMutex -, unsigned long ulSec -, unsigned long ulMillisec) +wxCondError wxCondition::WaitTimeout( + unsigned long lMilliSec +) { - APIRET ulrc; - - rMutex.Unlock(); - p_internal->m_nWaiters++; - ulrc = ::DosWaitEventSem(p_internal->m_vEvent, ULONG((ulSec * 1000L) + ulMillisec)); - p_internal->m_nWaiters--; - rMutex.Lock(); + APIRET rc = m_internal->Wait(lMilliSec); - return (ulrc != ERROR_TIMEOUT); + switch(rc) + { + case NO_ERROR: + return wxCOND_NO_ERROR; + case ERROR_INVALID_HANDLE: + return wxCOND_INVALID; + case ERROR_TIMEOUT: + return wxCOND_TIMEOUT; + default: + return wxCOND_MISC_ERROR; + } } -void wxCondition::Signal() +wxCondError wxCondition::Signal() { - ::DosPostEventSem(p_internal->m_vEvent); + APIRET rc = ::DosPostEventSem(m_internal->m_vEvent); + + switch(rc) + { + case NO_ERROR: + return wxCOND_NO_ERROR; + case ERROR_INVALID_HANDLE: + return wxCOND_INVALID; + default: + return wxCOND_MISC_ERROR; + } } -void wxCondition::Broadcast() +wxCondError wxCondition::Broadcast() { int i; + APIRET rc = NO_ERROR; - for (i = 0; i < p_internal->m_nWaiters; i++) + for (i = 0; i < m_internal->m_nWaiters; i++) { - if (::DosPostEventSem(p_internal->m_vEvent) != 0) + if ((rc = ::DosPostEventSem(m_internal->m_vEvent)) != NO_ERROR) { wxLogSysError(_("Couldn't change the state of event object.")); + break; } } -} - -// ---------------------------------------------------------------------------- -// wxCriticalSection implementation -// ---------------------------------------------------------------------------- - -class wxCriticalSectionInternal -{ -public: - // init the critical section object - wxCriticalSectionInternal() - { } - - // free the associated ressources - ~wxCriticalSectionInternal() - { } -private: -}; + switch(rc) + { + case NO_ERROR: + return wxCOND_NO_ERROR; + case ERROR_INVALID_HANDLE: + return wxCOND_INVALID; + default: + return wxCOND_MISC_ERROR; + } +} // ---------------------------------------------------------------------------- // wxCriticalSection implementation @@ -263,12 +310,10 @@ private: wxCriticalSection::wxCriticalSection() { - m_critsect = new wxCriticalSectionInternal; } wxCriticalSection::~wxCriticalSection() { - delete m_critsect; } void wxCriticalSection::Enter() @@ -298,8 +343,24 @@ public: m_nPriority = 0; } + ~wxThreadInternal() + { + Free(); + } + + void Free() + { + if (m_hThread) + { + ::DosExit(0,0); + m_hThread = 0; + } + } + // create a new (suspended) thread (for the given thread object) - bool Create(wxThread* pThread); + bool Create( wxThread* pThread + ,unsigned int uStackSize + ); // suspend/resume/terminate bool Suspend(); @@ -311,7 +372,7 @@ public: inline wxThreadState GetState() const { return m_eState; } // thread priority - inline void SetPriority(unsigned int nPriority) { m_nPriority = nPriority; } + void SetPriority(unsigned int nPriority); inline unsigned int GetPriority() const { return m_nPriority; } // thread handle and id @@ -338,35 +399,36 @@ ULONG wxThreadInternal::OS2ThreadStart( DWORD dwRet = (DWORD)pThread->Entry(); - pThread->p_internal->SetState(STATE_EXITED); + // enter m_critsect before changing the thread state + pThread->m_critsect.Enter(); + + bool bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED; + + pThread->m_internal->SetState(STATE_EXITED); + pThread->m_critsect.Leave(); + pThread->OnExit(); - delete pThread; - m_pThread = NULL; + // if the thread was cancelled (from Delete()), then it the handle is still + // needed there + if (pThread->IsDetached() && !bWasCancelled) + { + // auto delete + delete pThread; + } + //else: the joinable threads handle will be closed when Wait() is done return dwRet; } -bool wxThreadInternal::Create( - wxThread* pThread +void wxThreadInternal::SetPriority( + unsigned int nPriority ) { - APIRET ulrc; - - ulrc = ::DosCreateThread( &m_hThread - ,(PFNTHREAD)wxThreadInternal::OS2ThreadStart - ,(ULONG)pThread - ,CREATE_SUSPENDED | STACK_SPARSE - ,8192L - ); - if(ulrc != 0) - { - wxLogSysError(_("Can't create thread")); - - return FALSE; - } - // translate wxWindows priority to the PM one ULONG ulOS2_Priority; + ULONG ulrc; + + m_nPriority = nPriority; if (m_nPriority <= 20) ulOS2_Priority = PRTYC_NOCHANGE; @@ -392,7 +454,32 @@ bool wxThreadInternal::Create( { wxLogSysError(_("Can't set thread priority")); } - return TRUE; +} + +bool wxThreadInternal::Create( + wxThread* pThread +, unsigned int uStackSize +) +{ + APIRET ulrc; + + ulrc = ::DosCreateThread( &m_hThread + ,(PFNTHREAD)wxThreadInternal::OS2ThreadStart + ,(ULONG)pThread + ,CREATE_SUSPENDED | STACK_SPARSE + ,(ULONG)uStackSize + ); + if(ulrc != 0) + { + wxLogSysError(_("Can't create thread")); + + return FALSE; + } + if (m_nPriority != WXTHREAD_DEFAULT_PRIORITY) + { + SetPriority(m_nPriority); + } + return(TRUE); } bool wxThreadInternal::Suspend() @@ -458,12 +545,29 @@ void wxThread::Sleep( ::DosSleep(ulMilliseconds); } +// ctor and dtor +// ------------- + +wxThread::wxThread(wxThreadKind kind) +{ + m_internal = new wxThreadInternal(); + + m_isDetached = kind == wxTHREAD_DETACHED; +} + +wxThread::~wxThread() +{ + delete m_internal; +} + // create/start thread // ------------------- -wxThreadError wxThread::Create() +wxThreadError wxThread::Create( + unsigned int uStackSize +) { - if ( !p_internal->Create(this) ) + if ( !m_internal->Create(this, uStackSize) ) return wxTHREAD_NO_RESOURCE; return wxTHREAD_NO_ERROR; @@ -473,7 +577,7 @@ wxThreadError wxThread::Run() { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - if ( p_internal->GetState() != STATE_NEW ) + if ( m_internal->GetState() != STATE_NEW ) { // actually, it may be almost any state at all, not only STATE_RUNNING return wxTHREAD_RUNNING; @@ -488,102 +592,94 @@ wxThreadError wxThread::Pause() { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; + return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; } wxThreadError wxThread::Resume() { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; + return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; } // stopping thread // --------------- -wxThread::ExitCode wxThread::Delete() +wxThread::ExitCode wxThread::Wait() { - ExitCode rc = 0; - ULONG ulrc; + // although under Windows we can wait for any thread, it's an error to + // wait for a detached one in wxWin API + wxCHECK_MSG( !IsDetached(), (ExitCode)-1, + _T("can't wait for detached thread") ); + ExitCode rc = (ExitCode)-1; + (void)Delete(&rc); + m_internal->Free(); + return(rc); +} + +wxThreadError wxThread::Delete(ExitCode *pRc) +{ + ExitCode rc = 0; // Delete() is always safe to call, so consider all possible states if (IsPaused()) Resume(); + TID hThread = m_internal->GetHandle(); + if (IsRunning()) { if (IsMain()) { // set flag for wxIsWaitingForThread() - s_bWaitingForThread = TRUE; + gs_bWaitingForThread = TRUE; + +#if wxUSE_GUI wxBeginBusyCursor(); +#endif // wxUSE_GUI } - TID hThread; - + // ask the thread to terminate { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - - p_internal->Cancel(); - hThread = p_internal->GetHandle(); + wxCriticalSectionLocker lock(m_critsect); + m_internal->Cancel(); } - // we can't just wait for the thread to terminate because it might be - // calling some GUI functions and so it will never terminate before we - // process the Windows messages that result from these functions +#if wxUSE_GUI + // need a way to finish GUI processing before killing the thread + // until then we just exit - do + if ((gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread()) { - ulrc = ::DosWaitThread( &hThread - ,DCWW_NOWAIT - ); - switch (ulrc) - { - case ERROR_INTERRUPT: - case ERROR_INVALID_THREADID: - // error - wxLogSysError(_("Can not wait for thread termination")); - Kill(); - return (ExitCode)-1; - - case 0: - // thread we're waiting for terminated - break; - - case ERROR_THREAD_NOT_TERMINATED: - // new message arrived, process it - if (!wxTheApp->DoMessage()) - { - // WM_QUIT received: kill the thread - Kill(); - return (ExitCode)-1; - } - if (IsMain()) - { - // give the thread we're waiting for chance to exit - // from the GUI call it might have been in - if ((s_nWaitingForGui > 0) && wxGuiOwnedByMainThread()) - { - wxMutexGuiLeave(); - } - } - break; - - default: - wxFAIL_MSG(wxT("unexpected result of DosWatiThread")); - } - } while (ulrc != 0); + wxMutexGuiLeave(); + } +#else // !wxUSE_GUI - if (IsMain()) + // can't wait for yourself to end under OS/2 so just quit + +#endif // wxUSE_GUI/!wxUSE_GUI + + if ( IsMain() ) { - s_bWaitingForThread = FALSE; + gs_bWaitingForThread = FALSE; + +#if wxUSE_GUI wxEndBusyCursor(); +#endif // wxUSE_GUI } + } - ::DosExit(EXIT_THREAD, ulrc); + ::DosExit(0, 0); + // probably won't get this far, but + if (IsDetached()) + { + delete this; } - rc = (ExitCode)ulrc; - return rc; + + if ( pRc ) + *pRc = rc; + + return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR; } wxThreadError wxThread::Kill() @@ -591,15 +687,20 @@ wxThreadError wxThread::Kill() if (!IsRunning()) return wxTHREAD_NOT_RUNNING; - ::DosKillThread(p_internal->GetHandle()); - delete this; + ::DosKillThread(m_internal->GetHandle()); + m_internal->Free(); + if (IsDetached()) + { + delete this; + } return wxTHREAD_NO_ERROR; } void wxThread::Exit( - void* pStatus + ExitCode pStatus ) { + m_internal->Free(); delete this; ::DosExit(EXIT_THREAD, ULONG(pStatus)); wxFAIL_MSG(wxT("Couldn't return from DosExit()!")); @@ -611,60 +712,50 @@ void wxThread::SetPriority( { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - p_internal->SetPriority(nPrio); + m_internal->SetPriority(nPrio); } unsigned int wxThread::GetPriority() const { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - return p_internal->GetPriority(); + return m_internal->GetPriority(); } -unsigned long wxThread::GetID() const +unsigned long wxThread::GetId() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast - return (unsigned long)p_internal->GetId(); + return (unsigned long)m_internal->GetId(); } bool wxThread::IsRunning() const { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - return p_internal->GetState() == STATE_RUNNING; + return(m_internal->GetState() == STATE_RUNNING); } bool wxThread::IsAlive() const { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - return (p_internal->GetState() == STATE_RUNNING) || - (p_internal->GetState() == STATE_PAUSED); + return (m_internal->GetState() == STATE_RUNNING) || + (m_internal->GetState() == STATE_PAUSED); } bool wxThread::IsPaused() const { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - return (p_internal->GetState() == STATE_PAUSED); + return (m_internal->GetState() == STATE_PAUSED); } bool wxThread::TestDestroy() { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - return p_internal->GetState() == STATE_CANCELED; -} - -wxThread::wxThread() -{ - p_internal = new wxThreadInternal(); -} - -wxThread::~wxThread() -{ - delete p_internal; + return m_internal->GetState() == STATE_CANCELED; } // ---------------------------------------------------------------------------- @@ -685,10 +776,10 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) bool wxThreadModule::OnInit() { - s_pCritsectWaitingForGui = new wxCriticalSection(); + gs_pCritsectWaitingForGui = new wxCriticalSection(); - s_pCritsectGui = new wxCriticalSection(); - s_pCritsectGui->Enter(); + gs_pCritsectGui = new wxCriticalSection(); + gs_pCritsectGui->Enter(); PTIB ptib; PPIB ppib; @@ -701,14 +792,18 @@ bool wxThreadModule::OnInit() void wxThreadModule::OnExit() { - if (s_pCritsectGui) + if (gs_pCritsectGui) { - s_pCritsectGui->Leave(); - delete s_pCritsectGui; - s_pCritsectGui = NULL; + gs_pCritsectGui->Leave(); +#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ))) + delete gs_pCritsectGui; +#endif + gs_pCritsectGui = NULL; } - wxDELETE(s_pCritsectWaitingForGui); +#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ))) + wxDELETE(gs_pCritsectWaitingForGui); +#endif } // ---------------------------------------------------------------------------- @@ -722,24 +817,24 @@ void WXDLLEXPORT wxWakeUpMainThread() void WXDLLEXPORT wxMutexGuiLeave() { - wxCriticalSectionLocker enter(*s_pCritsectWaitingForGui); + wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui); if ( wxThread::IsMain() ) { - s_bGuiOwnedByMainThread = FALSE; + gs_bGuiOwnedByMainThread = FALSE; } else { // decrement the number of waiters now - wxASSERT_MSG( s_nWaitingForGui > 0, + wxASSERT_MSG(gs_nWaitingForGui > 0, wxT("calling wxMutexGuiLeave() without entering it first?") ); - s_nWaitingForGui--; + gs_nWaitingForGui--; wxWakeUpMainThread(); } - s_pCritsectGui->Leave(); + gs_pCritsectGui->Leave(); } void WXDLLEXPORT wxMutexGuiLeaveOrEnter() @@ -747,17 +842,17 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); - wxCriticalSectionLocker enter(*s_pCritsectWaitingForGui); + wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui); - if ( s_nWaitingForGui == 0 ) + if (gs_nWaitingForGui == 0) { // no threads are waiting for GUI - so we may acquire the lock without // any danger (but only if we don't already have it) if (!wxGuiOwnedByMainThread()) { - s_pCritsectGui->Enter(); + gs_pCritsectGui->Enter(); - s_bGuiOwnedByMainThread = TRUE; + gs_bGuiOwnedByMainThread = TRUE; } //else: already have it, nothing to do } @@ -774,7 +869,12 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() bool WXDLLEXPORT wxGuiOwnedByMainThread() { - return s_bGuiOwnedByMainThread; + return gs_bGuiOwnedByMainThread; +} + +bool WXDLLEXPORT wxIsWaitingForThread() +{ + return gs_bWaitingForThread; } #endif