X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/76a5e5d21ee1a6230d777ce0209b2df4c6075f0f..30e0b1c9720fcef5fb2fa0969ef4cc12a168cf97:/src/mac/carbon/thread.cpp diff --git a/src/mac/carbon/thread.cpp b/src/mac/carbon/thread.cpp index c68fd396de..db758b346f 100644 --- a/src/mac/carbon/thread.cpp +++ b/src/mac/carbon/thread.cpp @@ -35,9 +35,15 @@ #include "wx/thread.h" #ifdef __WXMAC__ -#include "wx/mac/private.h" +#include +#include "wx/mac/uma.h" +#include "wx/mac/macnotfy.h" +#include #endif +#define INFINITE 0xFFFFFFFF + + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -59,6 +65,7 @@ enum wxThreadState static ThreadID gs_idMainThread = kNoThreadID ; static bool gs_waitingForThread = FALSE ; +size_t g_numberOfThreads = 0; // ============================================================================ // MacOS implementation of thread classes @@ -67,13 +74,15 @@ static bool gs_waitingForThread = FALSE ; class wxMacStCritical { public : - wxMacStCritical() + wxMacStCritical() { - ThreadBeginCritical() ; + if ( UMASystemIsInitialized() ) + ThreadBeginCritical() ; } ~wxMacStCritical() { - ThreadEndCritical() ; + if ( UMASystemIsInitialized() ) + ThreadEndCritical() ; } }; @@ -84,114 +93,166 @@ public : class wxMutexInternal { public: - wxMutexInternal() + wxMutexInternal(wxMutexType WXUNUSED(mutexType)) { m_owner = kNoThreadID ; + m_locked = 0; } - ~wxMutexInternal() + ~wxMutexInternal() { + if ( m_locked > 0 ) + { + wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked); + } } + bool IsOk() const { return true; } + + wxMutexError Lock() ; + wxMutexError TryLock() ; + wxMutexError Unlock(); public: ThreadID m_owner ; wxArrayLong m_waiters ; + long m_locked ; }; -wxMutex::wxMutex() +wxMutexError wxMutexInternal::Lock() { - m_internal = new wxMutexInternal; + wxMacStCritical critical ; + if ( UMASystemIsInitialized() ) + { + OSErr err ; + ThreadID current = kNoThreadID; + err = ::MacGetCurrentThread(¤t); + // if we are not the owner, add this thread to the list of waiting threads, stop this thread + // and invoke the scheduler to continue executing the owner's thread + while ( m_owner != kNoThreadID && m_owner != current) + { + m_waiters.Add(current); + err = ::SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, m_owner); + err = ::ThreadBeginCritical(); + } + m_owner = current; + } + m_locked++; - m_locked = 0; + return wxMUTEX_NO_ERROR; } -wxMutex::~wxMutex() +wxMutexError wxMutexInternal::TryLock() { - if ( m_locked > 0 ) + wxMacStCritical critical ; + if ( UMASystemIsInitialized() ) { - wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked); + ThreadID current = kNoThreadID; + ::MacGetCurrentThread(¤t); + // if we are not the owner, give an error back + if ( m_owner != kNoThreadID && m_owner != current ) + return wxMUTEX_BUSY; + + m_owner = current; } + m_locked++; - delete m_internal; + return wxMUTEX_NO_ERROR; } -wxMutexError wxMutex::Lock() +wxMutexError wxMutexInternal::Unlock() { - wxMacStCritical critical ; - - OSErr err ; - ThreadID current = kNoThreadID; - err = ::MacGetCurrentThread(¤t); - // if we are not the owner, add this thread to the list of waiting threads, stop this thread - // and invoke the scheduler to continue executing the owner's thread - while ( m_internal->m_owner != kNoThreadID && m_internal->m_owner != current) - { - m_internal->m_waiters.Add(current); - err = ::SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, m_internal->m_owner); + if ( UMASystemIsInitialized() ) + { + OSErr err; err = ::ThreadBeginCritical(); - } - m_internal->m_owner = current; - m_locked++; + if (m_locked > 0) + m_locked--; + + // this mutex is not owned by anybody anmore + m_owner = kNoThreadID; + + // now pass on to the first waiting thread + ThreadID firstWaiting = kNoThreadID; + bool found = false; + while (!m_waiters.IsEmpty() && !found) + { + firstWaiting = m_waiters[0]; + err = ::SetThreadState(firstWaiting, kReadyThreadState, kNoThreadID); + // in case this was not successful (dead thread), we just loop on and reset the id + found = (err != threadNotFoundErr); + if ( !found ) + firstWaiting = kNoThreadID ; + m_waiters.RemoveAt(0) ; + } + // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the + // critical section and invoke the scheduler + err = ::SetThreadStateEndCritical(kCurrentThreadID, kReadyThreadState, firstWaiting); + } + else + { + if (m_locked > 0) + m_locked--; + } return wxMUTEX_NO_ERROR; } -wxMutexError wxMutex::TryLock() -{ - wxMacStCritical critical ; - - OSErr err ; - ThreadID current = kNoThreadID; - ::MacGetCurrentThread(¤t); - // if we are not the owner, give an error back - if ( m_internal->m_owner != kNoThreadID && m_internal->m_owner != current ) - return wxMUTEX_BUSY; - - m_internal->m_owner = current; - m_locked++; +// -------------------------------------------------------------------------- +// wxSemaphore +// -------------------------------------------------------------------------- - return wxMUTEX_NO_ERROR; -} +// TODO not yet implemented -wxMutexError wxMutex::Unlock() +class wxSemaphoreInternal { - OSErr err; - err = ::ThreadBeginCritical(); - - if (m_locked > 0) - m_locked--; +public: + wxSemaphoreInternal(int initialcount, int maxcount); + ~wxSemaphoreInternal(); + + bool IsOk() const { return true ; } + + wxSemaError Wait() { return WaitTimeout(INFINITE); } + wxSemaError TryWait() { return WaitTimeout(0); } + wxSemaError WaitTimeout(unsigned long milliseconds); + + wxSemaError Post(); - // this mutex is not owned by anybody anmore - m_internal->m_owner = kNoThreadID; +private: +}; - // now pass on to the first waiting thread - ThreadID firstWaiting = kNoThreadID; - bool found = false; - while (!m_internal->m_waiters.IsEmpty() && !found) +wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) +{ + if ( maxcount == 0 ) { - firstWaiting = m_internal->m_waiters[0]; - err = ::SetThreadState(firstWaiting, kReadyThreadState, kNoThreadID); - // in case this was not successful (dead thread), we just loop on and reset the id - found = (err != threadNotFoundErr); - if ( !found ) - firstWaiting = kNoThreadID ; - m_internal->m_waiters.RemoveAt(0) ; + // make it practically infinite + maxcount = INT_MAX; } - // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the - // critical section and invoke the scheduler - err = ::SetThreadStateEndCritical(kCurrentThreadID, kReadyThreadState, firstWaiting); +} - return wxMUTEX_NO_ERROR; +wxSemaphoreInternal::~wxSemaphoreInternal() +{ +} + +wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds) +{ + return wxSEMA_MISC_ERROR; +} + +wxSemaError wxSemaphoreInternal::Post() +{ + return wxSEMA_MISC_ERROR; } // ---------------------------------------------------------------------------- // wxCondition implementation // ---------------------------------------------------------------------------- +// TODO this is not yet completed + class wxConditionInternal { public: - wxConditionInternal() + wxConditionInternal(wxMutex& mutex) : m_mutex(mutex) { m_excessSignals = 0 ; } @@ -199,17 +260,24 @@ public: { } - bool Wait(unsigned long msectimeout) + bool IsOk() const { return m_mutex.IsOk() ; } + + wxCondError Wait() + { + return WaitTimeout(0xFFFFFFFF ); + } + + wxCondError WaitTimeout(unsigned long msectimeout) { wxMacStCritical critical ; if ( m_excessSignals > 0 ) { --m_excessSignals ; - return TRUE ; + return wxCOND_NO_ERROR ; } else if ( msectimeout == 0 ) { - return FALSE ; + return wxCOND_MISC_ERROR ; } else { @@ -224,59 +292,25 @@ public: return rc != WAIT_TIMEOUT; */ - return TRUE ; + return wxCOND_NO_ERROR ; } - void Signal() + wxCondError Signal() { wxMacStCritical critical ; + return wxCOND_NO_ERROR; + } + + wxCondError Broadcast() + { + wxMacStCritical critical ; + return wxCOND_NO_ERROR; } wxArrayLong m_waiters ; wxInt32 m_excessSignals ; + wxMutex& m_mutex; }; -wxCondition::wxCondition() -{ - m_internal = new wxConditionInternal; -} - -wxCondition::~wxCondition() -{ - delete m_internal; -} - -void wxCondition::Wait() -{ - (void)m_internal->Wait(0xFFFFFFFFL); -} - -bool wxCondition::Wait(unsigned long sec, - unsigned long nsec) -{ - return m_internal->Wait(sec*1000 + nsec/1000000); -} - -void wxCondition::Signal() -{ - // set the event to signaled: if a thread is already waiting on it, it will - // be woken up, otherwise the event will remain in the signaled state until - // 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. - m_internal->Signal() ; -} - -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 < m_internal->m_waiters.Count(); i++ ) - { - Signal(); - } -} - // ---------------------------------------------------------------------------- // wxCriticalSection implementation // ---------------------------------------------------------------------------- @@ -323,7 +357,7 @@ public: // thread priority void SetPriority(unsigned int priority); unsigned int GetPriority() const { return m_priority; } - + void SetResult( void *res ) { m_result = res ; } void *GetResult() { return m_result ; } @@ -403,13 +437,15 @@ bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) SetPriority(m_priority); } + m_state = STATE_NEW; + return TRUE; } bool wxThreadInternal::Suspend() { OSErr err ; - + ::ThreadBeginCritical(); if ( m_state != STATE_RUNNING ) @@ -434,18 +470,18 @@ bool wxThreadInternal::Resume() wxASSERT( err == noErr ) ; wxASSERT( current != m_tid ) ; - + ::ThreadBeginCritical(); if ( m_state != STATE_PAUSED && m_state != STATE_NEW ) { ::ThreadEndCritical() ; wxLogSysError(_("Can not resume thread %x"), m_tid); return FALSE; - + } err = ::SetThreadStateEndCritical(m_tid, kReadyThreadState, kNoThreadID); wxASSERT( err == noErr ) ; - + m_state = STATE_RUNNING; ::ThreadEndCritical() ; ::YieldToAnyThread() ; @@ -457,13 +493,13 @@ bool wxThreadInternal::Resume() wxThread *wxThread::This() { wxMacStCritical critical ; - + ThreadID current ; OSErr err ; - + err = MacGetCurrentThread( ¤t ) ; - - for ( int i = 0 ; i < s_threads.Count() ; ++i ) + + for ( size_t i = 0 ; i < s_threads.Count() ; ++i ) { if ( ( (wxThread*) s_threads[i] )->GetId() == current ) return (wxThread*) s_threads[i] ; @@ -477,7 +513,7 @@ bool wxThread::IsMain() { ThreadID current ; OSErr err ; - + err = MacGetCurrentThread( ¤t ) ; return current == gs_idMainThread; } @@ -488,16 +524,29 @@ bool wxThread::IsMain() void wxThread::Yield() { +#if TARGET_API_MAC_OSX + CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ; +#endif ::YieldToAnyThread() ; + } void wxThread::Sleep(unsigned long milliseconds) { - clock_t start = clock() ; - do - { - YieldToAnyThread() ; - } while( clock() - start < milliseconds / CLOCKS_PER_SEC ) ; + UnsignedWide start, now; + + Microseconds(&start); + + double mssleep = milliseconds * 1000 ; + double msstart, msnow ; + msstart = (start.hi * 4294967296.0 + start.lo) ; + + do + { + YieldToAnyThread(); + Microseconds(&now); + msnow = (now.hi * 4294967296.0 + now.lo) ; + } while( msnow - msstart < mssleep ); } int wxThread::GetCPUCount() @@ -506,6 +555,13 @@ int wxThread::GetCPUCount() return 1; } +unsigned long wxThread::GetCurrentId() +{ + ThreadID current ; + MacGetCurrentThread( ¤t ) ; + return (unsigned long)current; +} + bool wxThread::SetConcurrency(size_t level) { wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") ); @@ -521,7 +577,7 @@ bool wxThread::SetConcurrency(size_t level) // processor system it doesn't make much sense anyhow return level == 1; } - + return TRUE ; } @@ -530,6 +586,7 @@ bool wxThread::SetConcurrency(size_t level) wxThread::wxThread(wxThreadKind kind) { + g_numberOfThreads++; m_internal = new wxThreadInternal(); m_isDetached = kind == wxTHREAD_DETACHED; @@ -538,8 +595,22 @@ wxThread::wxThread(wxThreadKind kind) wxThread::~wxThread() { + if (g_numberOfThreads>0) + { + g_numberOfThreads--; + } +#ifdef __WXDEBUG__ + else + { + wxFAIL_MSG(wxT("More threads deleted than created.")); + } +#endif + s_threads.Remove( (void*) this ) ; - delete m_internal; + if (m_internal != NULL) { + delete m_internal; + m_internal = NULL; + } } // create/start thread @@ -674,13 +745,6 @@ wxThreadError wxThread::Delete(ExitCode *pRc) } } - // if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) ) - { - wxLogLastError("GetExitCodeThread"); - - rc = (ExitCode)-1; - } - if ( IsDetached() ) { // if the thread exits normally, this is done in WinThreadStart, but in @@ -690,9 +754,6 @@ wxThreadError wxThread::Delete(ExitCode *pRc) delete this; } - // wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE, - // wxT("thread must be already terminated.") ); - if ( pRc ) *pRc = rc; @@ -732,7 +793,7 @@ void wxThread::Exit(ExitCode status) m_internal->SetResult( status ) ; -/* +/* #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) _endthreadex((unsigned)status); #else // !VC++ @@ -812,7 +873,7 @@ bool wxThreadModule::OnInit() #endif if ( !hasThreadManager ) { - wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK ) ; + wxLogSysError( wxT("Thread Support is not available on this System") ); return FALSE ; } @@ -848,7 +909,7 @@ bool WXDLLEXPORT wxGuiOwnedByMainThread() return false ; } -// wake up the main thread +// wake up the main thread void WXDLLEXPORT wxWakeUpMainThread() { wxMacWakeUp() ; @@ -859,6 +920,6 @@ bool WXDLLEXPORT wxIsWaitingForThread() return false ; } -#endif // wxUSE_THREADS +#include "wx/thrimpl.cpp" -// vi:sts=4:sw=4:et +#endif // wxUSE_THREADS