// Created: 04/22/98
// RCS-ID: $Id$
// Copyright: (c) Stefan Neis (2003)
-//
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#ifdef __GNUG__
- #pragma implementation "thread.h"
-#endif
-
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if wxUSE_THREADS
-#include <stdio.h>
+#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 <stdio.h>
#define INCL_DOSSEMAPHORES
#define INCL_DOSPROCESS
// 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
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
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:
// (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;
}
}
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;
switch (ulrc)
{
case ERROR_TIMEOUT:
+ return wxMUTEX_TIMEOUT;
case ERROR_TOO_MANY_SEM_REQUESTS:
return wxMUTEX_BUSY;
ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE);
if (ulrc != 0)
{
- wxLogLastError(_T("DosCreateMutexSem()"));
+ wxLogLastError(wxT("DosCreateMutexSem()"));
m_vMutex = NULL;
m_vEvent = NULL;
return;
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;
{
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;
return wxSEMA_TIMEOUT;
default:
- wxLogLastError(_T("DosWaitEventSem(semaphore)"));
+ wxLogLastError(wxT("DosWaitEventSem(semaphore)"));
return wxSEMA_MISC_ERROR;
}
ulrc = :: DosRequestMutexSem(m_vMutex, ulMilliseconds);
return wxSEMA_OVERFLOW;
if ( ulrc != NO_ERROR && ulrc != ERROR_ALREADY_POSTED )
{
- wxLogLastError(_T("DosPostEventSem(semaphore)"));
+ wxLogLastError(wxT("DosPostEventSem(semaphore)"));
return wxSEMA_MISC_ERROR;
}
{
m_hThread = 0;
m_eState = STATE_NEW;
- m_nPriority = WXTHREAD_DEFAULT_PRIORITY;
+ m_nPriority = wxPRIORITY_DEFAULT;
}
~wxThreadInternal()
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();
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;
}
}
-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
m_eState = STATE_RUNNING;
}
- return TRUE;
+ return true;
}
// static functions
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
::DosSleep(0);
}
-void wxThread::Sleep(
- unsigned long ulMilliseconds
-)
-{
- ::DosSleep(ulMilliseconds);
-}
-
int wxThread::GetCPUCount()
{
ULONG CPUCount;
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 )
{
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
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;
// 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;
// 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
{
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
{
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 )
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
}
}
- 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
if ( IsMain() )
{
- gs_bWaitingForThread = FALSE;
+ gs_bWaitingForThread = false;
}
}
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()!"));
}
gs_pCritsectGui = new wxCriticalSection();
gs_pCritsectGui->Enter();
- PTIB ptib;
- PPIB ppib;
+ wxThread::ms_idMainThread = wxThread::GetCurrentId();
- ::DosGetInfoBlocks(&ptib, &ppib);
-
- s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid;
- return TRUE;
+ return true;
}
void wxThreadModule::OnExit()
// wake up the main thread if it's in ::GetMessage()
void WXDLLEXPORT wxWakeUpMainThread()
{
+#if 0
if ( !::WinPostQueueMsg(wxTheApp->m_hMq, WM_NULL, 0, 0) )
{
// should never happen
wxLogLastError(wxT("WinPostMessage(WM_NULL)"));
}
+#endif
}
-void WXDLLEXPORT wxMutexGuiEnter()
+void wxMutexGuiEnterImpl()
{
// this would dead lock everything...
wxASSERT_MSG( !wxThread::IsMain(),
gs_pCritsectGui->Enter();
}
-void WXDLLEXPORT wxMutexGuiLeave()
+void wxMutexGuiLeaveImpl()
{
wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
if ( wxThread::IsMain() )
{
- gs_bGuiOwnedByMainThread = FALSE;
+ gs_bGuiOwnedByMainThread = false;
}
else
{
{
gs_pCritsectGui->Enter();
- gs_bGuiOwnedByMainThread = TRUE;
+ gs_bGuiOwnedByMainThread = true;
}
//else: already have it, nothing to do
}