Implemented ELF loading! :D

Renamed a bunch of functions/methods in the Threading namespace that have been bugging me for a while.  (MutexLock is renamed to Mutex, Lock() is renamed to Aquire(), etc)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2102 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-10-31 19:18:29 +00:00
parent 655038be45
commit bc2aa38aa1
14 changed files with 254 additions and 189 deletions

View File

@ -38,15 +38,16 @@ namespace Exception
#if wxUSE_GUI
// --------------------------------------------------------------------------------------
// ThreadTimedOut Exception
// --------------------------------------------------------------------------------------
// This exception is thrown by Semaphore and Mutex Wait/Lock functions if a blocking wait is
// needed due to gui Yield recursion, and the timeout period for deadlocking (usually 3 seconds)
// is reached before the lock becomes available. This exception cannot occur in the following
// conditions:
// * If the user-specified timeout is less than the deadlock timeout.
// * If the method is run from a thread *other* than the MainGui thread.
// --------------------------------------------------------------------------------------
// ThreadTimedOut Exception
// --------------------------------------------------------------------------------------
// This exception is thrown by Semaphore and Mutex Wait/Aquire functions if a blocking wait is
// needed due to gui Yield recursion, and the timeout period for deadlocking (usually 3 seconds)
// is reached before the lock becomes available. This exception cannot occur in the following
// conditions:
// * If the user-specified timeout is less than the deadlock timeout.
// * If the method is run from a thread *other* than the MainGui thread.
//
class ThreadTimedOut : public virtual RuntimeError
{
public:
@ -57,12 +58,11 @@ namespace Exception
namespace Threading
{
// --------------------------------------------------------------------------------------
// Platform Specific External APIs
// --------------------------------------------------------------------------------------
// The following set of documented functions have Linux/Win32 specific implementations,
// which are found in WinThreads.cpp and LnxThreads.cpp
// --------------------------------------------------------------------------------------
// Platform Specific External APIs
// --------------------------------------------------------------------------------------
// The following set of documented functions have Linux/Win32 specific implementations,
// which are found in WinThreads.cpp and LnxThreads.cpp
// Returns the number of available logical CPUs (cores plus hyperthreaded cpus)
extern void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU );
@ -81,6 +81,31 @@ namespace Threading
// sleeps the current thread for the given number of milliseconds.
extern void Sleep( int ms );
// --------------------------------------------------------------------------------------
// AtomicExchange / AtomicIncrement
// --------------------------------------------------------------------------------------
// Our fundamental interlocking functions. All other useful interlocks can be derived
// from these little beasties! (these are all implemented internally using cross-platform
// implementations of _InterlockedExchange and such)
extern u32 AtomicExchange( volatile u32& Target, u32 value );
extern u32 AtomicExchangeAdd( volatile u32& Target, u32 value );
extern u32 AtomicIncrement( volatile u32& Target );
extern u32 AtomicDecrement( volatile u32& Target );
extern s32 AtomicExchange( volatile s32& Target, s32 value );
extern s32 AtomicExchangeAdd( volatile s32& Target, u32 value );
extern s32 AtomicIncrement( volatile s32& Target );
extern s32 AtomicDecrement( volatile s32& Target );
extern void* _AtomicExchangePointer( void * volatile * const target, void* const value );
extern void* _AtomicCompareExchangePointer( void * volatile * const target, void* const value, void* const comparand );
#define AtomicExchangePointer( target, value ) \
_InterlockedExchangePointer( &target, value )
#define AtomicCompareExchangePointer( target, value, comparand ) \
_InterlockedCompareExchangePointer( &target, value, comparand )
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
@ -98,36 +123,38 @@ namespace Threading
};
#endif
// --------------------------------------------------------------------------------------
// NonblockingMutex
// --------------------------------------------------------------------------------------
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
// trylock(), but without any of the extra overhead needed to set up a structure capable
// of blocking waits. It basically optimizes to a single InterlockedExchange.
//
// Simple use: if TryLock() returns false, the Bool is already interlocked by another thread.
// If TryLock() returns true, you've locked the object and are *responsible* for unlocking
// it later.
//
// --------------------------------------------------------------------------------------
// NonblockingMutex
// --------------------------------------------------------------------------------------
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
// trylock(), but without any of the extra overhead needed to set up a structure capable
// of blocking waits. It basically optimizes to a single InterlockedExchange.
//
// Simple use: if TryAquire() returns false, the Bool is already interlocked by another thread.
// If TryAquire() returns true, you've locked the object and are *responsible* for unlocking
// it later.
//
class NonblockingMutex
{
protected:
volatile long val;
volatile int val;
public:
NonblockingMutex() : val( false ) {}
virtual ~NonblockingMutex() throw() {}
bool TryLock() throw()
bool TryAquire() throw()
{
return !_InterlockedExchange( &val, true );
return !AtomicExchange( val, true );
}
bool IsLocked()
{ return !!val; }
void Release()
{ val = false; }
{
AtomicExchange( val, false );
}
};
class Semaphore
@ -153,37 +180,37 @@ namespace Threading
bool Wait( const wxTimeSpan& timeout );
};
class MutexLock
class Mutex
{
protected:
pthread_mutex_t m_mutex;
public:
MutexLock();
virtual ~MutexLock() throw();
Mutex();
virtual ~Mutex() throw();
virtual bool IsRecursive() const { return false; }
void Recreate();
bool RecreateIfLocked();
void Detach();
void Lock();
bool Lock( const wxTimeSpan& timeout );
bool TryLock();
void Unlock();
void Aquire();
bool Aquire( const wxTimeSpan& timeout );
bool TryAquire();
void Release();
void LockRaw();
bool LockRaw( const wxTimeSpan& timeout );
void FullBlockingAquire();
bool FullBlockingAquire( const wxTimeSpan& timeout );
void Wait();
bool Wait( const wxTimeSpan& timeout );
protected:
// empty constructor used by MutexLockRecursive
MutexLock( bool ) {}
Mutex( bool ) {}
};
class MutexLockRecursive : public MutexLock
class MutexLockRecursive : public Mutex
{
public:
MutexLockRecursive();
@ -253,7 +280,7 @@ namespace Threading
pthread_t m_thread;
Semaphore m_sem_event; // general wait event that's needed by most threads.
MutexLock m_lock_InThread; // used for canceling and closing threads in a deadlock-safe manner
Mutex m_lock_InThread; // used for canceling and closing threads in a deadlock-safe manner
MutexLockRecursive m_lock_start; // used to lock the Start() code from starting simultaneous threads accidentally.
volatile long m_detached; // a boolean value which indicates if the m_thread handle is valid
@ -275,7 +302,7 @@ namespace Threading
virtual void RethrowException() const;
void WaitOnSelf( Semaphore& mutex );
void WaitOnSelf( MutexLock& mutex );
void WaitOnSelf( Mutex& mutex );
bool IsRunning() const;
bool IsSelf() const;
@ -315,7 +342,7 @@ namespace Threading
TestCancel();
}
void FrankenMutex( MutexLock& mutex );
void FrankenMutex( Mutex& mutex );
// ----------------------------------------------------------------------------
// Section of methods for internal use only.
@ -330,46 +357,48 @@ namespace Threading
static void _pt_callback_cleanup( void* handle );
};
//////////////////////////////////////////////////////////////////////////////////////////
// ScopedLock: Helper class for using Mutexes.
// Using this class provides an exception-safe (and generally clean) method of locking
// code inside a function or conditional block.
// --------------------------------------------------------------------------------------
// ScopedLock
// --------------------------------------------------------------------------------------
// Helper class for using Mutexes. Using this class provides an exception-safe (and
// generally clean) method of locking code inside a function or conditional block. The lock
// will be automatically released on any return or exit from the function.
//
class ScopedLock
{
DeclareNoncopyableObject(ScopedLock);
protected:
MutexLock& m_lock;
Mutex& m_lock;
bool m_IsLocked;
public:
virtual ~ScopedLock() throw()
{
if( m_IsLocked )
m_lock.Unlock();
m_lock.Release();
}
ScopedLock( MutexLock& locker ) :
ScopedLock( Mutex& locker ) :
m_lock( locker )
, m_IsLocked( true )
{
m_lock.Lock();
m_lock.Aquire();
}
// Provides manual unlocking of a scoped lock prior to object destruction.
void Unlock()
void Release()
{
if( !m_IsLocked ) return;
m_IsLocked = false;
m_lock.Unlock();
m_lock.Release();
}
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
void Lock()
void Aquire()
{
if( m_IsLocked ) return;
m_lock.Lock();
m_lock.Aquire();
m_IsLocked = true;
}
@ -377,9 +406,9 @@ namespace Threading
protected:
// Special constructor used by ScopedTryLock
ScopedLock( MutexLock& locker, bool isTryLock ) :
ScopedLock( Mutex& locker, bool isTryLock ) :
m_lock( locker )
, m_IsLocked( isTryLock ? m_lock.TryLock() : false )
, m_IsLocked( isTryLock ? m_lock.TryAquire() : false )
{
}
@ -388,51 +417,84 @@ namespace Threading
class ScopedTryLock : public ScopedLock
{
public:
ScopedTryLock( MutexLock& locker ) : ScopedLock( locker, true ) { }
ScopedTryLock( Mutex& locker ) : ScopedLock( locker, true ) { }
virtual ~ScopedTryLock() throw() {}
bool Failed() const { return !m_IsLocked; }
};
//////////////////////////////////////////////////////////////////////////////////////////
// BaseTaskThread - an abstract base class which provides simple parallel execution of
// single tasks.
//
// Implementation:
// To use this class your derived class will need to implement its own Task() function
// and also a "StartTask( parameters )" function which suits the need of your task, along
// with any local variables your task needs to do its job. You may additionally want to
// implement a "GetResult()" function, which would be a combination of WaitForResult()
// and a return value of the computational result.
//
// Thread Safety:
// If operating on local variables, you must execute WaitForResult() before leaving the
// variable scope -- or alternatively have your StartTask() implementation make full
// copies of dependent data. Also, by default PostTask() always assumes the previous
// task has completed. If your system can post a new task before the previous one has
// completed, then it needs to explicitly call WaitForResult() or provide a mechanism
// to cancel the previous task (which is probably more work than it's worth).
//
// Performance notes:
// * Remember that thread creation is generally slow, so you should make your object
// instance once early and then feed it tasks repeatedly over the course of program
// execution.
//
// * For threading to be a successful speedup, the task being performed should be as lock
// free as possible. For example using STL containers in parallel usually fails to
// yield any speedup due to the gratuitous amount of locking that the STL performs
// internally.
//
// * The best application of tasking threads is to divide a large loop over a linear array
// into smaller sections. For example, if you have 20,000 items to process, the task
// can be divided into two threads of 10,000 items each.
//
// --------------------------------------------------------------------------------------
// ScopedNonblockingLock
// --------------------------------------------------------------------------------------
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
//
class ScopedNonblockingLock
{
DeclareNoncopyableObject(ScopedNonblockingLock);
protected:
NonblockingMutex& m_lock;
bool m_IsLocked;
public:
ScopedNonblockingLock( NonblockingMutex& locker ) :
m_lock( locker )
, m_IsLocked( m_lock.TryAquire() )
{
}
virtual ~ScopedNonblockingLock() throw()
{
if( m_IsLocked )
m_lock.Release();
}
bool Failed() const { return !m_IsLocked; }
};
// --------------------------------------------------------------------------------------
// BaseTaskThread
// --------------------------------------------------------------------------------------
// an abstract base class which provides simple parallel execution of single tasks.
//
// FIXME: This class is incomplete and untested! Don't use, unless you want to fix it
// while you're at it. :D
//
// Implementation:
// To use this class your derived class will need to implement its own Task() function
// and also a "StartTask( parameters )" function which suits the need of your task, along
// with any local variables your task needs to do its job. You may additionally want to
// implement a "GetResult()" function, which would be a combination of WaitForResult()
// and a return value of the computational result.
//
// Thread Safety:
// If operating on local variables, you must execute WaitForResult() before leaving the
// variable scope -- or alternatively have your StartTask() implementation make full
// copies of dependent data. Also, by default PostTask() always assumes the previous
// task has completed. If your system can post a new task before the previous one has
// completed, then it needs to explicitly call WaitForResult() or provide a mechanism
// to cancel the previous task (which is probably more work than it's worth).
//
// Performance notes:
// * Remember that thread creation is generally slow, so you should make your object
// instance once early and then feed it tasks repeatedly over the course of program
// execution.
//
// * For threading to be a successful speedup, the task being performed should be as lock
// free as possible. For example using STL containers in parallel usually fails to
// yield any speedup due to the gratuitous amount of locking that the STL performs
// internally.
//
// * The best application of tasking threads is to divide a large loop over a linear array
// into smaller sections. For example, if you have 20,000 items to process, the task
// can be divided into two threads of 10,000 items each.
//
class BaseTaskThread : public PersistentThread
{
protected:
volatile bool m_Done;
volatile bool m_TaskPending;
Semaphore m_post_TaskComplete;
MutexLock m_lock_TaskComplete;
Mutex m_lock_TaskComplete;
public:
virtual ~BaseTaskThread() throw() {}
@ -454,28 +516,5 @@ namespace Threading
virtual void ExecuteTaskInThread();
};
//////////////////////////////////////////////////////////////////////////////////////////
// Our fundamental interlocking functions. All other useful interlocks can be derived
// from these little beasties!
extern u32 AtomicExchange( volatile u32& Target, u32 value );
extern u32 AtomicExchangeAdd( volatile u32& Target, u32 value );
extern u32 AtomicIncrement( volatile u32& Target );
extern u32 AtomicDecrement( volatile u32& Target );
extern s32 AtomicExchange( volatile s32& Target, s32 value );
extern s32 AtomicExchangeAdd( volatile s32& Target, u32 value );
extern s32 AtomicIncrement( volatile s32& Target );
extern s32 AtomicDecrement( volatile s32& Target );
extern void* _AtomicExchangePointer( void * volatile * const target, void* const value );
extern void* _AtomicCompareExchangePointer( void * volatile * const target, void* const value, void* const comparand );
#define AtomicExchangePointer( target, value ) \
_InterlockedExchangePointer( &target, value )
#define AtomicCompareExchangePointer( target, value, comparand ) \
_InterlockedCompareExchangePointer( &target, value, comparand )
}

