X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/375f364ef239b2fc2a109aabee93c2437c1ebcd7..404b319a85dadd7decf7a5a5331020520031a41c:/src/msw/thread.cpp diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp index cc4d13a2e6..90d47a663e 100644 --- a/src/msw/thread.cpp +++ b/src/msw/thread.cpp @@ -40,6 +40,8 @@ #include "wx/except.h" +#include "wx/dynlib.h" + // must have this symbol defined to get _beginthread/_endthread declarations #ifndef _MT #define _MT @@ -62,7 +64,7 @@ #if defined(__VISUALC__) || \ (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) || \ (defined(__GNUG__) && defined(__MSVCRT__)) || \ - defined(__WATCOMC__) || defined(__MWERKS__) + defined(__WATCOMC__) #ifndef __WXWINCE__ #undef wxUSE_BEGIN_THREAD @@ -113,7 +115,7 @@ static DWORD gs_tlsThisThread = 0xFFFFFFFF; // id of the main thread - the one which can call GUI functions without first // calling wxMutexGuiEnter() -static DWORD gs_idMainThread = 0; +wxThreadIdType wxThread::ms_idMainThread = 0; // if it's false, some secondary thread is holding the GUI lock static bool gs_bGuiOwnedByMainThread = true; @@ -163,6 +165,25 @@ void wxCriticalSection::Enter() ::EnterCriticalSection((CRITICAL_SECTION *)m_buffer); } +bool wxCriticalSection::TryEnter() +{ +#if wxUSE_DYNLIB_CLASS + typedef BOOL + (WINAPI *TryEnterCriticalSection_t)(LPCRITICAL_SECTION lpCriticalSection); + + static TryEnterCriticalSection_t + pfnTryEnterCriticalSection = (TryEnterCriticalSection_t) + wxDynamicLibrary(wxT("kernel32.dll")). + GetSymbol(wxT("TryEnterCriticalSection")); + + return pfnTryEnterCriticalSection + ? (*pfnTryEnterCriticalSection)((CRITICAL_SECTION *)m_buffer) != 0 + : false; +#else + return false; +#endif +} + void wxCriticalSection::Leave() { ::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer); @@ -189,11 +210,11 @@ private: wxMutexError LockTimeout(DWORD milliseconds); HANDLE m_mutex; - + unsigned long m_owningThread; wxMutexType m_type; - DECLARE_NO_COPY_CLASS(wxMutexInternal) + wxDECLARE_NO_COPY_CLASS(wxMutexInternal); }; // all mutexes are recursive under Win32 so we don't use mutexType @@ -212,9 +233,9 @@ wxMutexInternal::wxMutexInternal(wxMutexType mutexType) if ( !m_mutex ) { - wxLogLastError(_T("CreateMutex()")); + wxLogLastError(wxT("CreateMutex()")); } - + } wxMutexInternal::~wxMutexInternal() @@ -223,7 +244,7 @@ wxMutexInternal::~wxMutexInternal() { if ( !::CloseHandle(m_mutex) ) { - wxLogLastError(_T("CloseHandle(mutex)")); + wxLogLastError(wxT("CloseHandle(mutex)")); } } } @@ -249,18 +270,14 @@ wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds) } DWORD rc = ::WaitForSingleObject(m_mutex, milliseconds); - if ( rc == WAIT_ABANDONED ) - { - // the previous caller died without releasing the mutex, but now we can - // really lock it - wxLogDebug(_T("WaitForSingleObject() returned WAIT_ABANDONED")); - - // use 0 timeout, normally we should always get it - rc = ::WaitForSingleObject(m_mutex, 0); - } - switch ( rc ) { + case WAIT_ABANDONED: + // the previous caller died without releasing the mutex, so even + // though we did get it, log a message about this + wxLogDebug(wxT("WaitForSingleObject() returned WAIT_ABANDONED")); + // fall through + case WAIT_OBJECT_0: // ok break; @@ -268,22 +285,21 @@ wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds) case WAIT_TIMEOUT: return wxMUTEX_TIMEOUT; - case WAIT_ABANDONED: // checked for above default: wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock")); // fall through case WAIT_FAILED: - wxLogLastError(_T("WaitForSingleObject(mutex)")); + wxLogLastError(wxT("WaitForSingleObject(mutex)")); return wxMUTEX_MISC_ERROR; } if (m_type == wxMUTEX_DEFAULT) - { + { // required for checking recursiveness m_owningThread = wxThread::GetCurrentId(); } - + return wxMUTEX_NO_ERROR; } @@ -294,7 +310,7 @@ wxMutexError wxMutexInternal::Unlock() if ( !::ReleaseMutex(m_mutex) ) { - wxLogLastError(_T("ReleaseMutex()")); + wxLogLastError(wxT("ReleaseMutex()")); return wxMUTEX_MISC_ERROR; } @@ -333,7 +349,7 @@ public: private: HANDLE m_semaphore; - DECLARE_NO_COPY_CLASS(wxSemaphoreInternal) + wxDECLARE_NO_COPY_CLASS(wxSemaphoreInternal); }; wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) @@ -355,7 +371,7 @@ wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) #endif if ( !m_semaphore ) { - wxLogLastError(_T("CreateSemaphore()")); + wxLogLastError(wxT("CreateSemaphore()")); } } @@ -365,7 +381,7 @@ wxSemaphoreInternal::~wxSemaphoreInternal() { if ( !::CloseHandle(m_semaphore) ) { - wxLogLastError(_T("CloseHandle(semaphore)")); + wxLogLastError(wxT("CloseHandle(semaphore)")); } } } @@ -383,7 +399,7 @@ wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds) return wxSEMA_TIMEOUT; default: - wxLogLastError(_T("WaitForSingleObject(semaphore)")); + wxLogLastError(wxT("WaitForSingleObject(semaphore)")); } return wxSEMA_MISC_ERROR; @@ -400,7 +416,7 @@ wxSemaError wxSemaphoreInternal::Post() } else { - wxLogLastError(_T("ReleaseSemaphore")); + wxLogLastError(wxT("ReleaseSemaphore")); return wxSEMA_MISC_ERROR; } } @@ -426,7 +442,7 @@ public: m_thread = thread; m_hThread = 0; m_state = STATE_NEW; - m_priority = WXTHREAD_DEFAULT_PRIORITY; + m_priority = wxPRIORITY_DEFAULT; m_nRef = 1; } @@ -455,6 +471,7 @@ public: // (politely, this is not Kill()!) to do it wxThreadError WaitForTerminate(wxCriticalSection& cs, wxThread::ExitCode *pRc, + wxThreadWait waitMode, wxThread *threadToDelete = NULL); // kill the thread unconditionally @@ -512,7 +529,7 @@ private: // reaches 0 we kill the owning wxThread -- and die ourselves with it LONG m_nRef; - DECLARE_NO_COPY_CLASS(wxThreadInternal) + wxDECLARE_NO_COPY_CLASS(wxThreadInternal); }; // small class which keeps a thread alive during its lifetime @@ -550,7 +567,7 @@ THREAD_RETVAL wxThreadInternal::DoThreadStart(wxThread *thread) // store the thread object in the TLS if ( !::TlsSetValue(gs_tlsThisThread, thread) ) { - wxLogSysError(_("Can not start thread: error writing TLS.")); + wxLogSysError(_("Cannot start thread: error writing TLS.")); return THREAD_ERROR_EXIT; } @@ -572,9 +589,14 @@ THREAD_RETVAL THREAD_CALLCONV wxThreadInternal::WinThreadStart(void *param) // each thread has its own SEH translator so install our own a.s.a.p. DisableAutomaticSETranslator(); + // NB: Notice that we can't use wxCriticalSectionLocker in this function as + // we use SEH and it's incompatible with C++ object dtors. + // first of all, check whether we hadn't been cancelled already and don't // start the user code at all then + thread->m_critsect.Enter(); const bool hasExited = thread->m_internal->GetState() == STATE_EXITED; + thread->m_critsect.Leave(); // run the thread function itself inside a SEH try/except block wxSEH_TRY @@ -592,10 +614,6 @@ THREAD_RETVAL THREAD_CALLCONV wxThreadInternal::WinThreadStart(void *param) const bool isDetached = thread->IsDetached(); if ( !hasExited ) { - // enter m_critsect before changing the thread state - // - // NB: can't use wxCriticalSectionLocker here as we use SEH and it's - // incompatible with C++ object dtors thread->m_critsect.Enter(); thread->m_internal->SetState(STATE_EXITED); thread->m_critsect.Leave(); @@ -639,7 +657,7 @@ void wxThreadInternal::SetPriority(unsigned int priority) bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) { wxASSERT_MSG( m_state == STATE_NEW && !m_hThread, - _T("Create()ing thread twice?") ); + wxT("Create()ing thread twice?") ); // for compilers which have it, we should use C RTL function for thread // creation instead of Win32 API one because otherwise we will have memory @@ -681,7 +699,7 @@ bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) return false; } - if ( m_priority != WXTHREAD_DEFAULT_PRIORITY ) + if ( m_priority != wxPRIORITY_DEFAULT ) { SetPriority(m_priority); } @@ -691,6 +709,8 @@ bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) wxThreadError wxThreadInternal::Kill() { + m_thread->OnKill(); + if ( !::TerminateThread(m_hThread, THREAD_ERROR_EXIT) ) { wxLogSysError(_("Couldn't terminate thread")); @@ -706,6 +726,7 @@ wxThreadError wxThreadInternal::Kill() wxThreadError wxThreadInternal::WaitForTerminate(wxCriticalSection& cs, wxThread::ExitCode *pRc, + wxThreadWait waitMode, wxThread *threadToDelete) { // prevent the thread C++ object from disappearing as long as we are using @@ -764,6 +785,8 @@ wxThreadInternal::WaitForTerminate(wxCriticalSection& cs, Cancel(); } + if ( threadToDelete ) + threadToDelete->OnDelete(); // now wait for thread to finish if ( wxThread::IsMain() ) @@ -793,7 +816,7 @@ wxThreadInternal::WaitForTerminate(wxCriticalSection& cs, wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; if ( traits ) { - result = traits->WaitForThread(m_hThread); + result = traits->WaitForThread(m_hThread, waitMode); } else // can't wait for the thread { @@ -805,7 +828,7 @@ wxThreadInternal::WaitForTerminate(wxCriticalSection& cs, { case 0xFFFFFFFF: // error - wxLogSysError(_("Can not wait for thread termination")); + wxLogSysError(_("Cannot wait for thread termination")); Kill(); return wxTHREAD_KILLED; @@ -882,7 +905,8 @@ bool wxThreadInternal::Suspend() DWORD nSuspendCount = ::SuspendThread(m_hThread); if ( nSuspendCount == (DWORD)-1 ) { - wxLogSysError(_("Can not suspend thread %x"), m_hThread); + wxLogSysError(_("Cannot suspend thread %lx"), + static_cast(wxPtrToUInt(m_hThread))); return false; } @@ -897,7 +921,8 @@ bool wxThreadInternal::Resume() DWORD nSuspendCount = ::ResumeThread(m_hThread); if ( nSuspendCount == (DWORD)-1 ) { - wxLogSysError(_("Can not resume thread %x"), m_hThread); + wxLogSysError(_("Cannot resume thread %lx"), + static_cast(wxPtrToUInt(m_hThread))); return false; } @@ -931,11 +956,6 @@ wxThread *wxThread::This() return thread; } -bool wxThread::IsMain() -{ - return ::GetCurrentThreadId() == gs_idMainThread || gs_idMainThread == 0; -} - void wxThread::Yield() { // 0 argument to Sleep() is special and means to just give away the rest of @@ -961,7 +981,7 @@ bool wxThread::SetConcurrency(size_t WXUNUSED_IN_WINCE(level)) #ifdef __WXWINCE__ return false; #else - 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 ) @@ -972,7 +992,7 @@ bool wxThread::SetConcurrency(size_t WXUNUSED_IN_WINCE(level)) DWORD_PTR dwProcMask, dwSysMask; if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 ) { - wxLogLastError(_T("GetProcessAffinityMask")); + wxLogLastError(wxT("GetProcessAffinityMask")); return false; } @@ -1011,7 +1031,7 @@ bool wxThread::SetConcurrency(size_t WXUNUSED_IN_WINCE(level)) // could we set all bits? if ( level != 0 ) { - wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level); + wxLogDebug(wxT("bad level %u in wxThread::SetConcurrency()"), level); return false; } @@ -1026,7 +1046,7 @@ bool wxThread::SetConcurrency(size_t WXUNUSED_IN_WINCE(level)) if ( !pfnSetProcessAffinityMask ) { - HMODULE hModKernel = ::LoadLibrary(_T("kernel32")); + HMODULE hModKernel = ::LoadLibrary(wxT("kernel32")); if ( hModKernel ) { pfnSetProcessAffinityMask = (SETPROCESSAFFINITYMASK) @@ -1035,7 +1055,7 @@ bool wxThread::SetConcurrency(size_t WXUNUSED_IN_WINCE(level)) // we've discovered a MT version of Win9x! wxASSERT_MSG( pfnSetProcessAffinityMask, - _T("this system has several CPUs but no SetProcessAffinityMask function?") ); + wxT("this system has several CPUs but no SetProcessAffinityMask function?") ); } if ( !pfnSetProcessAffinityMask ) @@ -1046,7 +1066,7 @@ bool wxThread::SetConcurrency(size_t WXUNUSED_IN_WINCE(level)) if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 ) { - wxLogLastError(_T("SetProcessAffinityMask")); + wxLogLastError(wxT("SetProcessAffinityMask")); return false; } @@ -1087,11 +1107,8 @@ wxThreadError wxThread::Run() { wxCriticalSectionLocker lock(m_critsect); - if ( m_internal->GetState() != STATE_NEW ) - { - // actually, it may be almost any state at all, not only STATE_RUNNING - return wxTHREAD_RUNNING; - } + wxCHECK_MSG( m_internal->GetState() == STATE_NEW, wxTHREAD_RUNNING, + wxT("thread may only be started once after Create()") ); // the thread has just been created and is still suspended - let it run return Resume(); @@ -1117,23 +1134,23 @@ wxThreadError wxThread::Resume() // stopping thread // --------------- -wxThread::ExitCode wxThread::Wait() +wxThread::ExitCode wxThread::Wait(wxThreadWait waitMode) { ExitCode rc = wxUIntToPtr(THREAD_ERROR_EXIT); // 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(), rc, - _T("wxThread::Wait(): can't wait for detached thread") ); + wxT("wxThread::Wait(): can't wait for detached thread") ); - (void)m_internal->WaitForTerminate(m_critsect, &rc); + (void)m_internal->WaitForTerminate(m_critsect, &rc, waitMode); return rc; } -wxThreadError wxThread::Delete(ExitCode *pRc) +wxThreadError wxThread::Delete(ExitCode *pRc, wxThreadWait waitMode) { - return m_internal->WaitForTerminate(m_critsect, pRc, this); + return m_internal->WaitForTerminate(m_critsect, pRc, waitMode, this); } wxThreadError wxThread::Kill() @@ -1159,6 +1176,8 @@ wxThreadError wxThread::Kill() void wxThread::Exit(ExitCode status) { + wxThreadInternal::DoThreadOnExit(this); + m_internal->Free(); if ( IsDetached() ) @@ -1193,28 +1212,28 @@ void wxThread::SetPriority(unsigned int prio) unsigned int wxThread::GetPriority() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast + wxCriticalSectionLocker lock(const_cast(m_critsect)); return m_internal->GetPriority(); } unsigned long wxThread::GetId() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast + wxCriticalSectionLocker lock(const_cast(m_critsect)); return (unsigned long)m_internal->GetId(); } bool wxThread::IsRunning() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast + wxCriticalSectionLocker lock(const_cast(m_critsect)); return m_internal->GetState() == STATE_RUNNING; } bool wxThread::IsAlive() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast + wxCriticalSectionLocker lock(const_cast(m_critsect)); return (m_internal->GetState() == STATE_RUNNING) || (m_internal->GetState() == STATE_PAUSED); @@ -1222,14 +1241,14 @@ bool wxThread::IsAlive() const bool wxThread::IsPaused() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast + wxCriticalSectionLocker lock(const_cast(m_critsect)); return m_internal->GetState() == STATE_PAUSED; } bool wxThread::TestDestroy() { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast + wxCriticalSectionLocker lock(const_cast(m_critsect)); return m_internal->GetState() == STATE_CANCELED; } @@ -1271,7 +1290,7 @@ bool wxThreadModule::OnInit() ::TlsFree(gs_tlsThisThread); gs_tlsThisThread = 0xFFFFFFFF; - wxLogSysError(_("Thread module initialization failed: can not store value in thread local storage")); + wxLogSysError(_("Thread module initialization failed: cannot store value in thread local storage")); return false; } @@ -1283,8 +1302,7 @@ bool wxThreadModule::OnInit() gs_critsectThreadDelete = new wxCriticalSection; - // no error return for GetCurrentThreadId() - gs_idMainThread = ::GetCurrentThreadId(); + wxThread::ms_idMainThread = wxThread::GetCurrentId(); return true; } @@ -1296,18 +1314,15 @@ void wxThreadModule::OnExit() wxLogLastError(wxT("TlsFree failed.")); } - delete gs_critsectThreadDelete; - gs_critsectThreadDelete = NULL; + wxDELETE(gs_critsectThreadDelete); if ( gs_critsectGui ) { gs_critsectGui->Leave(); - delete gs_critsectGui; - gs_critsectGui = NULL; + wxDELETE(gs_critsectGui); } - delete gs_critsectWaitingForGui; - gs_critsectWaitingForGui = NULL; + wxDELETE(gs_critsectWaitingForGui); } // ---------------------------------------------------------------------------- @@ -1398,7 +1413,7 @@ bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread() void WXDLLIMPEXP_BASE wxWakeUpMainThread() { // sending any message would do - hopefully WM_NULL is harmless enough - if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) ) + if ( !::PostThreadMessage(wxThread::GetMainId(), WM_NULL, 0, 0) ) { // should never happen wxLogLastError(wxT("PostThreadMessage(WM_NULL)"));