📄 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.54 2006/10/14 15:30:02 SC 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" #include "wx/module.h"#endif#if wxUSE_THREADS#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 threadstatic wxThreadIdType gs_idMainThread = kInvalidID;// this is the Per-Task Storage for the pointer to the appropriate wxThreadTaskStorageIndex gs_tlsForWXThread = 0;// if it's false, some secondary thread is holding the GUI lockstatic 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 callsstatic wxCriticalSection *gs_critsectGui = NULL;// critical section which protects gs_nWaitingForGui variablestatic 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 loopsize_t g_numberOfThreads = 0;#if wxUSE_GUIMPCriticalRegionID 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 );#endifwxMutexInternal::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_MUTEXclass 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_MUTEXclass 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(){ if ( m_critRegion != kInvalidID ) MPDeleteCriticalRegion( m_critRegion ); MPYield();}wxMutexError wxMutexInternal::Lock(){ wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ); OSStatus err = MPEnterCriticalRegion( m_critRegion, 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 = MPEnterCriticalRegion( m_critRegion, 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 = MPExitCriticalRegion( m_critRegion ); MPYield() ; if (err != noErr) { wxLogSysError( wxT("Could not unlock mutex") ); return wxMUTEX_MISC_ERROR; } return wxMUTEX_NO_ERROR;}#endif// --------------------------------------------------------------------------// wxSemaphore// --------------------------------------------------------------------------class wxSemaphoreInternal{public: wxSemaphoreInternal( int initialcount, int maxcount ); virtual ~wxSemaphoreInternal(); bool IsOk() const { return m_isOk; } wxSemaError Post(); wxSemaError WaitTimeout( unsigned long milliseconds ); wxSemaError Wait() { return WaitTimeout( kDurationForever); } wxSemaError TryWait() { wxSemaError err = WaitTimeout( kDurationImmediate ); if (err == wxSEMA_TIMEOUT) err = wxSEMA_BUSY; return err; }private: MPSemaphoreID m_semaphore; bool m_isOk;};wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount){ m_isOk = false; m_semaphore = kInvalidID; if ( maxcount == 0 ) // make it practically infinite maxcount = INT_MAX; verify_noerr( MPCreateSemaphore( maxcount, initialcount, &m_semaphore ) ); m_isOk = ( m_semaphore != kInvalidID ); if ( !IsOk() ) { wxFAIL_MSG( wxT("Error when creating semaphore") ); }}wxSemaphoreInternal::~wxSemaphoreInternal(){ if (m_semaphore != kInvalidID) MPDeleteSemaphore( m_semaphore ); MPYield();}wxSemaError wxSemaphoreInternal::WaitTimeout( unsigned long milliseconds ){ OSStatus err = MPWaitOnSemaphore( m_semaphore, milliseconds ); if (err != noErr) { if (err == kMPTimeoutErr) return wxSEMA_TIMEOUT; return wxSEMA_MISC_ERROR; } return wxSEMA_NO_ERROR;}wxSemaError wxSemaphoreInternal::Post(){ OSStatus err = MPSignalSemaphore( m_semaphore ); MPYield(); if (err != noErr) return wxSEMA_MISC_ERROR; return wxSEMA_NO_ERROR;}// ----------------------------------------------------------------------------// wxCondition implementation// ----------------------------------------------------------------------------#if 0class wxConditionInternal{public: wxConditionInternal( wxMutex& mutex ) :
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -