X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b568d04ffa191f9e3b643ca33526094eca0ba304..37b8e6798782278fdfe4f3c1291aaff55cdbb8c9:/src/msw/thread.cpp?ds=sidebyside diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp index a3929b693f..ac600434e9 100644 --- a/src/msw/thread.cpp +++ b/src/msw/thread.cpp @@ -41,7 +41,19 @@ #define _MT #endif -#ifdef __VISUALC__ +#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) + +#if defined(__BORLANDC__) && !defined(__MT__) +// I can't set -tWM in the IDE (anyone?) so have to do this +#define __MT__ +#endif + +#if defined(__BORLANDC__) && !defined(__MFC_COMPAT__) +// Needed to know about _beginthreadex etc.. +#define __MFC_COMPAT__ +#endif + + #include #endif @@ -99,33 +111,43 @@ static bool gs_waitingForThread = FALSE; class wxMutexInternal { public: - HANDLE p_mutex; + wxMutexInternal() + { + m_mutex = ::CreateMutex(NULL, FALSE, NULL); + if ( !m_mutex ) + { + wxLogSysError(_("Can not create mutex")); + } + } + + ~wxMutexInternal() { if ( m_mutex ) CloseHandle(m_mutex); } + +public: + HANDLE m_mutex; }; wxMutex::wxMutex() { - p_internal = new wxMutexInternal; - p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL); - if ( !p_internal->p_mutex ) - { - wxLogSysError(_("Can not create mutex.")); - } + m_internal = new wxMutexInternal; m_locked = 0; } wxMutex::~wxMutex() { - if (m_locked > 0) - wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked); - CloseHandle(p_internal->p_mutex); + if ( m_locked > 0 ) + { + wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked); + } + + delete m_internal; } wxMutexError wxMutex::Lock() { DWORD ret; - ret = WaitForSingleObject(p_internal->p_mutex, INFINITE); + ret = WaitForSingleObject(m_internal->m_mutex, INFINITE); switch ( ret ) { case WAIT_ABANDONED: @@ -152,7 +174,7 @@ wxMutexError wxMutex::TryLock() { DWORD ret; - ret = WaitForSingleObject(p_internal->p_mutex, 0); + ret = WaitForSingleObject(m_internal->m_mutex, 0); if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED) return wxMUTEX_BUSY; @@ -165,7 +187,7 @@ wxMutexError wxMutex::Unlock() if (m_locked > 0) m_locked--; - BOOL ret = ReleaseMutex(p_internal->p_mutex); + BOOL ret = ReleaseMutex(m_internal->m_mutex); if ( ret == 0 ) { wxLogSysError(_("Couldn't release a mutex")); @@ -197,16 +219,14 @@ public: waiters = 0; } - bool Wait(wxMutex& mutex, DWORD timeout) + bool Wait(DWORD timeout) { - mutex.Unlock(); waiters++; // FIXME this should be MsgWaitForMultipleObjects() as well probably DWORD rc = ::WaitForSingleObject(event, timeout); waiters--; - mutex.Lock(); return rc != WAIT_TIMEOUT; } @@ -228,24 +248,23 @@ public: wxCondition::wxCondition() { - p_internal = new wxConditionInternal; + m_internal = new wxConditionInternal; } wxCondition::~wxCondition() { - delete p_internal; + delete m_internal; } -void wxCondition::Wait(wxMutex& mutex) +void wxCondition::Wait() { - (void)p_internal->Wait(mutex, INFINITE); + (void)m_internal->Wait(INFINITE); } -bool wxCondition::Wait(wxMutex& mutex, - unsigned long sec, +bool wxCondition::Wait(unsigned long sec, unsigned long nsec) { - return p_internal->Wait(mutex, sec*1000 + nsec/1000000); + return m_internal->Wait(sec*1000 + nsec/1000000); } void wxCondition::Signal() @@ -255,7 +274,7 @@ void wxCondition::Signal() // someone waits on it. In any case, the system will return it to a non // signalled state afterwards. If multiple threads are waiting, only one // will be woken up. - if ( !::SetEvent(p_internal->event) ) + if ( !::SetEvent(m_internal->event) ) { wxLogLastError("SetEvent"); } @@ -266,7 +285,7 @@ void wxCondition::Broadcast() // this works because all these threads are already waiting and so each // SetEvent() inside Signal() is really a PulseEvent() because the event // state is immediately returned to non-signaled - for ( int i = 0; i < p_internal->waiters; i++ ) + for ( int i = 0; i < m_internal->waiters; i++ ) { Signal(); } @@ -366,6 +385,12 @@ private: DWORD wxThreadInternal::WinThreadStart(wxThread *thread) { + // first of all, check whether we hadn't been cancelled already + if ( thread->m_internal->GetState() == STATE_EXITED ) + { + return (DWORD)-1; + } + // store the thread object in the TLS if ( !::TlsSetValue(gs_tlsThisThread, thread) ) { @@ -378,8 +403,8 @@ DWORD wxThreadInternal::WinThreadStart(wxThread *thread) // enter m_critsect before changing the thread state thread->m_critsect.Enter(); - bool wasCancelled = thread->p_internal->GetState() == STATE_CANCELED; - thread->p_internal->SetState(STATE_EXITED); + bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED; + thread->m_internal->SetState(STATE_EXITED); thread->m_critsect.Leave(); thread->OnExit(); @@ -429,11 +454,11 @@ bool wxThreadInternal::Create(wxThread *thread) // 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 // leaks if the thread uses C RTL (and most threads do) -#ifdef __VISUALC__ +#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) typedef unsigned (__stdcall *RtlThreadStart)(void *); m_hThread = (HANDLE)_beginthreadex(NULL, 0, - (RtlThreadStart) + (RtlThreadStart) wxThreadInternal::WinThreadStart, thread, CREATE_SUSPENDED, (unsigned int *)&m_tid); @@ -518,6 +543,10 @@ bool wxThread::IsMain() return ::GetCurrentThreadId() == gs_idMainThread; } +#ifdef Yield +#undef Yield +#endif + void wxThread::Yield() { // 0 argument to Sleep() is special and means to just give away the rest of @@ -530,19 +559,128 @@ void wxThread::Sleep(unsigned long milliseconds) ::Sleep(milliseconds); } +int wxThread::GetCPUCount() +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + + return si.dwNumberOfProcessors; +} + +bool wxThread::SetConcurrency(size_t level) +{ + wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") ); + + // ok only for the default one + if ( level == 0 ) + return 0; + + // get system affinity mask first + HANDLE hProcess = ::GetCurrentProcess(); + DWORD dwProcMask, dwSysMask; + if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 ) + { + wxLogLastError(_T("GetProcessAffinityMask")); + + return FALSE; + } + + // how many CPUs have we got? + if ( dwSysMask == 1 ) + { + // don't bother with all this complicated stuff - on a single + // processor system it doesn't make much sense anyhow + return level == 1; + } + + // calculate the process mask: it's a bit vector with one bit per + // processor; we want to schedule the process to run on first level + // CPUs + DWORD bit = 1; + while ( bit ) + { + if ( dwSysMask & bit ) + { + // ok, we can set this bit + dwProcMask |= bit; + + // another process added + if ( !--level ) + { + // and that's enough + break; + } + } + + // next bit + bit <<= 1; + } + + // could we set all bits? + if ( level != 0 ) + { + wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level); + + return FALSE; + } + + // set it: we can't link to SetProcessAffinityMask() because it doesn't + // exist in Win9x, use RT binding instead + + typedef BOOL (*SETPROCESSAFFINITYMASK)(HANDLE, DWORD); + + // can use static var because we're always in the main thread here + static SETPROCESSAFFINITYMASK pfnSetProcessAffinityMask = NULL; + + if ( !pfnSetProcessAffinityMask ) + { + HMODULE hModKernel = ::LoadLibrary(_T("kernel32")); + if ( hModKernel ) + { + pfnSetProcessAffinityMask = (SETPROCESSAFFINITYMASK) + ::GetProcAddress(hModKernel, +#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520) + "SetProcessAffinityMask"); +#else + _T("SetProcessAffinityMask")); +#endif + } + + // we've discovered a MT version of Win9x! + wxASSERT_MSG( pfnSetProcessAffinityMask, + _T("this system has several CPUs but no " + "SetProcessAffinityMask function?") ); + } + + if ( !pfnSetProcessAffinityMask ) + { + // msg given above - do it only once + return FALSE; + } + + if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 ) + { + wxLogLastError(_T("SetProcessAffinityMask")); + + return FALSE; + } + + return TRUE; +} + // ctor and dtor // ------------- wxThread::wxThread(wxThreadKind kind) { - p_internal = new wxThreadInternal(); + m_internal = new wxThreadInternal(); m_isDetached = kind == wxTHREAD_DETACHED; } wxThread::~wxThread() { - delete p_internal; + delete m_internal; } // create/start thread @@ -552,7 +690,7 @@ wxThreadError wxThread::Create() { wxCriticalSectionLocker lock(m_critsect); - if ( !p_internal->Create(this) ) + if ( !m_internal->Create(this) ) return wxTHREAD_NO_RESOURCE; return wxTHREAD_NO_ERROR; @@ -562,7 +700,7 @@ wxThreadError wxThread::Run() { wxCriticalSectionLocker lock(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; @@ -579,14 +717,14 @@ wxThreadError wxThread::Pause() { wxCriticalSectionLocker lock(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); - return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; + return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; } // stopping thread @@ -603,7 +741,7 @@ wxThread::ExitCode wxThread::Wait() (void)Delete(&rc); - p_internal->Free(); + m_internal->Free(); return rc; } @@ -613,11 +751,29 @@ wxThreadError wxThread::Delete(ExitCode *pRc) ExitCode rc = 0; // Delete() is always safe to call, so consider all possible states - if ( IsPaused() ) + + // has the thread started to run? + bool shouldResume = FALSE; + + { + wxCriticalSectionLocker lock(m_critsect); + + if ( m_internal->GetState() == STATE_NEW ) + { + // WinThreadStart() will see it and terminate immediately + m_internal->SetState(STATE_EXITED); + + shouldResume = TRUE; + } + } + + // is the thread paused? + if ( shouldResume || IsPaused() ) Resume(); - HANDLE hThread = p_internal->GetHandle(); + HANDLE hThread = m_internal->GetHandle(); + // does is still run? if ( IsRunning() ) { if ( IsMain() ) @@ -634,7 +790,7 @@ wxThreadError wxThread::Delete(ExitCode *pRc) { wxCriticalSectionLocker lock(m_critsect); - p_internal->Cancel(); + m_internal->Cancel(); } #if wxUSE_GUI @@ -742,14 +898,14 @@ wxThreadError wxThread::Kill() if ( !IsRunning() ) return wxTHREAD_NOT_RUNNING; - if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) ) + if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) ) { wxLogSysError(_("Couldn't terminate thread")); return wxTHREAD_MISC_ERROR; } - p_internal->Free(); + m_internal->Free(); if ( IsDetached() ) { @@ -761,14 +917,14 @@ wxThreadError wxThread::Kill() void wxThread::Exit(ExitCode status) { - p_internal->Free(); + m_internal->Free(); if ( IsDetached() ) { delete this; } -#ifdef __VISUALC__ +#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) _endthreadex((unsigned)status); #else // !VC++ ::ExitThread((DWORD)status); @@ -784,50 +940,50 @@ void wxThread::SetPriority(unsigned int prio) { wxCriticalSectionLocker lock(m_critsect); - p_internal->SetPriority(prio); + m_internal->SetPriority(prio); } unsigned int wxThread::GetPriority() const { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast - return p_internal->GetPriority(); + return m_internal->GetPriority(); } unsigned long wxThread::GetId() const { 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); // const_cast - return p_internal->GetState() == STATE_RUNNING; + return m_internal->GetState() == STATE_RUNNING; } bool wxThread::IsAlive() const { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast - 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); // const_cast - return p_internal->GetState() == STATE_PAUSED; + return m_internal->GetState() == STATE_PAUSED; } bool wxThread::TestDestroy() { wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast - return p_internal->GetState() == STATE_CANCELED; + return m_internal->GetState() == STATE_CANCELED; } // ----------------------------------------------------------------------------