View File

@ -204,7 +204,7 @@ const IConsoleWriter ConsoleWriter_wxError =
static const int MaxFormattedStringLength = 0x80000;
template< typename CharType >
class FormatBuffer : public MutexLock
class FormatBuffer : public Mutex
{
public:
bool& clearbit;

View File

@ -27,15 +27,15 @@ namespace Threading
}
// --------------------------------------------------------------------------------------
// MutexLock Implementations
// Mutex Implementations
// --------------------------------------------------------------------------------------
Threading::MutexLock::MutexLock()
Threading::Mutex::Mutex()
{
pthread_mutex_init( &m_mutex, NULL );
}
void Threading::MutexLock::Detach()
void Threading::Mutex::Detach()
{
if( EBUSY != pthread_mutex_destroy(&m_mutex) ) return;
@ -46,7 +46,7 @@ void Threading::MutexLock::Detach()
// (note: if the mutex is locked recursively more than twice then this assert won't
// detect it)
Unlock(); Unlock(); // in case of double recursion.
Release(); Release(); // in case of double recursion.
int result = pthread_mutex_destroy( &m_mutex );
if( pxAssertDev( result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!)." ) ) return;
}
@ -57,14 +57,14 @@ void Threading::MutexLock::Detach()
Console.Error( "(Thread Log) Mutex cleanup failed due to possible deadlock.");
}
Threading::MutexLock::~MutexLock() throw()
Threading::Mutex::~Mutex() throw()
{
try {
MutexLock::Detach();
Mutex::Detach();
} DESTRUCTOR_CATCHALL;
}
Threading::MutexLockRecursive::MutexLockRecursive() : MutexLock( false )
Threading::MutexLockRecursive::MutexLockRecursive() : Mutex( false )
{
if( _InterlockedIncrement( &_attr_refcount ) == 1 )
{
@ -88,7 +88,7 @@ Threading::MutexLockRecursive::~MutexLockRecursive() throw()
// the application to survive unexpected or inconvenient failures, where a mutex is deadlocked by
// a rogue thread. This function allows us to Recreate the mutex and let the deadlocked one ponder
// the deeper meanings of the universe for eternity.
void Threading::MutexLock::Recreate()
void Threading::Mutex::Recreate()
{
Detach();
pthread_mutex_init( &m_mutex, NULL );
@ -97,7 +97,7 @@ void Threading::MutexLock::Recreate()
// Returns:
// true if the mutex had to be recreated due to lock contention, or false if the mutex is safely
// unlocked.
bool Threading::MutexLock::RecreateIfLocked()
bool Threading::Mutex::RecreateIfLocked()
{
if( !Wait(def_deadlock_timeout) )
{
@ -108,81 +108,85 @@ bool Threading::MutexLock::RecreateIfLocked()
}
void Threading::MutexLock::LockRaw()
// This is a direct blocking action -- very fast, very efficient, and generally very dangerous
// if used from the main GUI thread, since it typically results in an unresponsive program.
// Call this method directly only if you know the code in question will be run from threads
// other than the main thread.
void Threading::Mutex::FullBlockingAquire()
{
pthread_mutex_lock( &m_mutex );
}
bool Threading::MutexLock::LockRaw( const wxTimeSpan& timeout )
bool Threading::Mutex::FullBlockingAquire( const wxTimeSpan& timeout )
{
wxDateTime megafail( wxDateTime::UNow() + timeout );
const timespec fail = { megafail.GetTicks(), megafail.GetMillisecond() * 1000000 };
return pthread_mutex_timedlock( &m_mutex, &fail ) == 0;
}
void Threading::MutexLock::Unlock()
void Threading::Mutex::Release()
{
pthread_mutex_unlock( &m_mutex );
}
bool Threading::MutexLock::TryLock()
bool Threading::Mutex::TryAquire()
{
return EBUSY != pthread_mutex_trylock( &m_mutex );
}
// This is a wxApp-safe rendition of LockRaw, which makes sure to execute pending app events
// This is a wxApp-safe rendition of FullBlockingAquire, which makes sure to execute pending app events
// and messages *if* the lock is performed from the main GUI thread.
//
// Exceptions:
// ThreadTimedOut - See description of ThreadTimedOut for details
//
void Threading::MutexLock::Lock()
void Threading::Mutex::Aquire()
{
#if wxUSE_GUI
if( !wxThread::IsMain() || (wxTheApp == NULL) )
{
LockRaw();
FullBlockingAquire();
}
else if( _WaitGui_RecursionGuard( "Mutex::Lock" ) )
else if( _WaitGui_RecursionGuard( "Mutex::Aquire" ) )
{
if( !LockRaw(def_deadlock_timeout) )
if( !FullBlockingAquire(def_deadlock_timeout) )
throw Exception::ThreadTimedOut();
}
else
{
while( !LockRaw(def_yieldgui_interval) )
while( !FullBlockingAquire(def_yieldgui_interval) )
wxTheApp->Yield( true );
}
#else
LockRaw();
FullBlockingAquire();
#endif
}
// Exceptions:
// ThreadTimedOut - See description of ThreadTimedOut for details
//
bool Threading::MutexLock::Lock( const wxTimeSpan& timeout )
bool Threading::Mutex::Aquire( const wxTimeSpan& timeout )
{
#if wxUSE_GUI
if( !wxThread::IsMain() || (wxTheApp == NULL) )
{
return LockRaw(timeout);
return FullBlockingAquire(timeout);
}
else if( _WaitGui_RecursionGuard( "Mutex::Lock(timeout)" ) )
else if( _WaitGui_RecursionGuard( "Mutex::Aquire(timeout)" ) )
{
if( timeout > def_deadlock_timeout )
{
if( LockRaw(def_deadlock_timeout) ) return true;
if( FullBlockingAquire(def_deadlock_timeout) ) return true;
throw Exception::ThreadTimedOut();
}
return LockRaw( timeout );
return FullBlockingAquire( timeout );
}
else
{
wxTimeSpan countdown( (timeout) );
do {
if( LockRaw( def_yieldgui_interval ) ) break;
if( FullBlockingAquire( def_yieldgui_interval ) ) break;
wxTheApp->Yield(true);
countdown -= def_yieldgui_interval;
} while( countdown.GetMilliseconds() > 0 );
@ -194,7 +198,7 @@ bool Threading::MutexLock::Lock( const wxTimeSpan& timeout )
throw Exception::ThreadTimedOut();
#else
return LockRaw();
return FullBlockingAquire();
#endif
}
@ -203,19 +207,19 @@ bool Threading::MutexLock::Lock( const wxTimeSpan& timeout )
// specific task, and to block until the task is finished (PersistentThread uses it to
// determine if the thread is running or completed, for example).
//
// Implemented internally as a simple Lock/Unlock pair.
// Implemented internally as a simple Aquire/Release pair.
//
// Exceptions:
// ThreadTimedOut - See description of ThreadTimedOut for details
//
void Threading::MutexLock::Wait()
void Threading::Mutex::Wait()
{
Lock();
Unlock();
Aquire();
Release();
}
// Performs a wait on a locked mutex, or returns instantly if the mutex is unlocked.
// (Implemented internally as a simple Lock/Unlock pair.)
// (Implemented internally as a simple Aquire/Release pair.)
//
// Returns:
// true if the mutex was freed and is in an unlocked state; or false if the wait timed out
@ -224,11 +228,11 @@ void Threading::MutexLock::Wait()
// Exceptions:
// ThreadTimedOut - See description of ThreadTimedOut for details
//
bool Threading::MutexLock::Wait( const wxTimeSpan& timeout )
bool Threading::Mutex::Wait( const wxTimeSpan& timeout )
{
if( Lock(timeout) )
if( Aquire(timeout) )
{
Unlock();
Release();
return true;
}
return false;

View File

@ -114,7 +114,7 @@ Threading::PersistentThread::~PersistentThread() throw()
DESTRUCTOR_CATCHALL
}
void Threading::PersistentThread::FrankenMutex( MutexLock& mutex )
void Threading::PersistentThread::FrankenMutex( Mutex& mutex )
{
if( mutex.RecreateIfLocked() )
{
@ -268,7 +268,7 @@ void Threading::PersistentThread::WaitOnSelf( Semaphore& sem )
// Exceptions:
// ThreadTimedOut
//
void Threading::PersistentThread::WaitOnSelf( MutexLock& mutex )
void Threading::PersistentThread::WaitOnSelf( Mutex& mutex )
{
if( !pxAssertDev( !IsSelf(), "WaitOnSelf called from inside the thread (invalid operation!)" ) ) return;
@ -369,7 +369,7 @@ void Threading::PersistentThread::_ThreadCleanup()
_try_virtual_invoke( &PersistentThread::OnCleanupInThread );
m_lock_InThread.Unlock();
m_lock_InThread.Release();
}
wxString Threading::PersistentThread::GetName() const
@ -390,7 +390,7 @@ void Threading::PersistentThread::OnStartInThread()
void Threading::PersistentThread::_internal_execute()
{
m_lock_InThread.Lock();
m_lock_InThread.Aquire();
OnStartInThread();
_DoSetThreadName( m_name );
@ -510,10 +510,10 @@ void Threading::BaseTaskThread::ExecuteTaskInThread()
m_sem_event.WaitRaw();
Task();
m_lock_TaskComplete.Lock();
m_lock_TaskComplete.Aquire();
m_TaskPending = false;
m_post_TaskComplete.Post();
m_lock_TaskComplete.Unlock();
m_lock_TaskComplete.Release();
};
return;

View File

@ -520,11 +520,11 @@ static void cdvdDetectDisk()
void cdvdNewDiskCB()
{
if( !Mutex_NewDiskCB.TryLock() ) return;
if( !Mutex_NewDiskCB.TryAquire() ) return;
DoCDVDresetDiskTypeCache();
try { cdvdDetectDisk(); }
catch(...) { Mutex_NewDiskCB.Unlock(); } // ensure mutex gets unlocked.
catch(...) { Mutex_NewDiskCB.Release(); } // ensure mutex gets unlocked.
}
static void mechaDecryptBytes( u32 madr, int size )

View File

@ -92,7 +92,7 @@ protected:
uint m_WritePos; // cur pos ee thread is writing to
Semaphore m_sem_OpenDone;
MutexLock m_lock_RingRestart;
Mutex m_lock_RingRestart;
// used to keep multiple threads from sending packets to the ringbuffer concurrently.
MutexLockRecursive m_PacketLocker;
@ -116,7 +116,7 @@ protected:
uint m_packet_ringpos; // index of the data location in the ringbuffer.
#ifdef RINGBUF_DEBUG_STACK
Threading::MutexLock m_lock_Stack;
Threading::Mutex m_lock_Stack;
#endif
public:

View File

@ -272,7 +272,7 @@ void mtgsThreadObject::ExecuteTaskInThread()
pxAssert( stackpos == m_RingPos );
prevCmd = tag;
ringposStack.pop_back();
m_lock_Stack.Unlock();
m_lock_Stack.Release();
#endif
switch( tag.command )
@ -536,7 +536,7 @@ void mtgsThreadObject::SendDataPacket()
SetEvent();
}
}
//m_PacketLocker.Unlock();
//m_PacketLocker.Release();
}
int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size )
@ -561,7 +561,7 @@ static u32 ringtx_inf_s[32];
// size - size of the packet data, in smd128's
int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size )
{
//m_PacketLocker.Lock();
//m_PacketLocker.Aquire();
#ifdef PCSX2_GSRING_TX_STATS
ringtx_s += size;
@ -674,10 +674,10 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s
SpinWait();
}
m_lock_RingRestart.Lock();
m_lock_RingRestart.Aquire();
SendSimplePacket( GS_RINGTYPE_RESTART, 0, 0, 0 );
m_WritePos = writepos = 0;
m_lock_RingRestart.Unlock();
m_lock_RingRestart.Release();
SetEvent();
// stall until the read position is past the end of our incoming block,
@ -719,7 +719,7 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s
#ifdef RINGBUF_DEBUG_STACK
m_lock_Stack.Lock();
ringposStack.push_front( writepos );
m_lock_Stack.Unlock();
m_lock_Stack.Release();
#endif
// Command qword: Low word is the command, and the high word is the packet
@ -738,7 +738,7 @@ __forceinline uint mtgsThreadObject::_PrepForSimplePacket()
#ifdef RINGBUF_DEBUG_STACK
m_lock_Stack.Lock();
ringposStack.push_front( m_WritePos );
m_lock_Stack.Unlock();
m_lock_Stack.Release();
#endif
uint future_writepos = m_WritePos+1;

View File

@ -72,7 +72,7 @@ protected:
void OnStart()
{
if( !state_buffer_lock.TryLock() )
if( !state_buffer_lock.TryAquire() )
throw Exception::CancelEvent( m_name + L"request ignored: state copy buffer is already locked!" );
_parent::OnStart();
@ -429,7 +429,7 @@ void StateCopy_ThawFromMem()
void State_ThawFromMem_Blocking()
{
if( !state_buffer_lock.TryLock() )
if( !state_buffer_lock.TryAquire() )
memLoadingState( state_buffer ).FreezeAll();
state_buffer_lock.Release();

View File

@ -189,6 +189,9 @@ void SysThreadBase::Resume()
if( IsSelf() ) return;
if( m_ExecMode == ExecMode_Opened ) return;
ScopedNonblockingLock resprotect( m_ResumeProtection );
if( resprotect.Failed() ) return;
ScopedLock locker( m_ExecModeMutex );
// Implementation Note:
@ -203,9 +206,9 @@ void SysThreadBase::Resume()
case ExecMode_NoThreadYet:
{
static int __Guard = 0;
/*static int __Guard = 0;
RecursionGuard guard( __Guard );
if( guard.IsReentrant() ) return;
if( guard.IsReentrant() ) return;*/
Start();
if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) )
@ -242,7 +245,7 @@ void SysThreadBase::Resume()
void SysThreadBase::OnStartInThread()
{
m_RunningLock.Lock();
m_RunningLock.Aquire();
_parent::OnStartInThread();
m_ResumeEvent.Post();
}
@ -251,7 +254,7 @@ void SysThreadBase::OnCleanupInThread()
{
m_ExecMode = ExecMode_NoThreadYet;
_parent::OnCleanupInThread();
m_RunningLock.Unlock();
m_RunningLock.Release();
}
void SysThreadBase::OnSuspendInThread() {}
@ -281,7 +284,7 @@ void SysThreadBase::StateCheckInThread()
{
OnPauseInThread();
m_ExecMode = ExecMode_Paused;
m_RunningLock.Unlock();
m_RunningLock.Release();
}
// fallthrough...
@ -289,7 +292,7 @@ void SysThreadBase::StateCheckInThread()
while( m_ExecMode == ExecMode_Paused )
m_ResumeEvent.WaitRaw();
m_RunningLock.Lock();
m_RunningLock.Aquire();
OnResumeInThread( false );
break;
@ -298,7 +301,7 @@ void SysThreadBase::StateCheckInThread()
{
OnSuspendInThread();
m_ExecMode = ExecMode_Closed;
m_RunningLock.Unlock();
m_RunningLock.Release();
}
// fallthrough...
@ -306,7 +309,7 @@ void SysThreadBase::StateCheckInThread()
while( m_ExecMode == ExecMode_Closed )
m_ResumeEvent.WaitRaw();
m_RunningLock.Lock();
m_RunningLock.Aquire();
OnResumeInThread( true );
break;

View File

@ -99,7 +99,11 @@ protected:
// Locked whenever the thread is not in a suspended state (either closed or paused).
// Issue a Wait against this mutex for performing actions that require the thread
// to be suspended.
MutexLock m_RunningLock;
Mutex m_RunningLock;
// Protects the thread from re-entrant resume requests while dependent resources are
// being constructed.
NonblockingMutex m_ResumeProtection;
public:
explicit SysThreadBase();
@ -124,11 +128,14 @@ public:
bool IsClosed() const { return !IsOpen(); }
ExecutionMode GetExecutionMode() const { return m_ExecMode; }
MutexLock& ExecutionModeMutex() { return m_ExecModeMutex; }
Mutex& ExecutionModeMutex() { return m_ExecModeMutex; }
virtual bool Suspend( bool isBlocking = true );
virtual void Resume();
virtual bool Pause();
virtual bool AquireResumeLock() { return m_ResumeProtection.TryAquire(); }
virtual void ReleaseResumeLock() { m_ResumeProtection.Release(); }
protected:
virtual void OnStart();

View File

@ -49,6 +49,8 @@ void AppCoreThread::Resume()
// Thread control (suspend / resume) should only be performed from the main/gui thread.
if( !AllowFromMainThreadOnly() ) return;
if( m_ExecMode == ExecMode_Opened ) return;
if( m_ResumeProtection.IsLocked() ) return;
if( !pxAssert( g_plugins != NULL ) ) return;
if( sys_resume_lock > 0 )

View File

@ -447,6 +447,12 @@ static wxString _sysexec_elf_override;
static void _sendmsg_SysExecute()
{
if( !CoreThread.AquireResumeLock() )
{
DbgCon.WriteLn( "(SysExecute) another resume lock or message is already pending; no message posted." );
return;
}
wxCommandEvent execevt( pxEVT_SysExecute );
execevt.SetInt( _sysexec_cdvdsrc_type );
wxGetApp().AddPendingEvent( execevt );
@ -464,6 +470,7 @@ void Pcsx2App::SysExecute()
{
_sysexec_cdvdsrc_type = -1;
_sysexec_elf_override = CoreThread.GetElfOverride();
if( !m_CorePlugins )
{
LoadPluginsPassive( OnSysExecuteAfterPlugins );
@ -488,6 +495,9 @@ void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override
_sendmsg_SysExecute();
}
// This message performs actual system execution (as dictated by SysExecute variants).
// It is implemented as a message handler so that it can be triggered in response to
// the completion of other dependent activites, namely loading plugins.
void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
{
if( sys_resume_lock > 0 )
@ -502,10 +512,13 @@ void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
if( evt.GetInt() != -1 ) CoreThread.Reset(); else CoreThread.Suspend();
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
if( evt.GetInt() != -1 ) CDVDsys_ChangeSource( (CDVD_SourceType)evt.GetInt() );
if( evt.GetInt() != -1 || (CDVD == NULL) )
CDVDsys_ChangeSource( (CDVD_SourceType)evt.GetInt() );
if( !CoreThread.HasValidState() )
CoreThread.SetElfOverride( _sysexec_elf_override );
CoreThread.ReleaseResumeLock();
CoreThread.Resume();
}

View File

@ -364,13 +364,13 @@ void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
if( m_pendingFlushes > 32 && !wxThread::IsMain() )
{
++m_WaitingThreadsForFlush;
lock.Unlock();
lock.Release();
if( !m_sem_QueueFlushed.Wait( wxTimeSpan( 0,0,0,500 ) ) )
{
// Necessary since the main thread could grab the lock and process before
// the above function actually returns (gotta love threading!)
lock.Lock();
lock.Aquire();
if( m_WaitingThreadsForFlush != 0 ) --m_WaitingThreadsForFlush;
}
else

View File

@ -215,7 +215,7 @@ void __evt_fastcall MainEmuFrame::OnCorePluginStatusChanged( void* obj, PluginEv
MainEmuFrame& mframe = *(MainEmuFrame*)obj;
if( !pxAssertMsg( mframe.GetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return;
mframe.ApplyCoreStatus();
//mframe.ApplyCoreStatus();
mframe.ApplyPluginStatus();
}
@ -350,9 +350,6 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
m_menuBoot.Append(MenuId_Boot_ELF, _("Run ELF File..."),
_("For running raw binaries"));
wxMenu* recentRunMenu = new wxMenu();
m_menuBoot.Append(MenuId_Boot_Recent, _("Run Recent"), recentRunMenu);
m_menuBoot.AppendSeparator();
m_menuBoot.Append(MenuId_Exit, _("Exit"),
_("Closing PCSX2 may be hazardous to your health"));
@ -554,7 +551,7 @@ void PerPluginMenuInfo::Populate( PluginsEnum_t pid )
// Populate options from the plugin here.
MyMenu.Append( GetPluginMenuId_Settings(PluginId), _("Plugin Settings..."),
wxsFormat( _("Opens the %s plugin's advanced settings dialog."), tbl_PluginInfo[pid].GetShortname() )
wxsFormat( _("Opens the %s plugin's advanced settings dialog."), tbl_PluginInfo[pid].GetShortname().c_str() )
);
}