#include "wx/module.h"
#include "wx/thread.h"
+#ifdef __WXMAC__
+#include <Threads.h>
+#include "wx/mac/uma.h"
+#include "wx/mac/macnotfy.h"
+#include <Timer.h>
+#endif
+
+#define INFINITE 0xFFFFFFFF
+
+
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
static ThreadID gs_idMainThread = kNoThreadID ;
static bool gs_waitingForThread = FALSE ;
+size_t g_numberOfThreads = 0;
// ============================================================================
// MacOS implementation of thread classes
class wxMacStCritical
{
public :
- wxMacStCritical()
- {
- ThreadBeginCritical() ;
- }
- ~wxMacStCritical()
- {
- ThreadEndCritical() ;
- }
-} ;
+ wxMacStCritical()
+ {
+ if ( UMASystemIsInitialized() )
+ ThreadBeginCritical() ;
+ }
+ ~wxMacStCritical()
+ {
+ if ( UMASystemIsInitialized() )
+ ThreadEndCritical() ;
+ }
+};
// ----------------------------------------------------------------------------
// wxMutex implementation
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
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
}
// 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();
// 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 ; }
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 ;
}
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 )
{
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;
}
// ----------------
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;
bool wxThread::IsMain()
{
- ThreadID current ;
- OSErr err ;
-
- err = MacGetCurrentThread( ¤t ) ;
+ ThreadID current ;
+ OSErr err ;
+
+ err = MacGetCurrentThread( ¤t ) ;
return current == gs_idMainThread;
}
void wxThread::Yield()
{
- ::YieldToAnyThread() ;
+ ::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()
{
- // 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") );
// processor system it doesn't make much sense anyhow
return level == 1;
}
-
+
return TRUE ;
}
wxThread::wxThread(wxThreadKind kind)
{
+ g_numberOfThreads++;
m_internal = new wxThreadInternal();
m_isDetached = kind == wxTHREAD_DETACHED;
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;
#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() )
}
}
- // if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
- {
- wxLogLastError("GetExitCodeThread");
-
- rc = (ExitCode)-1;
- }
-
if ( IsDetached() )
{
// if the thread exits normally, this is done in WinThreadStart, but in
delete this;
}
- // wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
- // wxT("thread must be already terminated.") );
-
if ( pRc )
*pRc = rc;
delete this;
}
- m_internal->SetResult( status ) ;
+ m_internal->SetResult( status ) ;
-/*
+/*
#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
_endthreadex((unsigned)status);
#else // !VC++
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 ) ;
return false ;
}
-// wake up the main thread
+// wake up the main thread
void WXDLLEXPORT wxWakeUpMainThread()
{
- wxMacWakeUp() ;
+ wxMacWakeUp() ;
}
bool WXDLLEXPORT wxIsWaitingForThread()
return false ;
}
-#endif // wxUSE_THREADS
+#include "wx/thrimpl.cpp"
+#endif // wxUSE_THREADS