📄 mpthread.cpp
字号:
/////////////////////////////////////////////////////////////////////////////// Name: src/mac/carbon/mpthread.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: mpthread.cpp,v 1.12 2006/08/31 19:30:43 ABX Exp $// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),// Vadim Zeitlin (1999) , Stefan Csomor (2000)// Licence: wxWindows licence/////////////////////////////////////////////////////////////////////////////// ----------------------------------------------------------------------------// headers// ----------------------------------------------------------------------------// For compilers that support precompilation, includes "wx.h".#include "wx/wxprec.h"#if defined(__BORLANDC__) #pragma hdrstop#endif#if wxUSE_THREADS#ifndef WX_PRECOMP #include "wx/wx.h" #include "wx/module.h"#endif#include "wx/thread.h"#ifdef __WXMAC__#if TARGET_API_MAC_OSX#include <CoreServices/CoreServices.h>#else#include <DriverServices.h>#include <Multiprocessing.h>#endif#include "wx/mac/uma.h"#endif// ----------------------------------------------------------------------------// constants// ----------------------------------------------------------------------------// 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};// ----------------------------------------------------------------------------// this module 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 two 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 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*/// ----------------------------------------------------------------------------// wxMutex implementation// ----------------------------------------------------------------------------static bool wxMacMPThreadsInitVerify(){ static bool hasThreadManager = false ; if ( !hasThreadManager ) hasThreadManager = MPLibraryIsLoaded(); if ( !hasThreadManager ) { wxMessageBox( wxT("Error") , wxT("MP Thread Support is not available on this System" ), wxOK ) ; return false ; } return true ;}#if 0class wxMutexInternal{public: wxMutexInternal(wxMutexType mutexType) ; ~wxMutexInternal() ; bool IsOk() const { return m_isOk; } wxMutexError Lock() ; wxMutexError TryLock() ; wxMutexError Unlock();private: MPSemaphoreID m_semaphore; bool m_isOk ;};wxMutexInternal::wxMutexInternal(wxMutexType mutexType ){ wxMacMPThreadsInitVerify() ; 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);}wxMutexError wxMutexInternal::Lock(){ wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ; OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationForever); if ( err) { 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) { 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); if ( err) { wxLogSysError(_("Could not unlock mutex")); return wxMUTEX_MISC_ERROR; } return wxMUTEX_NO_ERROR;}#elseclass wxMutexInternal{public: wxMutexInternal(wxMutexType mutexType) ; ~wxMutexInternal() ; bool IsOk() const { return m_isOk; } wxMutexError Lock() ; wxMutexError TryLock() ; wxMutexError Unlock();private: MPCriticalRegionID m_critRegion ; bool m_isOk ;};wxMutexInternal::wxMutexInternal(wxMutexType mutexType ){ wxMacMPThreadsInitVerify() ; 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);}wxMutexError wxMutexInternal::Lock(){ wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ; OSStatus err = MPEnterCriticalRegion( m_critRegion, kDurationForever); if ( err) { 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) { 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); if ( err) { wxLogSysError(_("Could not unlock mutex")); return wxMUTEX_MISC_ERROR; } return wxMUTEX_NO_ERROR;}#endif// --------------------------------------------------------------------------// wxSemaphore// --------------------------------------------------------------------------class wxSemaphoreInternal{public: wxSemaphoreInternal(int initialcount, int maxcount); ~wxSemaphoreInternal(); bool IsOk() const { return m_isOk; } 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 ; } wxSemaError Post();private: MPSemaphoreID m_semaphore; bool m_isOk ;};wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount){ wxMacMPThreadsInitVerify() ; 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);}wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds){ OSStatus err = MPWaitOnSemaphore( m_semaphore, milliseconds); if ( err) { if ( err == kMPTimeoutErr) { return wxSEMA_TIMEOUT; } return wxSEMA_MISC_ERROR; } return wxSEMA_NO_ERROR;}wxSemaError wxSemaphoreInternal::Post(){ OSStatus err = MPSignalSemaphore( m_semaphore); if ( err) { return wxSEMA_MISC_ERROR; } return wxSEMA_NO_ERROR;}// ----------------------------------------------------------------------------// wxCondition implementation// ----------------------------------------------------------------------------#if 0class 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; } ~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(_("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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -