X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d90895ac118ad4546eed7ee4c358a3fe644a1ad7..19e30148e18cc99296b26503c155e5cef59045f4:/src/os2/thread.cpp?ds=inline diff --git a/src/os2/thread.cpp b/src/os2/thread.cpp index c636e6e9ae..af2e0f7304 100644 --- a/src/os2/thread.cpp +++ b/src/os2/thread.cpp @@ -20,12 +20,18 @@ #include -#define INCL_DOS -#include - #include "wx/module.h" +#include "wx/intl.h" +#include "wx/utils.h" +#include "wx/log.h" #include "wx/thread.h" +#define INCL_DOSSEMAPHORES +#define INCL_DOSPROCESS +#define INCL_ERRORS +#include +#include + // the possible states of the thread ("=>" shows all possible transitions from // this state) enum wxThreadState @@ -41,32 +47,33 @@ enum wxThreadState // static variables // ---------------------------------------------------------------------------- -// TLS index of the slot where we store the pointer to the current thread -static DWORD s_tlsThisThread = 0xFFFFFFFF; - // id of the main thread - the one which can call GUI functions without first // calling wxMutexGuiEnter() -static DWORD s_idMainThread = 0; +static ULONG s_ulIdMainThread = 0; +wxMutex* p_wxMainMutex; + +// OS2 substitute for Tls pointer the current parent thread object +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_critsectGui = NULL; +static wxCriticalSection *gs_pCritsectGui = NULL; // critical section which protects s_nWaitingForGui variable -static wxCriticalSection *s_critsectWaitingForGui = 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_waitingForThread = FALSE; +static bool gs_bWaitingForThread = FALSE; // ============================================================================ -// Windows implementation of thread classes +// OS/2 implementation of thread classes // ============================================================================ // ---------------------------------------------------------------------------- @@ -75,18 +82,19 @@ static bool s_waitingForThread = FALSE; class wxMutexInternal { public: - HANDLE p_mutex; + HMTX m_vMutex; }; wxMutex::wxMutex() { - p_internal = new wxMutexInternal; -// p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL); - if ( !p_internal->p_mutex ) + APIRET ulrc; + + m_internal = new wxMutexInternal; + ulrc = ::DosCreateMutexSem(NULL, &m_internal->m_vMutex, 0L, FALSE); + if (ulrc != 0) { wxLogSysError(_("Can not create mutex.")); } - m_locked = 0; } @@ -94,66 +102,64 @@ wxMutex::~wxMutex() { if (m_locked > 0) wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked); -// CloseHandle(p_internal->p_mutex); + ::DosCloseMutexSem(m_internal->m_vMutex); + m_internal->m_vMutex = NULL; } wxMutexError wxMutex::Lock() { - DWORD ret; + APIRET ulrc; -// TODO: -/* - ret = WaitForSingleObject(p_internal->p_mutex, INFINITE); - switch ( ret ) + ulrc = ::DosRequestMutexSem(m_internal->m_vMutex, SEM_INDEFINITE_WAIT); + + switch (ulrc) { - case WAIT_ABANDONED: + case ERROR_TOO_MANY_SEM_REQUESTS: return wxMUTEX_BUSY; - case WAIT_OBJECT_0: + case NO_ERROR: // ok break; - case WAIT_FAILED: + case ERROR_INVALID_HANDLE: + case ERROR_INTERRUPT: + case ERROR_SEM_OWNER_DIED: wxLogSysError(_("Couldn't acquire a mutex lock")); return wxMUTEX_MISC_ERROR; - case WAIT_TIMEOUT: + case ERROR_TIMEOUT: default: wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock")); } - m_locked++; -*/ return wxMUTEX_NO_ERROR; } wxMutexError wxMutex::TryLock() { - DWORD ret; + ULONG ulrc; -// TODO: -/* - ret = WaitForSingleObject(p_internal->p_mutex, 0); - if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED) + 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; } wxMutexError wxMutex::Unlock() { + APIRET ulrc; + if (m_locked > 0) m_locked--; - BOOL ret = 0; // TODO: ReleaseMutex(p_internal->p_mutex); - if ( ret == 0 ) + ulrc = ::DosReleaseMutexSem(m_internal->m_vMutex); + if (ulrc != 0) { wxLogSysError(_("Couldn't release a mutex")); return wxMUTEX_MISC_ERROR; } - return wxMUTEX_NO_ERROR; } @@ -164,117 +170,120 @@ wxMutexError wxMutex::Unlock() class wxConditionInternal { public: - HANDLE event; - int waiters; + 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 bool Wait( + unsigned long ulTimeout + ) + { + APIRET ulrc; + + m_nWaiters++; + ulrc = ::DosWaitEventSem(m_vEvent, ulTimeout); + m_nWaiters--; + return (ulrc != ERROR_TIMEOUT); + } + + 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) { - p_internal = new wxConditionInternal; -// TODO: -/* - p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL); - if ( !p_internal->event ) + APIRET ulrc; + ULONG ulCount; + + 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->waiters = 0; + m_internal->m_nWaiters = 0; + // ?? just for good measure? + ::DosResetEventSem(m_internal->m_vEvent, &ulCount); } wxCondition::~wxCondition() { -// CloseHandle(p_internal->event); + ::DosCloseEventSem(m_internal->m_vEvent); + delete m_internal; + m_internal = NULL; } -void wxCondition::Wait(wxMutex& mutex) +void wxCondition::Wait() { - mutex.Unlock(); - p_internal->waiters++; -// WaitForSingleObject(p_internal->event, INFINITE); - p_internal->waiters--; - mutex.Lock(); + (void)m_internal->Wait(SEM_INDEFINITE_WAIT); } -bool wxCondition::Wait(wxMutex& mutex, - unsigned long sec, - unsigned long nsec) +bool wxCondition::Wait( + unsigned long lMilliSec +) { - DWORD ret; - - mutex.Unlock(); - p_internal->waiters++; -// ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000)); - p_internal->waiters--; - mutex.Lock(); - -// return (ret != WAIT_TIMEOUT); - return FALSE; + return m_internal->Wait(lMilliSec); } void wxCondition::Signal() { -// SetEvent(p_internal->event); + ::DosPostEventSem(m_internal->m_vEvent); } void wxCondition::Broadcast() { - int i; + int i; -// TODO: -/* - for (i=0;iwaiters;i++) + for (i = 0; i < m_internal->m_nWaiters; i++) { - if ( SetEvent(p_internal->event) == 0 ) + if (::DosPostEventSem(m_internal->m_vEvent) != 0) { wxLogSysError(_("Couldn't change the state of event object.")); } } -*/ } // ---------------------------------------------------------------------------- // wxCriticalSection implementation // ---------------------------------------------------------------------------- -#define CRITICAL_SECTION ULONG -class wxCriticalSectionInternal -{ -public: - // init the critical section object - wxCriticalSectionInternal() - { //::InitializeCriticalSection(&m_data); - } - - // implicit cast to the associated data - operator CRITICAL_SECTION *() { return &m_data; } - - // free the associated ressources - ~wxCriticalSectionInternal() - { //::DeleteCriticalSection(&m_data); - } - -private: - CRITICAL_SECTION m_data; -}; wxCriticalSection::wxCriticalSection() { - m_critsect = new wxCriticalSectionInternal; } wxCriticalSection::~wxCriticalSection() { - delete m_critsect; } void wxCriticalSection::Enter() { -//TODO: ::EnterCriticalSection(*m_critsect); + ::DosEnterCritSec(); } void wxCriticalSection::Leave() { -// TODO: ::LeaveCriticalSection(*m_critsect); + ::DosExitCritSec(); } // ---------------------------------------------------------------------------- @@ -287,144 +296,176 @@ void wxCriticalSection::Leave() class wxThreadInternal { public: - wxThreadInternal() + inline wxThreadInternal() { m_hThread = 0; - m_state = STATE_NEW; - m_priority = 0; // TODO: WXTHREAD_DEFAULT_PRIORITY; + m_eState = STATE_NEW; + 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 *thread); + bool Create( wxThread* pThread + ,unsigned int uStackSize + ); // suspend/resume/terminate bool Suspend(); bool Resume(); - void Cancel() { m_state = STATE_CANCELED; } + inline void Cancel() { m_eState = STATE_CANCELED; } // thread state - void SetState(wxThreadState state) { m_state = state; } - wxThreadState GetState() const { return m_state; } + inline void SetState(wxThreadState eState) { m_eState = eState; } + inline wxThreadState GetState() const { return m_eState; } // thread priority - void SetPriority(unsigned int priority) { m_priority = priority; } - unsigned int GetPriority() const { return m_priority; } + void SetPriority(unsigned int nPriority); + inline unsigned int GetPriority() const { return m_nPriority; } // thread handle and id - HANDLE GetHandle() const { return m_hThread; } - DWORD GetId() const { return m_tid; } + inline TID GetHandle() const { return m_hThread; } + TID GetId() const { return m_hThread; } // thread function static DWORD OS2ThreadStart(wxThread *thread); private: - HANDLE m_hThread; // handle of the thread - wxThreadState m_state; // state, see wxThreadState enum - unsigned int m_priority; // thread priority in "wx" units - DWORD m_tid; // thread id + // 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. + 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 }; -DWORD wxThreadInternal::OS2ThreadStart(wxThread *thread) +ULONG wxThreadInternal::OS2ThreadStart( + wxThread* pThread +) { - // store the thread object in the TLS -// TODO: -/* - if ( !::TlsSetValue(s_tlsThisThread, thread) ) - { - wxLogSysError(_("Can not start thread: error writing TLS.")); + m_pThread = pThread; - return (DWORD)-1; - } -*/ - DWORD ret = (DWORD)thread->Entry(); - thread->p_internal->SetState(STATE_EXITED); - thread->OnExit(); + DWORD dwRet = (DWORD)pThread->Entry(); - delete thread; + // enter m_critsect before changing the thread state + pThread->m_critsect.Enter(); - return ret; -} + bool bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED; -bool wxThreadInternal::Create(wxThread *thread) -{ -// TODO: -/* - m_hThread = ::CreateThread - ( - NULL, // default security - 0, // default stack size - (LPTHREAD_START_ROUTINE) // thread entry point - wxThreadInternal::OS2ThreadStart, // - (LPVOID)thread, // parameter - CREATE_SUSPENDED, // flags - &m_tid // [out] thread id - ); + pThread->m_internal->SetState(STATE_EXITED); + pThread->m_critsect.Leave(); - if ( m_hThread == NULL ) - { - wxLogSysError(_("Can't create thread")); + pThread->OnExit(); - return FALSE; + // if the thread was cancelled (from Delete()), then it the handle is still + // needed there + if (pThread->IsDetached() && !bWasCancelled) + { + // auto delete + delete pThread; } - - // translate wxWindows priority to the Windows one - int win_priority; - if (m_priority <= 20) - win_priority = THREAD_PRIORITY_LOWEST; - else if (m_priority <= 40) - win_priority = THREAD_PRIORITY_BELOW_NORMAL; - else if (m_priority <= 60) - win_priority = THREAD_PRIORITY_NORMAL; - else if (m_priority <= 80) - win_priority = THREAD_PRIORITY_ABOVE_NORMAL; - else if (m_priority <= 100) - win_priority = THREAD_PRIORITY_HIGHEST; + //else: the joinable threads handle will be closed when Wait() is done + return dwRet; +} + +void wxThreadInternal::SetPriority( + unsigned int nPriority +) +{ + // translate wxWindows priority to the PM one + ULONG ulOS2_Priority; + ULONG ulrc; + + m_nPriority = nPriority; + + if (m_nPriority <= 20) + ulOS2_Priority = PRTYC_NOCHANGE; + else if (m_nPriority <= 40) + ulOS2_Priority = PRTYC_IDLETIME; + else if (m_nPriority <= 60) + ulOS2_Priority = PRTYC_REGULAR; + else if (m_nPriority <= 80) + ulOS2_Priority = PRTYC_TIMECRITICAL; + else if (m_nPriority <= 100) + ulOS2_Priority = PRTYC_FOREGROUNDSERVER; else { wxFAIL_MSG(wxT("invalid value of thread priority parameter")); - win_priority = THREAD_PRIORITY_NORMAL; + ulOS2_Priority = PRTYC_REGULAR; } - - if ( ::SetThreadPriority(m_hThread, win_priority) == 0 ) + ulrc = ::DosSetPriority( PRTYS_THREAD + ,ulOS2_Priority + ,0 + ,(ULONG)m_hThread + ); + if (ulrc != 0) { wxLogSysError(_("Can't set thread priority")); } -*/ - return FALSE; } -bool wxThreadInternal::Suspend() +bool wxThreadInternal::Create( + wxThread* pThread +, unsigned int uStackSize +) { -// TODO: -/* - DWORD nSuspendCount = ::SuspendThread(m_hThread); - if ( nSuspendCount == (DWORD)-1 ) + APIRET ulrc; + + ulrc = ::DosCreateThread( &m_hThread + ,(PFNTHREAD)wxThreadInternal::OS2ThreadStart + ,(ULONG)pThread + ,CREATE_SUSPENDED | STACK_SPARSE + ,(ULONG)uStackSize + ); + if(ulrc != 0) { - wxLogSysError(_("Can not suspend thread %x"), m_hThread); + wxLogSysError(_("Can't create thread")); return FALSE; } + if (m_nPriority != WXTHREAD_DEFAULT_PRIORITY) + { + SetPriority(m_nPriority); + } + return(TRUE); +} - m_state = STATE_PAUSED; -*/ - return FALSE; +bool wxThreadInternal::Suspend() +{ + ULONG ulrc = ::DosSuspendThread(m_hThread); + + if (ulrc != 0) + { + wxLogSysError(_("Can not suspend thread %lu"), m_hThread); + return FALSE; + } + m_eState = STATE_PAUSED; + return TRUE; } bool wxThreadInternal::Resume() { -// TODO: -/* - DWORD nSuspendCount = ::ResumeThread(m_hThread); - if ( nSuspendCount == (DWORD)-1 ) - { - wxLogSysError(_("Can not resume thread %x"), m_hThread); + ULONG ulrc = ::DosResumeThread(m_hThread); + if (ulrc != 0) + { + wxLogSysError(_("Can not suspend thread %lu"), m_hThread); return FALSE; } - - m_state = STATE_RUNNING; -*/ - return FALSE; + m_eState = STATE_PAUSED; + return TRUE; } // static functions @@ -432,24 +473,19 @@ bool wxThreadInternal::Resume() wxThread *wxThread::This() { - wxThread *thread = NULL; // TODO (wxThread *)::TlsGetValue(s_tlsThisThread); - -// TODO: -/* - // be careful, 0 may be a valid return value as well - if ( !thread && (::GetLastError() != NO_ERROR) ) - { - wxLogSysError(_("Couldn't get the current thread pointer")); - - // return NULL... - } -*/ - return thread; + wxThread* pThread = m_pThread; + return pThread; } bool wxThread::IsMain() { -// TODO: return ::GetCurrentThreadId() == s_idMainThread; + PTIB ptib; + PPIB ppib; + + ::DosGetInfoBlocks(&ptib, &ppib); + + if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread) + return TRUE; return FALSE; } @@ -459,21 +495,39 @@ bool wxThread::IsMain() void wxThread::Yield() { - // 0 argument to Sleep() is special ::DosSleep(0); } -void wxThread::Sleep(unsigned long milliseconds) +void wxThread::Sleep( + unsigned long ulMilliseconds +) +{ + ::DosSleep(ulMilliseconds); +} + +// ctor and dtor +// ------------- + +wxThread::wxThread(wxThreadKind kind) +{ + m_internal = new wxThreadInternal(); + + m_isDetached = kind == wxTHREAD_DETACHED; +} + +wxThread::~wxThread() { - ::DosSleep(milliseconds); + 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; @@ -481,14 +535,13 @@ wxThreadError wxThread::Create() wxThreadError wxThread::Run() { - wxCriticalSectionLocker lock(m_critsect); + 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; } - return Resume(); } @@ -497,215 +550,172 @@ wxThreadError wxThread::Run() wxThreadError wxThread::Pause() { - wxCriticalSectionLocker lock(m_critsect); + 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(m_critsect); + 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() +{ + // 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() ) + if (IsPaused()) Resume(); - if ( IsRunning() ) + TID hThread = m_internal->GetHandle(); + + if (IsRunning()) { - if ( IsMain() ) + if (IsMain()) { // set flag for wxIsWaitingForThread() - s_waitingForThread = TRUE; + gs_bWaitingForThread = TRUE; +#if wxUSE_GUI wxBeginBusyCursor(); +#endif // wxUSE_GUI } - HANDLE hThread; + // ask the thread to terminate { wxCriticalSectionLocker lock(m_critsect); - - p_internal->Cancel(); - hThread = p_internal->GetHandle(); + 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 - DWORD result; -// TODO: -/* - do - { - result = ::MsgWaitForMultipleObjects - ( - 1, // number of objects to wait for - &hThread, // the objects - FALSE, // don't wait for all objects - INFINITE, // no timeout - QS_ALLEVENTS // return as soon as there are any events - ); - - switch ( result ) - { - case 0xFFFFFFFF: - // error - wxLogSysError(_("Can not wait for thread termination")); - Kill(); - return (ExitCode)-1; - - case WAIT_OBJECT_0: - // thread we're waiting for terminated - break; - - case WAIT_OBJECT_0 + 1: - // 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 MsgWaitForMultipleObject")); - } - } while ( result != WAIT_OBJECT_0 ); -*/ - if ( IsMain() ) - { - s_waitingForThread = FALSE; +#if wxUSE_GUI + // need a way to finish GUI processing before killing the thread + // until then we just exit - wxEndBusyCursor(); + if ((gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread()) + { + wxMutexGuiLeave(); } +#else // !wxUSE_GUI + + // can't wait for yourself to end under OS/2 so just quit + +#endif // wxUSE_GUI/!wxUSE_GUI -// TODO: -/* - if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) ) + if ( IsMain() ) { - wxLogLastError("GetExitCodeThread"); + gs_bWaitingForThread = FALSE; - rc = (ExitCode)-1; +#if wxUSE_GUI + wxEndBusyCursor(); +#endif // wxUSE_GUI } + } - wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE, - wxT("thread must be already terminated.") ); - - ::CloseHandle(hThread); -*/ + ::DosExit(0, 0); + // probably won't get this far, but + if (IsDetached()) + { + delete this; } - return rc; + if ( pRc ) + *pRc = rc; + + return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR; } wxThreadError wxThread::Kill() { - if ( !IsRunning() ) + if (!IsRunning()) return wxTHREAD_NOT_RUNNING; -// TODO: -/* - if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) ) + ::DosKillThread(m_internal->GetHandle()); + m_internal->Free(); + if (IsDetached()) { - wxLogSysError(_("Couldn't terminate thread")); - - return wxTHREAD_MISC_ERROR; + delete this; } -*/ - delete this; - return wxTHREAD_NO_ERROR; } -void wxThread::Exit(void *status) +void wxThread::Exit( + ExitCode pStatus +) { + m_internal->Free(); delete this; - -// TODO: ::ExitThread((DWORD)status); - - wxFAIL_MSG(wxT("Couldn't return from ExitThread()!")); + ::DosExit(EXIT_THREAD, ULONG(pStatus)); + wxFAIL_MSG(wxT("Couldn't return from DosExit()!")); } -void wxThread::SetPriority(unsigned int prio) +void wxThread::SetPriority( + unsigned int nPrio +) { - wxCriticalSectionLocker lock(m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - p_internal->SetPriority(prio); + m_internal->SetPriority(nPrio); } unsigned int wxThread::GetPriority() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + 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); + 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); + 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); + 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(); -} + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); -wxThread::~wxThread() -{ - delete p_internal; + return m_internal->GetState() == STATE_CANCELED; } // ---------------------------------------------------------------------------- @@ -726,115 +736,65 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) bool wxThreadModule::OnInit() { - // allocate TLS index for storing the pointer to the current thread -// TODO: -/* - s_tlsThisThread = ::TlsAlloc(); - if ( s_tlsThisThread == 0xFFFFFFFF ) - { - // in normal circumstances it will only happen if all other - // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other - // words, this should never happen - wxLogSysError(_("Thread module initialization failed: " - "impossible to allocate index in thread " - "local storage")); - - return FALSE; - } -*/ - // main thread doesn't have associated wxThread object, so store 0 in the - // TLS instead + gs_pCritsectWaitingForGui = new wxCriticalSection(); -// TODO: -/* - if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) ) - { - ::TlsFree(s_tlsThisThread); - s_tlsThisThread = 0xFFFFFFFF; - - wxLogSysError(_("Thread module initialization failed: " - "can not store value in thread local storage")); - - return FALSE; - } -*/ - s_critsectWaitingForGui = new wxCriticalSection(); + gs_pCritsectGui = new wxCriticalSection(); + gs_pCritsectGui->Enter(); - s_critsectGui = new wxCriticalSection(); - s_critsectGui->Enter(); + PTIB ptib; + PPIB ppib; - // no error return for GetCurrentThreadId() -// s_idMainThread = ::GetCurrentThreadId(); + ::DosGetInfoBlocks(&ptib, &ppib); + s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid; return TRUE; } void wxThreadModule::OnExit() { -// TODO: -/* - if ( !::TlsFree(s_tlsThisThread) ) + if (gs_pCritsectGui) { - wxLogLastError("TlsFree failed."); - } -*/ - if ( s_critsectGui ) - { - s_critsectGui->Leave(); - delete s_critsectGui; - s_critsectGui = NULL; + gs_pCritsectGui->Leave(); +#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ))) + delete gs_pCritsectGui; +#endif + gs_pCritsectGui = NULL; } - wxDELETE(s_critsectWaitingForGui); +#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ))) + wxDELETE(gs_pCritsectWaitingForGui); +#endif } // ---------------------------------------------------------------------------- -// under Windows, these functions are implemented usign a critical section and -// not a mutex, so the names are a bit confusing +// Helper functions // ---------------------------------------------------------------------------- -void WXDLLEXPORT wxMutexGuiEnter() +// Does nothing under OS/2 [for now] +void WXDLLEXPORT wxWakeUpMainThread() { - // this would dead lock everything... - wxASSERT_MSG( !wxThread::IsMain(), - wxT("main thread doesn't want to block in wxMutexGuiEnter()!") ); - - // the order in which we enter the critical sections here is crucial!! - - // set the flag telling to the main thread that we want to do some GUI - { - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); - - s_nWaitingForGui++; - } - - wxWakeUpMainThread(); - - // now we may block here because the main thread will soon let us in - // (during the next iteration of OnIdle()) - s_critsectGui->Enter(); } void WXDLLEXPORT wxMutexGuiLeave() { - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); + 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_critsectGui->Leave(); + gs_pCritsectGui->Leave(); } void WXDLLEXPORT wxMutexGuiLeaveOrEnter() @@ -842,24 +802,24 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); + 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() ) + if (!wxGuiOwnedByMainThread()) { - s_critsectGui->Enter(); + gs_pCritsectGui->Enter(); - s_bGuiOwnedByMainThread = TRUE; + gs_bGuiOwnedByMainThread = TRUE; } //else: already have it, nothing to do } else { // some threads are waiting, release the GUI lock if we have it - if ( wxGuiOwnedByMainThread() ) + if (wxGuiOwnedByMainThread()) { wxMutexGuiLeave(); } @@ -869,28 +829,13 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() bool WXDLLEXPORT wxGuiOwnedByMainThread() { - return s_bGuiOwnedByMainThread; -} - -// wake up the main thread if it's in ::GetMessage() -void WXDLLEXPORT wxWakeUpMainThread() -{ - // sending any message would do - hopefully WM_NULL is harmless enough -// TODO: -/* - if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) ) - { - // should never happen - wxLogLastError("PostThreadMessage(WM_NULL)"); - } -*/ + return gs_bGuiOwnedByMainThread; } bool WXDLLEXPORT wxIsWaitingForThread() { - return s_waitingForThread; + return gs_bWaitingForThread; } - #endif // wxUSE_THREADS