+// this is the Per-Task Storage for the pointer to the appropriate wxThread
+TaskStorageIndex gs_tlsForWXThread = 0;
+
+// if it's false, some secondary thread is holding the GUI lock
+static bool gs_bGuiOwnedByMainThread = true;
+
+// critical section which controls access to all GUI functions: any secondary
+// thread (i.e. except the main one) must enter this crit section before doing
+// any GUI calls
+static wxCriticalSection *gs_critsectGui = NULL;
+
+// critical section which protects gs_nWaitingForGui variable
+static wxCriticalSection *gs_critsectWaitingForGui = NULL;
+
+// number of threads waiting for GUI in wxMutexGuiEnter()
+static size_t gs_nWaitingForGui = 0;
+
+// overall number of threads, needed for determining
+// the sleep value of the main event loop
+size_t g_numberOfThreads = 0;
+
+
+#if wxUSE_GUI
+MPCriticalRegionID gs_guiCritical = kInvalidID;
+#endif
+
+// ============================================================================
+// MacOS implementation of thread classes
+// ============================================================================
+
+/*
+ Notes :
+
+ The implementation is very close to the phtreads implementation, the reason for
+ using MPServices is the fact that these are also available under OS 9. Thus allowing
+ for one common API for all current builds.
+
+ As soon as wxThreads are on a 64 bit address space, the TLS must be extended
+ to use two indices one for each 32 bit part as the MP implementation is limited
+ to longs.
+
+ I have three implementations for mutexes :
+ version A based on a binary semaphore, problem - not reentrant, version B based
+ on a critical region, allows for reentrancy, performance implications not
+ yet tested, and third a plain pthreads implementation
+
+ The same for condition internal, one implementation by Aj Lavin and the other one
+ copied from the thrimpl.cpp which I assume has been more broadly tested, I've just
+ replaced the interlock increment with the appropriate PPC calls
+*/
+
+// ----------------------------------------------------------------------------
+// wxCriticalSection
+// ----------------------------------------------------------------------------
+
+wxCriticalSection::wxCriticalSection()
+{
+ MPCreateCriticalRegion( (MPCriticalRegionID*) &m_critRegion );
+}
+
+wxCriticalSection::~wxCriticalSection()
+{
+ MPDeleteCriticalRegion( (MPCriticalRegionID) m_critRegion );
+}
+
+void wxCriticalSection::Enter()
+{
+ MPEnterCriticalRegion( (MPCriticalRegionID) m_critRegion, kDurationForever );
+}
+
+void wxCriticalSection::Leave()
+{
+ MPExitCriticalRegion( (MPCriticalRegionID) m_critRegion );
+}
+
+// ----------------------------------------------------------------------------
+// wxMutex implementation
+// ----------------------------------------------------------------------------
+
+#if TARGET_API_MAC_OSX
+#define wxUSE_MAC_SEMAPHORE_MUTEX 0
+#define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
+#define wxUSE_MAC_PTHREADS_MUTEX 0
+#else
+#define wxUSE_MAC_SEMAPHORE_MUTEX 0
+#define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
+#define wxUSE_MAC_PTHREADS_MUTEX 0
+#endif
+
+#if wxUSE_MAC_PTHREADS_MUTEX
+
+#include <pthread.h>
+
+
+class wxMutexInternal
+{
+public:
+ wxMutexInternal( wxMutexType mutexType );
+ ~wxMutexInternal();
+
+ wxMutexError Lock();
+ wxMutexError TryLock();
+ wxMutexError Unlock();
+
+ bool IsOk() const
+ { return m_isOk; }
+
+private:
+ pthread_mutex_t m_mutex;
+ bool m_isOk;
+
+ // wxConditionInternal uses our m_mutex
+ friend class wxConditionInternal;
+};
+
+#ifdef HAVE_PTHREAD_MUTEXATTR_T
+// on some systems pthread_mutexattr_settype() is not in the headers (but it is
+// in the library, otherwise we wouldn't compile this code at all)
+extern "C" int pthread_mutexattr_settype( pthread_mutexattr_t *, int );
+#endif
+
+wxMutexInternal::wxMutexInternal( wxMutexType mutexType )
+{
+ int err;
+ switch ( mutexType )
+ {
+ case wxMUTEX_RECURSIVE:
+ // support recursive locks like Win32, i.e. a thread can lock a
+ // mutex which it had itself already locked
+ //
+ // unfortunately initialization of recursive mutexes is non
+ // portable, so try several methods
+#ifdef HAVE_PTHREAD_MUTEXATTR_T
+ {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init( &attr );
+ pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
+
+ err = pthread_mutex_init( &m_mutex, &attr );
+ }
+#elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
+ // we can use this only as initializer so we have to assign it
+ // first to a temp var - assigning directly to m_mutex wouldn't
+ // even compile
+ {
+ pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+ m_mutex = mutex;
+ }
+#else // no recursive mutexes
+ err = EINVAL;
+#endif // HAVE_PTHREAD_MUTEXATTR_T/...
+ break;
+
+ default:
+ wxFAIL_MSG( wxT("unknown mutex type") );
+ // fall through
+
+ case wxMUTEX_DEFAULT:
+ err = pthread_mutex_init( &m_mutex, NULL );
+ break;
+ }
+
+ m_isOk = err == 0;
+ if ( !m_isOk )
+ {
+ wxLogApiError( wxT("pthread_mutex_init()"), err );
+ }
+}
+
+wxMutexInternal::~wxMutexInternal()
+{
+ if ( m_isOk )
+ {
+ int err = pthread_mutex_destroy( &m_mutex );
+ if ( err != 0 )
+ {
+ wxLogApiError( wxT("pthread_mutex_destroy()"), err );
+ }
+ }
+}
+
+wxMutexError wxMutexInternal::Lock()
+{
+ int err = pthread_mutex_lock( &m_mutex );
+ switch ( err )
+ {
+ case EDEADLK:
+ // only error checking mutexes return this value and so it's an
+ // unexpected situation -- hence use assert, not wxLogDebug
+ wxFAIL_MSG( wxT("mutex deadlock prevented") );
+ return wxMUTEX_DEAD_LOCK;
+
+ case EINVAL:
+ wxLogDebug( wxT("pthread_mutex_lock(): mutex not initialized.") );
+ break;
+
+ case 0:
+ return wxMUTEX_NO_ERROR;
+
+ default:
+ wxLogApiError( wxT("pthread_mutex_lock()"), err );
+ }
+
+ return wxMUTEX_MISC_ERROR;
+}
+
+wxMutexError wxMutexInternal::TryLock()
+{
+ int err = pthread_mutex_trylock( &m_mutex );
+ switch ( err )
+ {
+ case EBUSY:
+ // not an error: mutex is already locked, but we're prepared for this case
+ return wxMUTEX_BUSY;
+
+ case EINVAL:
+ wxLogDebug( wxT("pthread_mutex_trylock(): mutex not initialized.") );
+ break;
+
+ case 0:
+ return wxMUTEX_NO_ERROR;
+
+ default:
+ wxLogApiError( wxT("pthread_mutex_trylock()"), err );
+ }
+
+ return wxMUTEX_MISC_ERROR;
+}
+
+wxMutexError wxMutexInternal::Unlock()
+{
+ int err = pthread_mutex_unlock( &m_mutex );
+ switch ( err )
+ {
+ case EPERM:
+ // we don't own the mutex
+ return wxMUTEX_UNLOCKED;
+
+ case EINVAL:
+ wxLogDebug( wxT("pthread_mutex_unlock(): mutex not initialized.") );
+ break;
+
+ case 0:
+ return wxMUTEX_NO_ERROR;
+
+ default:
+ wxLogApiError( wxT("pthread_mutex_unlock()"), err );
+ }
+
+ return wxMUTEX_MISC_ERROR;
+}
+
+#endif
+
+#if wxUSE_MAC_SEMAPHORE_MUTEX
+
+class wxMutexInternal
+{
+public:
+ wxMutexInternal( wxMutexType mutexType );
+ virtual ~wxMutexInternal();
+
+ bool IsOk() const
+ { return m_isOk; }
+
+ wxMutexError Lock();
+ wxMutexError TryLock();
+ wxMutexError Unlock();
+
+private:
+ MPSemaphoreID m_semaphore;
+ bool m_isOk;
+};
+
+wxMutexInternal::wxMutexInternal(wxMutexType mutexType )
+{
+ m_isOk = false;
+ m_semaphore = kInvalidID;
+ OSStatus err = noErr;
+
+ switch ( mutexType )
+ {
+ case wxMUTEX_DEFAULT :
+ verify_noerr( MPCreateBinarySemaphore( &m_semaphore ) );
+ m_isOk = ( m_semaphore != kInvalidID );
+ break;
+
+ case wxMUTEX_RECURSIVE :
+ wxFAIL_MSG( wxT("Recursive Mutex not supported yet") );
+ break;
+
+ default :
+ wxFAIL_MSG( wxT("Unknown mutex type") );
+ break;
+ }
+}
+
+wxMutexInternal::~wxMutexInternal()
+{
+ if ( m_semaphore != kInvalidID )
+ MPDeleteSemaphore( m_semaphore );
+
+ MPYield();
+}
+
+wxMutexError wxMutexInternal::Lock()
+{
+ wxCHECK_MSG( m_isOk, wxMUTEX_MISC_ERROR, wxT("Invalid Mutex") );
+ OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationForever );
+ if (err != noErr)
+ {
+ wxLogSysError( wxT("Could not lock mutex") );
+
+ return wxMUTEX_MISC_ERROR;
+ }
+
+ return wxMUTEX_NO_ERROR;
+}
+
+wxMutexError wxMutexInternal::TryLock()
+{
+ wxCHECK_MSG( m_isOk, wxMUTEX_MISC_ERROR, wxT("Invalid Mutex") );
+ OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationImmediate );
+ if (err != noErr)
+ {
+ if (err == kMPTimeoutErr)
+ return wxMUTEX_BUSY;
+
+ wxLogSysError( wxT("Could not try lock mutex") );
+
+ return wxMUTEX_MISC_ERROR;
+ }
+
+ return wxMUTEX_NO_ERROR;
+}
+
+wxMutexError wxMutexInternal::Unlock()
+{
+ wxCHECK_MSG( m_isOk, wxMUTEX_MISC_ERROR, wxT("Invalid Mutex") );
+ OSStatus err = MPSignalSemaphore( m_semaphore );
+
+ MPYield();
+ if (err != noErr)
+ {
+ wxLogSysError( wxT("Could not unlock mutex") );
+ return wxMUTEX_MISC_ERROR;
+ }
+
+ return wxMUTEX_NO_ERROR;
+}
+
+#endif
+
+#if wxUSE_MAC_CRITICAL_REGION_MUTEX