/////////////////////////////////////////////////////////////////////////////
-// Name: src/mac/carbon/thread.cpp
+// Name: src/osx/carbon/thread.cpp
// Purpose: wxThread Implementation
// Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
// Modified by: Aj Lavin, Stefan Csomor
#include "wx/thread.h"
+#if wxOSX_USE_COCOA_OR_CARBON
#include <CoreServices/CoreServices.h>
+#else
+#include <Foundation/Foundation.h>
+#endif
+
#include "wx/osx/uma.h"
// the possible states of the thread:
// wxCriticalSection
// ----------------------------------------------------------------------------
-wxCriticalSection::wxCriticalSection()
+wxCriticalSection::wxCriticalSection( wxCriticalSectionType WXUNUSED(critSecType) )
{
MPCreateCriticalRegion( (MPCriticalRegionID*) &m_critRegion );
}
#define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
#define wxUSE_MAC_PTHREADS_MUTEX 0
-#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
class wxMutexInternal
// wxCondition implementation
// ----------------------------------------------------------------------------
-#if 0
-
-class wxConditionInternal
-{
-public:
- wxConditionInternal( wxMutex& mutex )
- :
- m_mutex( mutex ),
- m_semaphore( 0, 1 ),
- m_gate( 1, 1 )
- {
- m_waiters = 0;
- m_signals = 0;
- m_canceled = 0;
- }
-
- virtual ~wxConditionInternal() {}
-
- bool IsOk() const
- { return m_mutex.IsOk(); }
-
- wxCondError Wait()
- { return WaitTimeout( kDurationForever ); }
-
- wxCondError WaitTimeout( unsigned long msectimeout );
-
- wxCondError Signal()
- { return DoSignal( false); }
-
- wxCondError Broadcast()
- { return DoSignal( true ); }
-
-private:
- wxCondError DoSignal( bool signalAll );
-
- wxMutex& m_mutex;
- wxSemaphoreInternal m_semaphore; // Signals the waiting threads.
- wxSemaphoreInternal m_gate;
- wxCriticalSection m_varSection;
- size_t m_waiters; // Number of threads waiting for a signal.
- size_t m_signals; // Number of signals to send.
- size_t m_canceled; // Number of canceled waiters in m_waiters.
-};
-
-wxCondError wxConditionInternal::WaitTimeout( unsigned long msectimeout )
-{
- m_gate.Wait();
-
- if ( ++ m_waiters == INT_MAX )
- {
- m_varSection.Enter();
-
- m_waiters -= m_canceled;
- m_signals -= m_canceled;
- m_canceled = 0;
-
- m_varSection.Leave();
- }
-
- m_gate.Post();
- m_mutex.Unlock();
-
- wxSemaError err = m_semaphore.WaitTimeout( msectimeout);
- wxASSERT( err == wxSEMA_NO_ERROR || err == wxSEMA_TIMEOUT);
-
- m_varSection.Enter();
-
- if ( err != wxSEMA_NO_ERROR )
- {
- if ( m_signals > m_canceled )
- {
- // A signal is being sent after we timed out.
- if ( m_waiters == m_signals )
- {
- // There are no excess waiters to catch the signal, so
- // we must throw it away.
- wxSemaError err2 = m_semaphore.Wait();
- if ( err2 != wxSEMA_NO_ERROR )
- {
- wxLogSysError( wx("Error while waiting on semaphore") );
- }
-
- wxASSERT( err2 == wxSEMA_NO_ERROR);
-
- --m_waiters;
- if ( --m_signals == m_canceled )
- {
- // This was the last signal. open the gate.
- wxASSERT( m_waiters == m_canceled );
- m_gate.Post();
- }
- }
- else
- {
- // There are excess waiters to catch the signal, leave it be.
- --m_waiters;
- }
- }
- else
- {
- // No signals is being sent:
- // the gate may be open or closed, so we can't touch m_waiters.
- ++m_canceled;
- ++m_signals;
- }
- }
- else
- {
- // We caught a signal.
- wxASSERT( m_signals > m_canceled );
-
- --m_waiters;
-
- if ( --m_signals == m_canceled)
- {
- // This was the last signal. open the gate.
- wxASSERT( m_waiters == m_canceled );
-
- m_gate.Post();
- }
- }
-
- m_varSection.Leave();
- m_mutex.Lock();
-
- if (err != noErr)
- return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
-
- return wxCOND_NO_ERROR;
-}
-
-
-wxCondError wxConditionInternal::DoSignal( bool signalAll)
-{
- m_gate.Wait();
- m_varSection.Enter();
-
- wxASSERT( m_signals == m_canceled );
-
- if ( m_waiters == m_canceled)
- {
- m_varSection.Leave();
- m_gate.Post();
- return wxCOND_NO_ERROR;
- }
-
- if ( m_canceled > 0)
- {
- m_waiters -= m_canceled;
- m_signals = 0;
- m_canceled = 0;
- }
-
- m_signals = signalAll ? m_waiters : 1;
- size_t n = m_signals;
-
- m_varSection.Leave();
-
- // Let the waiters inherit the gate lock.
-
- do
- {
- wxSemaError err = m_semaphore.Post();
- wxASSERT( err == wxSEMA_NO_ERROR );
- }
- while ( --n );
-
- return wxCOND_NO_ERROR;
-}
-
-#else
class wxConditionInternal
{
public:
wxMutex& m_mutex;
wxSemaphore m_semaphore;
- DECLARE_NO_COPY_CLASS(wxConditionInternal)
+ wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
};
wxConditionInternal::wxConditionInternal( wxMutex& mutex )
return wxCOND_NO_ERROR;
}
-#endif
// ----------------------------------------------------------------------------
// wxCriticalSection implementation
g_numberOfThreads--;
-#ifdef __WXDEBUG__
m_critsect.Enter();
// check that the thread either exited or couldn't be created
}
m_critsect.Leave();
-#endif
wxDELETE( m_internal ) ;
}