📄 thread.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/carbon/thread.cpp
// Purpose: wxThread Implementation
// Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
// Modified by: Aj Lavin, Stefan Csomor
// Created: 04/22/98
// RCS-ID: $Id: thread.cpp,v 1.51 2006/06/15 17:58:33 ABX Exp $
// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
// Vadim Zeitlin (1999), Stefan Csomor (2000)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#if defined(__BORLANDC__)
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#if wxUSE_THREADS
#include "wx/module.h"
#include "wx/thread.h"
#ifdef __WXMAC__
#ifdef __DARWIN__
#include <CoreServices/CoreServices.h>
#else
#include <DriverServices.h>
#include <Multiprocessing.h>
#endif
#include "wx/mac/uma.h"
#endif
#include "wx/mac/macnotfy.h"
// the possible states of the thread:
// ("=>" shows all possible transitions from this state)
enum wxThreadState
{
STATE_NEW, // didn't start execution yet (=> RUNNING)
STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
STATE_EXITED // thread is terminating
};
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
// the task ID of the main thread
static wxThreadIdType gs_idMainThread = kInvalidID;
// 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
class wxMutexInternal
{
public:
wxMutexInternal( wxMutexType mutexType );
virtual ~wxMutexInternal();
bool IsOk() const
{ return m_isOk; }
wxMutexError Lock() ;
wxMutexError TryLock();
wxMutexError Unlock();
private:
MPCriticalRegionID m_critRegion;
bool m_isOk ;
};
wxMutexInternal::wxMutexInternal( wxMutexType mutexType )
{
m_isOk = false;
m_critRegion = kInvalidID;
verify_noerr( MPCreateCriticalRegion( &m_critRegion ) );
m_isOk = ( m_critRegion != kInvalidID );
if ( !IsOk() )
{
wxFAIL_MSG( wxT("Error when creating mutex") );
}
}
wxMutexInternal::~wxMutexInternal()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -