X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8e5052faec2ffcf85cd65194877071faa4015ee8..fb8d7eb7a880f1f2e32d8830f9c5e12b2536e05f:/src/os2/thread.cpp diff --git a/src/os2/thread.cpp b/src/os2/thread.cpp index f9fe2f123f..b17b17cb83 100644 --- a/src/os2/thread.cpp +++ b/src/os2/thread.cpp @@ -6,14 +6,9 @@ // Created: 04/22/98 // RCS-ID: $Id$ // Copyright: (c) Stefan Neis (2003) -// // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ - #pragma implementation "thread.h" -#endif - // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- @@ -23,14 +18,19 @@ #if wxUSE_THREADS -#include +#include "wx/thread.h" -#include "wx/app.h" -#include "wx/module.h" -#include "wx/intl.h" +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/module.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" #include "wx/utils.h" -#include "wx/log.h" -#include "wx/thread.h" + +#include #define INCL_DOSSEMAPHORES #define INCL_DOSPROCESS @@ -57,14 +57,14 @@ enum wxThreadState // id of the main thread - the one which can call GUI functions without first // calling wxMutexGuiEnter() -static ULONG s_ulIdMainThread = 1; +wxThreadIdType wxThread::ms_idMainThread = 0; wxMutex* p_wxMainMutex; // OS2 substitute for Tls pointer the current parent thread object -wxThread* m_pThread; // pointer to the wxWindows thread object +wxThread* m_pThread; // pointer to the wxWidgets thread object -// if it's FALSE, some secondary thread is holding the GUI lock -static bool gs_bGuiOwnedByMainThread = TRUE; +// if it's false, some secondary thread is holding the GUI lock +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 @@ -78,7 +78,7 @@ static wxCriticalSection *gs_pCritsectWaitingForGui = NULL; static size_t gs_nWaitingForGui = 0; // are we waiting for a thread termination? -static bool gs_bWaitingForThread = FALSE; +static bool gs_bWaitingForThread = false; // ============================================================================ // OS/2 implementation of thread and related classes @@ -96,7 +96,8 @@ public: bool IsOk() const { return m_vMutex != NULL; } wxMutexError Lock() { return LockTimeout(SEM_INDEFINITE_WAIT); } - wxMutexError TryLock() { return LockTimeout(SEM_IMMEDIATE_RETURN); } + wxMutexError Lock(unsigned long ms) { return LockTimeout(ms); } + wxMutexError TryLock(); wxMutexError Unlock(); private: @@ -108,16 +109,12 @@ private: // (Calls to DosRequestMutexSem and DosReleaseMutexSem can be nested, but // the request count for a semaphore cannot exceed 65535. If an attempt is // made to exceed this number, ERROR_TOO_MANY_SEM_REQUESTS is returned.) -wxMutexInternal::wxMutexInternal( - wxMutexType WXUNUSED(eMutexType) -) +wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(eMutexType)) { - APIRET ulrc; - - ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE); + APIRET ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE); if (ulrc != 0) { - wxLogSysError(_("Can not create mutex.")); + wxLogSysError(_("Cannot create mutex.")); m_vMutex = NULL; } } @@ -127,10 +124,20 @@ wxMutexInternal::~wxMutexInternal() if (m_vMutex) { if (::DosCloseMutexSem(m_vMutex)) - wxLogLastError(_T("DosCloseMutexSem(mutex)")); + { + wxLogLastError(wxT("DosCloseMutexSem(mutex)")); + } } } +wxMutexError wxMutexInternal::TryLock() +{ + const wxMutexError rc = LockTimeout( SEM_IMMEDIATE_RETURN ); + + // we have a special return code for timeout in this case + return rc == wxMUTEX_TIMEOUT ? wxMUTEX_BUSY : rc; +} + wxMutexError wxMutexInternal::LockTimeout(ULONG ulMilliseconds) { APIRET ulrc; @@ -140,6 +147,7 @@ wxMutexError wxMutexInternal::LockTimeout(ULONG ulMilliseconds) switch (ulrc) { case ERROR_TIMEOUT: + return wxMUTEX_TIMEOUT; case ERROR_TOO_MANY_SEM_REQUESTS: return wxMUTEX_BUSY; @@ -213,7 +221,7 @@ wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE); if (ulrc != 0) { - wxLogLastError(_T("DosCreateMutexSem()")); + wxLogLastError(wxT("DosCreateMutexSem()")); m_vMutex = NULL; m_vEvent = NULL; return; @@ -221,7 +229,7 @@ wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) ulrc = ::DosCreateEventSem(NULL, &m_vEvent, 0L, FALSE); if ( ulrc != 0) { - wxLogLastError(_T("DosCreateEventSem()")); + wxLogLastError(wxT("DosCreateEventSem()")); ::DosCloseMutexSem(m_vMutex); m_vMutex = NULL; m_vEvent = NULL; @@ -236,11 +244,11 @@ wxSemaphoreInternal::~wxSemaphoreInternal() { if ( ::DosCloseEventSem(m_vEvent) ) { - wxLogLastError(_T("DosCloseEventSem(semaphore)")); + wxLogLastError(wxT("DosCloseEventSem(semaphore)")); } if ( ::DosCloseMutexSem(m_vMutex) ) { - wxLogLastError(_T("DosCloseMutexSem(semaphore)")); + wxLogLastError(wxT("DosCloseMutexSem(semaphore)")); } else m_vEvent = NULL; @@ -264,7 +272,7 @@ wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long ulMilliseconds) return wxSEMA_TIMEOUT; default: - wxLogLastError(_T("DosWaitEventSem(semaphore)")); + wxLogLastError(wxT("DosWaitEventSem(semaphore)")); return wxSEMA_MISC_ERROR; } ulrc = :: DosRequestMutexSem(m_vMutex, ulMilliseconds); @@ -324,7 +332,7 @@ wxSemaError wxSemaphoreInternal::Post() return wxSEMA_OVERFLOW; if ( ulrc != NO_ERROR && ulrc != ERROR_ALREADY_POSTED ) { - wxLogLastError(_T("DosPostEventSem(semaphore)")); + wxLogLastError(wxT("DosPostEventSem(semaphore)")); return wxSEMA_MISC_ERROR; } @@ -346,7 +354,7 @@ public: { m_hThread = 0; m_eState = STATE_NEW; - m_nPriority = WXTHREAD_DEFAULT_PRIORITY; + m_nPriority = wxPRIORITY_DEFAULT; } ~wxThreadInternal() @@ -377,43 +385,51 @@ public: TID GetId() const { return m_hThread; } // thread function - static DWORD OS2ThreadStart(ULONG ulParam); + static void OS2ThreadStart(void* pParam); private: // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID // PM also has no real Tls mechanism to index pointers by so we'll just - // keep track of the wxWindows parent object here. + // keep track of the wxWidgets parent object here. TID m_hThread; // handle and ID of the thread wxThreadState m_eState; // state, see wxThreadState enum unsigned int m_nPriority; // thread priority in "wx" units }; -ULONG wxThreadInternal::OS2ThreadStart( - ULONG ulParam -) +void wxThreadInternal::OS2ThreadStart( void * pParam ) { - DWORD dwRet; + DWORD dwRet; bool bWasCancelled; - // first of all, check whether we hadn't been cancelled already and don't - // start the user code at all then - wxThread *pThread = (wxThread *)ulParam; + wxThread *pThread = (wxThread *)pParam; + + // first of all, wait for the thread to be started. + pThread->m_critsect.Enter(); + pThread->m_critsect.Leave(); + // Now check whether we hadn't been cancelled already and don't + // start the user code at all in this case. if ( pThread->m_internal->GetState() == STATE_EXITED ) { dwRet = (DWORD)-1; - bWasCancelled = TRUE; + bWasCancelled = true; } else // do run thread { + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + unsigned long ulHab; + if (traits) + traits->InitializeGui(ulHab); dwRet = (DWORD)pThread->Entry(); + if (traits) + traits->TerminateGui(ulHab); - // enter m_critsect before changing the thread state - pThread->m_critsect.Enter(); + // enter m_critsect before changing the thread state + pThread->m_critsect.Enter(); - bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED; + bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED; - pThread->m_internal->SetState(STATE_EXITED); - pThread->m_critsect.Leave(); + pThread->m_internal->SetState(STATE_EXITED); + pThread->m_critsect.Leave(); } pThread->OnExit(); @@ -425,14 +441,14 @@ ULONG wxThreadInternal::OS2ThreadStart( delete pThread; } //else: the joinable threads handle will be closed when Wait() is done - return dwRet; + return; } void wxThreadInternal::SetPriority( unsigned int nPriority ) { - // translate wxWindows priority to the PM one + // translate wxWidgets priority to the PM one ULONG ulOS2_PriorityClass; ULONG ulOS2_SubPriority; ULONG ulrc; @@ -463,54 +479,54 @@ void wxThreadInternal::SetPriority( } } -bool wxThreadInternal::Create( - wxThread* pThread -, unsigned int uStackSize -) +bool wxThreadInternal::Create( wxThread* pThread, + unsigned int uStackSize) { - APIRET ulrc; + int tid; - ulrc = ::DosCreateThread( &m_hThread - ,(PFNTHREAD)wxThreadInternal::OS2ThreadStart - ,(ULONG)pThread - ,CREATE_SUSPENDED | STACK_SPARSE - ,(ULONG)uStackSize - ); - if(ulrc != 0) + if (!uStackSize) + uStackSize = 131072; + + pThread->m_critsect.Enter(); + tid = _beginthread(wxThreadInternal::OS2ThreadStart, + NULL, uStackSize, pThread); + if(tid == -1) { wxLogSysError(_("Can't create thread")); - return FALSE; + return false; } - if (m_nPriority != WXTHREAD_DEFAULT_PRIORITY) + m_hThread = tid; + if (m_nPriority != wxPRIORITY_DEFAULT) { SetPriority(m_nPriority); } - return(TRUE); + return true; } bool wxThreadInternal::Suspend() { - ULONG ulrc = ::DosSuspendThread(m_hThread); + ULONG ulrc = ::DosSuspendThread(m_hThread); if (ulrc != 0) { - wxLogSysError(_("Can not suspend thread %lu"), m_hThread); - return FALSE; + wxLogSysError(_("Cannot suspend thread %lu"), m_hThread); + return false; } m_eState = STATE_PAUSED; - return TRUE; + + return true; } bool wxThreadInternal::Resume() { - ULONG ulrc = ::DosResumeThread(m_hThread); + ULONG ulrc = ::DosResumeThread(m_hThread); if (ulrc != 0) { - wxLogSysError(_("Can not suspend thread %lu"), m_hThread); - return FALSE; + wxLogSysError(_("Cannot resume thread %lu"), m_hThread); + return false; } // don't change the state from STATE_EXITED because it's special and means @@ -521,32 +537,18 @@ bool wxThreadInternal::Resume() m_eState = STATE_RUNNING; } - return TRUE; + return true; } // static functions // ---------------- -bool WXDLLEXPORT wxGuiOwnedByMainThread(); - wxThread *wxThread::This() { wxThread* pThread = m_pThread; return pThread; } -bool wxThread::IsMain() -{ - PTIB ptib; - PPIB ppib; - - ::DosGetInfoBlocks(&ptib, &ppib); - - if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread) - return TRUE; - return FALSE; -} - #ifdef Yield #undef Yield #endif @@ -556,13 +558,6 @@ void wxThread::Yield() ::DosSleep(0); } -void wxThread::Sleep( - unsigned long ulMilliseconds -) -{ - ::DosSleep(ulMilliseconds); -} - int wxThread::GetCPUCount() { ULONG CPUCount; @@ -576,18 +571,18 @@ int wxThread::GetCPUCount() return CPUCount; } -unsigned long wxThread::GetCurrentId() +wxThreadIdType wxThread::GetCurrentId() { PTIB ptib; PPIB ppib; ::DosGetInfoBlocks(&ptib, &ppib); - return (unsigned long) ptib->tib_ptib2->tib2_ultid; + return (wxThreadIdType) ptib->tib_ptib2->tib2_ultid; } bool wxThread::SetConcurrency(size_t level) { - wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") ); + wxASSERT_MSG( IsMain(), wxT("should only be called from the main thread") ); // ok only for the default one if ( level == 0 ) @@ -631,6 +626,14 @@ wxThreadError wxThread::Run() { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + // Create the thread if it wasn't created yet with an explicit + // Create() call: + if ( !m_internal->GetHandle() ) + { + if ( !m_internal->Create(this, 0) ) + return wxTHREAD_NO_RESOURCE; + } + if ( m_internal->GetState() != STATE_NEW ) { // actually, it may be almost any state at all, not only STATE_RUNNING @@ -651,6 +654,13 @@ wxThreadError wxThread::Pause() wxThreadError wxThread::Resume() { + if (m_internal->GetState() == STATE_NEW) + { + m_internal->SetState(STATE_RUNNING); + m_critsect.Leave(); + return wxTHREAD_NO_ERROR; + } + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; @@ -659,18 +669,18 @@ wxThreadError wxThread::Resume() // stopping thread // --------------- -wxThread::ExitCode wxThread::Wait() +wxThread::ExitCode wxThread::Wait(wxThreadWait waitMode) { // 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") ); + wxT("can't wait for detached thread") ); ExitCode rc = (ExitCode)-1; - (void)Delete(&rc); + (void)Delete(&rc, waitMode); return(rc); } -wxThreadError wxThread::Delete(ExitCode *pRc) +wxThreadError wxThread::Delete(ExitCode *pRc, wxThreadWait WXUNUSED(waitMode)) { ExitCode rc = 0; @@ -678,9 +688,9 @@ wxThreadError wxThread::Delete(ExitCode *pRc) // we might need to resume the thread, but we might also not need to cancel // it if it doesn't run yet - bool shouldResume = FALSE, - shouldCancel = TRUE, - isRunning = FALSE; + bool shouldResume = false, + shouldCancel = true, + isRunning = false; // check if the thread already started to run { @@ -695,10 +705,10 @@ wxThreadError wxThread::Delete(ExitCode *pRc) Resume(); // it knows about STATE_EXITED special case - shouldCancel = FALSE; - isRunning = TRUE; + shouldCancel = false; + isRunning = true; - // shouldResume is correctly set to FALSE here + // shouldResume is correctly set to false here } else { @@ -710,15 +720,15 @@ wxThreadError wxThread::Delete(ExitCode *pRc) if ( shouldResume ) Resume(); - TID hThread = m_internal->GetHandle(); + TID hThread = m_internal->GetHandle(); if ( isRunning || IsRunning()) { if (IsMain()) { // set flag for wxIsWaitingForThread() - gs_bWaitingForThread = TRUE; - } + gs_bWaitingForThread = true; + } // ask the thread to terminate if ( shouldCancel ) @@ -728,7 +738,7 @@ wxThreadError wxThread::Delete(ExitCode *pRc) m_internal->Cancel(); } -#if wxUSE_GUI +#if 0 // 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 @@ -745,25 +755,42 @@ wxThreadError wxThread::Delete(ExitCode *pRc) } } - result = ::DosWaitThread(&hThread, DCWW_WAIT); - // FIXME: We ought to have a message processing loop here!! + result = ::DosWaitThread(&hThread, DCWW_NOWAIT); + // FIXME: We ought to have a message processing loop here!! switch ( result ) - { - case ERROR_THREAD_NOT_TERMINATED: - case ERROR_INVALID_THREADID: - // error - wxLogSysError(_("Can not wait for thread termination")); - Kill(); - return wxTHREAD_KILLED; - + { + case ERROR_INTERRUPT: + case ERROR_THREAD_NOT_TERMINATED: + break; + case ERROR_INVALID_THREADID: case NO_ERROR: - // thread we're waiting for terminated + // thread we're waiting for just terminated + // or even does not exist any more. + result = NO_ERROR; break; - default: wxFAIL_MSG(wxT("unexpected result of DosWaitThread")); } + if ( IsMain() ) + { + // event processing - needed if we are the main thread + // to give other threads a chance to do remaining GUI + // processing and terminate cleanly. + wxTheApp->HandleSockets(); + if (wxTheApp->Pending()) + if ( !wxTheApp->DoMessage() ) + { + // WM_QUIT received: kill the thread + Kill(); + + return wxTHREAD_KILLED; + } + else + wxUsleep(10); + } + else + wxUsleep(10); } while ( result != NO_ERROR ); #else // !wxUSE_GUI // simply wait for the thread to terminate @@ -778,7 +805,7 @@ wxThreadError wxThread::Delete(ExitCode *pRc) if ( IsMain() ) { - gs_bWaitingForThread = FALSE; + gs_bWaitingForThread = false; } } @@ -825,12 +852,10 @@ wxThreadError wxThread::Kill() return wxTHREAD_NO_ERROR; } -void wxThread::Exit( - ExitCode pStatus -) +void wxThread::Exit(ExitCode WXUNUSED(pStatus)) { delete this; - ::DosExit(EXIT_THREAD, ULONG(pStatus)); + _endthread(); wxFAIL_MSG(wxT("Couldn't return from DosExit()!")); } @@ -909,13 +934,9 @@ bool wxThreadModule::OnInit() gs_pCritsectGui = new wxCriticalSection(); gs_pCritsectGui->Enter(); - PTIB ptib; - PPIB ppib; - - ::DosGetInfoBlocks(&ptib, &ppib); + wxThread::ms_idMainThread = wxThread::GetCurrentId(); - s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid; - return TRUE; + return true; } void wxThreadModule::OnExit() @@ -950,7 +971,7 @@ void WXDLLEXPORT wxWakeUpMainThread() #endif } -void WXDLLEXPORT wxMutexGuiEnter() +void wxMutexGuiEnterImpl() { // this would dead lock everything... wxASSERT_MSG( !wxThread::IsMain(), @@ -972,13 +993,13 @@ void WXDLLEXPORT wxMutexGuiEnter() gs_pCritsectGui->Enter(); } -void WXDLLEXPORT wxMutexGuiLeave() +void wxMutexGuiLeaveImpl() { wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui); if ( wxThread::IsMain() ) { - gs_bGuiOwnedByMainThread = FALSE; + gs_bGuiOwnedByMainThread = false; } else { @@ -1009,7 +1030,7 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() { gs_pCritsectGui->Enter(); - gs_bGuiOwnedByMainThread = TRUE; + gs_bGuiOwnedByMainThread = true; } //else: already have it, nothing to do }