X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d254213eb2b973e826ed3bc84bc681a819eae091..af36ec0aa1b2110723637a27c42f4fc82afaff96:/src/msw/thread.cpp diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp index 7127bee02b..d57bbb9b0f 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 @@ -75,7 +77,8 @@ // this is where _beginthreadex() is declared #include - // the return type of the thread function entry point + // the return type of the thread function entry point: notice that this + // type can't hold a pointer under Win64 typedef unsigned THREAD_RETVAL; // the calling convention of the thread function entry point @@ -86,6 +89,8 @@ #define THREAD_CALLCONV WINAPI #endif +static const THREAD_RETVAL THREAD_ERROR_EXIT = (THREAD_RETVAL)-1; + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -110,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; @@ -142,7 +147,7 @@ static bool gs_waitingForThread = false; // wxCriticalSection // ---------------------------------------------------------------------------- -wxCriticalSection::wxCriticalSection() +wxCriticalSection::wxCriticalSection( wxCriticalSectionType WXUNUSED(critSecType) ) { wxCOMPILE_TIME_ASSERT( sizeof(CRITICAL_SECTION) <= sizeof(wxCritSectBuffer), wxCriticalSectionBufferTooSmall ); @@ -160,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); @@ -187,11 +211,14 @@ private: HANDLE m_mutex; - DECLARE_NO_COPY_CLASS(wxMutexInternal) + unsigned long m_owningThread; + wxMutexType m_type; + + wxDECLARE_NO_COPY_CLASS(wxMutexInternal); }; // all mutexes are recursive under Win32 so we don't use mutexType -wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(mutexType)) +wxMutexInternal::wxMutexInternal(wxMutexType mutexType) { // create a nameless (hence intra process and always private) mutex m_mutex = ::CreateMutex @@ -201,10 +228,14 @@ wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(mutexType)) NULL // no name ); + m_type = mutexType; + m_owningThread = 0; + if ( !m_mutex ) { - wxLogLastError(_T("CreateMutex()")); + wxLogLastError(wxT("CreateMutex()")); } + } wxMutexInternal::~wxMutexInternal() @@ -213,7 +244,7 @@ wxMutexInternal::~wxMutexInternal() { if ( !::CloseHandle(m_mutex) ) { - wxLogLastError(_T("CloseHandle(mutex)")); + wxLogLastError(wxT("CloseHandle(mutex)")); } } } @@ -228,19 +259,25 @@ wxMutexError wxMutexInternal::TryLock() wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds) { - DWORD rc = ::WaitForSingleObject(m_mutex, milliseconds); - if ( rc == WAIT_ABANDONED ) + if (m_type == wxMUTEX_DEFAULT) { - // 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); + // Don't allow recursive + if (m_owningThread != 0) + { + if (m_owningThread == wxThread::GetCurrentId()) + return wxMUTEX_DEAD_LOCK; + } } + DWORD rc = ::WaitForSingleObject(m_mutex, milliseconds); 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; @@ -248,24 +285,32 @@ 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; } wxMutexError wxMutexInternal::Unlock() { + // required for checking recursiveness + m_owningThread = 0; + if ( !::ReleaseMutex(m_mutex) ) { - wxLogLastError(_T("ReleaseMutex()")); + wxLogLastError(wxT("ReleaseMutex()")); return wxMUTEX_MISC_ERROR; } @@ -304,7 +349,7 @@ public: private: HANDLE m_semaphore; - DECLARE_NO_COPY_CLASS(wxSemaphoreInternal) + wxDECLARE_NO_COPY_CLASS(wxSemaphoreInternal); }; wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) @@ -326,7 +371,7 @@ wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) #endif if ( !m_semaphore ) { - wxLogLastError(_T("CreateSemaphore()")); + wxLogLastError(wxT("CreateSemaphore()")); } } @@ -336,7 +381,7 @@ wxSemaphoreInternal::~wxSemaphoreInternal() { if ( !::CloseHandle(m_semaphore) ) { - wxLogLastError(_T("CloseHandle(semaphore)")); + wxLogLastError(wxT("CloseHandle(semaphore)")); } } } @@ -354,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; @@ -371,7 +416,7 @@ wxSemaError wxSemaphoreInternal::Post() } else { - wxLogLastError(_T("ReleaseSemaphore")); + wxLogLastError(wxT("ReleaseSemaphore")); return wxSEMA_MISC_ERROR; } } @@ -426,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 @@ -483,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 @@ -514,19 +560,19 @@ THREAD_RETVAL wxThreadInternal::DoThreadStart(wxThread *thread) { wxON_BLOCK_EXIT1(DoThreadOnExit, thread); - THREAD_RETVAL rc = (THREAD_RETVAL)-1; + THREAD_RETVAL rc = THREAD_ERROR_EXIT; wxTRY { // 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_RETVAL)-1; + return THREAD_ERROR_EXIT; } - rc = (THREAD_RETVAL)thread->Entry(); + rc = wxPtrToUInt(thread->Entry()); } wxCATCH_ALL( wxTheApp->OnUnhandledException(); ) @@ -536,7 +582,7 @@ THREAD_RETVAL wxThreadInternal::DoThreadStart(wxThread *thread) /* static */ THREAD_RETVAL THREAD_CALLCONV wxThreadInternal::WinThreadStart(void *param) { - THREAD_RETVAL rc = (THREAD_RETVAL)-1; + THREAD_RETVAL rc = THREAD_ERROR_EXIT; wxThread * const thread = (wxThread *)param; @@ -555,7 +601,7 @@ THREAD_RETVAL THREAD_CALLCONV wxThreadInternal::WinThreadStart(void *param) else rc = DoThreadStart(thread); } - wxSEH_HANDLE((THREAD_RETVAL)-1) + wxSEH_HANDLE(THREAD_ERROR_EXIT) // save IsDetached because thread object can be deleted by joinable @@ -610,7 +656,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 @@ -662,7 +708,9 @@ bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) wxThreadError wxThreadInternal::Kill() { - if ( !::TerminateThread(m_hThread, (DWORD)-1) ) + m_thread->OnKill(); + + if ( !::TerminateThread(m_hThread, THREAD_ERROR_EXIT) ) { wxLogSysError(_("Couldn't terminate thread")); @@ -677,6 +725,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 @@ -688,7 +737,7 @@ wxThreadInternal::WaitForTerminate(wxCriticalSection& cs, // from Wait()) or ask it to terminate (when called from Delete()) bool shouldDelete = threadToDelete != NULL; - wxThread::ExitCode rc = 0; + DWORD rc = 0; // we might need to resume the thread if it's currently stopped bool shouldResume = false; @@ -735,6 +784,8 @@ wxThreadInternal::WaitForTerminate(wxCriticalSection& cs, Cancel(); } + if ( threadToDelete ) + threadToDelete->OnDelete(); // now wait for thread to finish if ( wxThread::IsMain() ) @@ -764,7 +815,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 { @@ -776,7 +827,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; @@ -821,16 +872,16 @@ wxThreadInternal::WaitForTerminate(wxCriticalSection& cs, // terminated if the "if" above hadn't been taken for ( ;; ) { - if ( !::GetExitCodeThread(m_hThread, (LPDWORD)&rc) ) + if ( !::GetExitCodeThread(m_hThread, &rc) ) { wxLogLastError(wxT("GetExitCodeThread")); - rc = (wxThread::ExitCode)-1; + rc = THREAD_ERROR_EXIT; break; } - if ( (DWORD)rc != STILL_ACTIVE ) + if ( rc != STILL_ACTIVE ) break; // give the other thread some time to terminate, otherwise we may be @@ -839,14 +890,13 @@ wxThreadInternal::WaitForTerminate(wxCriticalSection& cs, } if ( pRc ) - *pRc = rc; + *pRc = wxUIntToPtr(rc); // we don't need the thread handle any more in any case Free(); - return rc == (wxThread::ExitCode)-1 ? wxTHREAD_MISC_ERROR - : wxTHREAD_NO_ERROR; + return rc == THREAD_ERROR_EXIT ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR; } bool wxThreadInternal::Suspend() @@ -854,7 +904,7 @@ bool wxThreadInternal::Suspend() DWORD nSuspendCount = ::SuspendThread(m_hThread); if ( nSuspendCount == (DWORD)-1 ) { - wxLogSysError(_("Can not suspend thread %x"), m_hThread); + wxLogSysError(_("Cannot suspend thread %x"), m_hThread); return false; } @@ -869,7 +919,7 @@ bool wxThreadInternal::Resume() DWORD nSuspendCount = ::ResumeThread(m_hThread); if ( nSuspendCount == (DWORD)-1 ) { - wxLogSysError(_("Can not resume thread %x"), m_hThread); + wxLogSysError(_("Cannot resume thread %x"), m_hThread); return false; } @@ -903,11 +953,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 @@ -915,11 +960,6 @@ void wxThread::Yield() ::Sleep(0); } -void wxThread::Sleep(unsigned long milliseconds) -{ - ::Sleep(milliseconds); -} - int wxThread::GetCPUCount() { SYSTEM_INFO si; @@ -938,7 +978,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 ) @@ -949,7 +989,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; } @@ -988,7 +1028,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; } @@ -1003,7 +1043,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) @@ -1012,7 +1052,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 ) @@ -1023,7 +1063,7 @@ bool wxThread::SetConcurrency(size_t WXUNUSED_IN_WINCE(level)) if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 ) { - wxLogLastError(_T("SetProcessAffinityMask")); + wxLogLastError(wxT("SetProcessAffinityMask")); return false; } @@ -1064,11 +1104,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(); @@ -1094,23 +1131,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(), (ExitCode)-1, - _T("wxThread::Wait(): can't wait for detached thread") ); - - ExitCode rc = (ExitCode)-1; + wxCHECK_MSG( !IsDetached(), rc, + 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() @@ -1150,7 +1187,7 @@ void wxThread::Exit(ExitCode status) } #ifdef wxUSE_BEGIN_THREAD - _endthreadex((unsigned)status); + _endthreadex(wxPtrToUInt(status)); #else // !VC++ ::ExitThread((DWORD)status); #endif // VC++/!VC++ @@ -1170,28 +1207,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); @@ -1199,14 +1236,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; } @@ -1248,7 +1285,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; } @@ -1260,8 +1297,7 @@ bool wxThreadModule::OnInit() gs_critsectThreadDelete = new wxCriticalSection; - // no error return for GetCurrentThreadId() - gs_idMainThread = ::GetCurrentThreadId(); + wxThread::ms_idMainThread = wxThread::GetCurrentId(); return true; } @@ -1273,18 +1309,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); } // ---------------------------------------------------------------------------- @@ -1375,7 +1408,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)"));