mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
655038be45
commit
bc2aa38aa1
|
@ -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 )
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() )
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue