X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a959b08869abdec7449d49e18cb069e81a3f83e6..bb655eade90ab5c24bca3728db33a1c7afb48196:/src/mac/thread.cpp diff --git a/src/mac/thread.cpp b/src/mac/thread.cpp index 86e17b88c0..3634a69dde 100644 --- a/src/mac/thread.cpp +++ b/src/mac/thread.cpp @@ -34,6 +34,15 @@ #include "wx/module.h" #include "wx/thread.h" +#ifdef __WXMAC__ +#include +#include "wx/mac/uma.h" +#include "wx/mac/macnotfy.h" +#endif + +#define INFINITE 0xFFFFFFFF + + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -55,6 +64,7 @@ enum wxThreadState static ThreadID gs_idMainThread = kNoThreadID ; static bool gs_waitingForThread = FALSE ; +size_t g_numberOfThreads = 0; // ============================================================================ // MacOS implementation of thread classes @@ -63,15 +73,17 @@ static bool gs_waitingForThread = FALSE ; class wxMacStCritical { public : - wxMacStCritical() - { - ThreadBeginCritical() ; - } - ~wxMacStCritical() - { - ThreadEndCritical() ; - } -} ; + wxMacStCritical() + { + if ( UMASystemIsInitialized() ) + ThreadBeginCritical() ; + } + ~wxMacStCritical() + { + if ( UMASystemIsInitialized() ) + ThreadEndCritical() ; + } +}; // ---------------------------------------------------------------------------- // wxMutex implementation @@ -80,137 +92,196 @@ public : class wxMutexInternal { public: - wxMutexInternal() + wxMutexInternal(wxMutexType WXUNUSED(mutexType)) { - m_owner = kNoThreadID ; + 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); - err = ::ThreadBeginCritical(); - } - m_internal->m_owner = current; - m_locked++; + if ( UMASystemIsInitialized() ) + { + OSErr err; + err = ::ThreadBeginCritical(); + + 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() +// -------------------------------------------------------------------------- +// wxSemaphore +// -------------------------------------------------------------------------- + +// TODO not yet implemented + +class wxSemaphoreInternal { - 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++; +public: + wxSemaphoreInternal(int initialcount, int maxcount); + ~wxSemaphoreInternal(); - return wxMUTEX_NO_ERROR; + bool IsOk() const { return true ; } + + wxSemaError Wait() { return WaitTimeout(INFINITE); } + wxSemaError TryWait() { return WaitTimeout(0); } + wxSemaError WaitTimeout(unsigned long milliseconds); + + wxSemaError Post(); + +private: +}; + +wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) +{ + if ( maxcount == 0 ) + { + // make it practically infinite + maxcount = INT_MAX; + } } -wxMutexError wxMutex::Unlock() -{ - OSErr err; - err = ::ThreadBeginCritical(); - - if (m_locked > 0) - m_locked--; - - // this mutex is not owned by anybody anmore - m_internal->m_owner = kNoThreadID; - - // now pass on to the first waiting thread - ThreadID firstWaiting = kNoThreadID; - bool found = false; - while (!m_internal->m_waiters.IsEmpty() && !found) - { - 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) ; - } - // 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); +wxSemaphoreInternal::~wxSemaphoreInternal() +{ +} - return wxMUTEX_NO_ERROR; +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 ; + m_excessSignals = 0 ; } ~wxConditionInternal() { } - 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 ; - } - else if ( msectimeout == 0 ) - { - return FALSE ; - } - else - { - } - /* + wxMacStCritical critical ; + if ( m_excessSignals > 0 ) + { + --m_excessSignals ; + return wxCOND_NO_ERROR ; + } + else if ( msectimeout == 0 ) + { + return wxCOND_MISC_ERROR ; + } + else + { + } + /* waiters++; // FIXME this should be MsgWaitForMultipleObjects() as well probably @@ -220,58 +291,24 @@ public: return rc != WAIT_TIMEOUT; */ - return TRUE ; + return wxCOND_NO_ERROR ; + } + wxCondError Signal() + { + wxMacStCritical critical ; + return wxCOND_NO_ERROR; } - void Signal() - { - wxMacStCritical critical ; - } - - wxArrayLong m_waiters ; - wxInt32 m_excessSignals ; -}; - -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++ ) + wxCondError Broadcast() { - Signal(); + wxMacStCritical critical ; + return wxCOND_NO_ERROR; } -} + + wxArrayLong m_waiters ; + wxInt32 m_excessSignals ; + wxMutex& m_mutex; +}; // ---------------------------------------------------------------------------- // wxCriticalSection implementation @@ -305,7 +342,7 @@ public: } // create a new (suspended) thread (for the given thread object) - bool Create(wxThread *thread); + bool Create(wxThread *thread, unsigned int stackSize); // suspend/resume/terminate bool Suspend(); @@ -319,7 +356,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 ; } @@ -327,15 +364,14 @@ public: ThreadID GetId() const { return m_tid; } // thread function - static pascal void* MacThreadStart(wxThread* arg); + static pascal void* MacThreadStart(wxThread* arg); private: - wxThreadState m_state; // state, see wxThreadState enum - unsigned int m_priority; // thread priority in "wx" units - ThreadID m_tid; // thread id - void * m_result ; - static ThreadEntryUPP s_threadEntry ; -public : + wxThreadState m_state; // state, see wxThreadState enum + unsigned int m_priority; // thread priority in "wx" units + ThreadID m_tid; // thread id + void* m_result; + static ThreadEntryUPP s_threadEntry ; }; static wxArrayPtrVoid s_threads ; @@ -372,22 +408,22 @@ pascal void* wxThreadInternal::MacThreadStart(wxThread *thread) } void wxThreadInternal::SetPriority(unsigned int priority) { - // Priorities don't exist on Mac + // Priorities don't exist on Mac } -bool wxThreadInternal::Create(wxThread *thread) +bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) { - if ( s_threadEntry == NULL ) - { - s_threadEntry = NewThreadEntryUPP( (ThreadEntryProcPtr) MacThreadStart ) ; - } - OSErr err = NewThread(kCooperativeThread, - s_threadEntry, - (void*) thread , - 0 , - kNewSuspend , - &m_result , - &m_tid ) ; + if ( s_threadEntry == NULL ) + { + s_threadEntry = NewThreadEntryUPP( (ThreadEntryProcPtr) MacThreadStart ) ; + } + OSErr err = NewThread( kCooperativeThread, + s_threadEntry, + (void*) thread, + stackSize, + kNewSuspend, + &m_result, + &m_tid ); if ( err != noErr ) { @@ -400,52 +436,54 @@ bool wxThreadInternal::Create(wxThread *thread) SetPriority(m_priority); } + m_state = STATE_NEW; + return TRUE; } bool wxThreadInternal::Suspend() { - OSErr err ; - - ::ThreadBeginCritical(); + OSErr err ; + + ::ThreadBeginCritical(); - if ( m_state != STATE_RUNNING ) + if ( m_state != STATE_RUNNING ) { - ::ThreadEndCritical() ; + ::ThreadEndCritical() ; wxLogSysError(_("Can not suspend thread %x"), m_tid); return FALSE; } m_state = STATE_PAUSED; - err = ::SetThreadStateEndCritical(m_tid, kStoppedThreadState, kNoThreadID); + err = ::SetThreadStateEndCritical(m_tid, kStoppedThreadState, kNoThreadID); return TRUE; } bool wxThreadInternal::Resume() { - ThreadID current ; - OSErr err ; - err = MacGetCurrentThread( ¤t ) ; - - wxASSERT( err == noErr ) ; - wxASSERT( current != m_tid ) ; - - ::ThreadBeginCritical(); - if ( m_state != STATE_PAUSED && m_state != STATE_NEW ) - { - ::ThreadEndCritical() ; + ThreadID current ; + OSErr err ; + err = MacGetCurrentThread( ¤t ) ; + + 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 ) ; - + + } + err = ::SetThreadStateEndCritical(m_tid, kReadyThreadState, kNoThreadID); + wxASSERT( err == noErr ) ; + m_state = STATE_RUNNING; - ::ThreadEndCritical() ; - ::YieldToAnyThread() ; + ::ThreadEndCritical() ; + ::YieldToAnyThread() ; return TRUE; } @@ -453,18 +491,18 @@ bool wxThreadInternal::Resume() // ---------------- wxThread *wxThread::This() { - wxMacStCritical critical ; - - ThreadID current ; - OSErr err ; - - err = MacGetCurrentThread( ¤t ) ; - - for ( int i = 0 ; i < s_threads.Count() ; ++i ) - { - if ( ( (wxThread*) s_threads[i] )->GetId() == current ) - return (wxThread*) s_threads[i] ; - } + wxMacStCritical critical ; + + ThreadID current ; + OSErr err ; + + err = MacGetCurrentThread( ¤t ) ; + + for ( size_t i = 0 ; i < s_threads.Count() ; ++i ) + { + if ( ( (wxThread*) s_threads[i] )->GetId() == current ) + return (wxThread*) s_threads[i] ; + } wxLogSysError(_("Couldn't get the current thread pointer")); return NULL; @@ -472,10 +510,10 @@ wxThread *wxThread::This() bool wxThread::IsMain() { - ThreadID current ; - OSErr err ; - - err = MacGetCurrentThread( ¤t ) ; + ThreadID current ; + OSErr err ; + + err = MacGetCurrentThread( ¤t ) ; return current == gs_idMainThread; } @@ -485,24 +523,31 @@ bool wxThread::IsMain() void wxThread::Yield() { - ::YieldToAnyThread() ; + ::YieldToAnyThread() ; } void wxThread::Sleep(unsigned long milliseconds) { - clock_t start = clock() ; - do - { - YieldToAnyThread() ; - } while( clock() - start < milliseconds / CLOCKS_PER_SEC ) ; + clock_t start = clock(); + do + { + YieldToAnyThread(); + } while( clock() - start < milliseconds * CLOCKS_PER_SEC / 1000.0 ) ; } int wxThread::GetCPUCount() { - // we will use whatever MP API will be used for the new MP Macs + // we will use whatever MP API will be used for the new MP Macs 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") ); @@ -518,7 +563,7 @@ bool wxThread::SetConcurrency(size_t level) // processor system it doesn't make much sense anyhow return level == 1; } - + return TRUE ; } @@ -527,6 +572,7 @@ bool wxThread::SetConcurrency(size_t level) wxThread::wxThread(wxThreadKind kind) { + g_numberOfThreads++; m_internal = new wxThreadInternal(); m_isDetached = kind == wxTHREAD_DETACHED; @@ -535,18 +581,32 @@ wxThread::wxThread(wxThreadKind kind) wxThread::~wxThread() { - s_threads.Remove( (void*) this ) ; - delete m_internal; + if (g_numberOfThreads>0) + { + g_numberOfThreads--; + } +#ifdef __WXDEBUG__ + else + { + wxFAIL_MSG(wxT("More threads deleted than created.")); + } +#endif + + s_threads.Remove( (void*) this ) ; + if (m_internal != NULL) { + delete m_internal; + m_internal = NULL; + } } // create/start thread // ------------------- -wxThreadError wxThread::Create() +wxThreadError wxThread::Create(unsigned int stackSize) { wxCriticalSectionLocker lock(m_critsect); - if ( !m_internal->Create(this) ) + if ( !m_internal->Create(this, stackSize) ) return wxTHREAD_NO_RESOURCE; return wxTHREAD_NO_ERROR; @@ -649,16 +709,16 @@ wxThreadError wxThread::Delete(ExitCode *pRc) #if wxUSE_GUI // simply wait for the thread to terminate - while( TestDestroy() ) - { - ::YieldToAnyThread() ; - } + while( TestDestroy() ) + { + ::YieldToAnyThread() ; + } #else // !wxUSE_GUI // simply wait for the thread to terminate - while( TestDestroy() ) - { - ::YieldToAnyThread() ; - } + while( TestDestroy() ) + { + ::YieldToAnyThread() ; + } #endif // wxUSE_GUI/!wxUSE_GUI if ( IsMain() ) @@ -671,13 +731,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 @@ -687,9 +740,6 @@ wxThreadError wxThread::Delete(ExitCode *pRc) delete this; } - // wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE, - // wxT("thread must be already terminated.") ); - if ( pRc ) *pRc = rc; @@ -727,9 +777,9 @@ void wxThread::Exit(ExitCode status) delete this; } - m_internal->SetResult( status ) ; + m_internal->SetResult( status ) ; -/* +/* #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) _endthreadex((unsigned)status); #else // !VC++ @@ -798,18 +848,20 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) bool wxThreadModule::OnInit() { - long response; - bool hasThreadManager ; - hasThreadManager = Gestalt( gestaltThreadMgrAttr, &response) == noErr && response & 1; -#if GENERATINGPOWERPC || GENERATINGCFM - // verify presence of shared library - hasThreadManager = hasThreadManager && ((Ptr)NewThread != (Ptr)kUnresolvedCFragSymbolAddress); + long response; + bool hasThreadManager ; + hasThreadManager = Gestalt( gestaltThreadMgrAttr, &response) == noErr && response & 1; +#if !TARGET_CARBON +#if GENERATINGCFM + // verify presence of shared library + hasThreadManager = hasThreadManager && ((Ptr)NewThread != (Ptr)kUnresolvedCFragSymbolAddress); +#endif #endif - if ( !hasThreadManager ) - { - wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK ) ; - return FALSE ; - } + if ( !hasThreadManager ) + { + wxLogSysError( wxT("Thread Support is not available on this System") ); + return FALSE ; + } // no error return for GetCurrentThreadId() MacGetCurrentThread( &gs_idMainThread ) ; @@ -843,10 +895,10 @@ bool WXDLLEXPORT wxGuiOwnedByMainThread() return false ; } -// wake up the main thread +// wake up the main thread void WXDLLEXPORT wxWakeUpMainThread() { - wxMacWakeUp() ; + wxMacWakeUp() ; } bool WXDLLEXPORT wxIsWaitingForThread() @@ -854,5 +906,6 @@ bool WXDLLEXPORT wxIsWaitingForThread() return false ; } -#endif // wxUSE_THREADS +#include "wx/thrimpl.cpp" +#endif // wxUSE_THREADS