diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h index 59c67314cc..af9c29cb2b 100644 --- a/common/include/Utilities/Threading.h +++ b/common/include/Utilities/Threading.h @@ -99,19 +99,32 @@ namespace Threading int Count(); }; - struct MutexLock + class MutexLock { + protected: pthread_mutex_t mutex; + public: MutexLock(); - MutexLock( bool isRecursive ); - ~MutexLock(); + virtual ~MutexLock() throw(); void Lock(); void Unlock(); bool TryLock(); + + protected: + // empty constructor used by MutexLockRecursive + MutexLock( bool ) {} }; + class MutexLockRecursive : public MutexLock + { + public: + MutexLockRecursive(); + virtual ~MutexLockRecursive() throw(); + }; + + // Returns the number of available logical CPUs (cores plus hyperthreaded cpus) extern void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU ); @@ -187,7 +200,7 @@ namespace Threading pthread_t m_thread; Semaphore m_sem_event; // general wait event that's needed by most threads. Semaphore m_sem_finished; // used for canceling and closing threads in a deadlock-safe manner - MutexLock m_lock_start; // used to lock the Start() code from starting simultaneous threads accidentally. + 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 volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc. diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index d2a87f4297..8e04ad75a4 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -48,7 +48,7 @@ namespace Threading , m_thread() , m_sem_event() , m_sem_finished() - , m_lock_start( true ) // recursive mutexing! + , m_lock_start() , m_detached( true ) // start out with m_thread in detached/invalid state , m_running( false ) { @@ -572,31 +572,34 @@ namespace Threading err = pthread_mutex_init( &mutex, NULL ); } - MutexLock::MutexLock( bool isRecursive ) - { - if( isRecursive ) - { - pthread_mutexattr_t mutexAttribute; - int status = pthread_mutexattr_init( &mutexAttribute ); - if (status != 0) { /* ... */ } - status = pthread_mutexattr_settype( &mutexAttribute, PTHREAD_MUTEX_RECURSIVE); - if (status != 0) { /* ... */} - - int err = 0; - err = pthread_mutex_init( &mutex, &mutexAttribute ); - } - else - { - int err = 0; - err = pthread_mutex_init( &mutex, NULL ); - } - } - - MutexLock::~MutexLock() + MutexLock::~MutexLock() throw() { pthread_mutex_destroy( &mutex ); } + static long _attr_refcount = 0; + static pthread_mutexattr_t _attr_recursive; + + MutexLockRecursive::MutexLockRecursive() : MutexLock( false ) + { + if( _InterlockedIncrement( &_attr_refcount ) == 1 ) + { + if( 0 != pthread_mutexattr_init( &_attr_recursive ) ) + throw Exception::OutOfMemory( "Out of memory error initializing the Mutex attributes for recursive mutexing." ); + + pthread_mutexattr_settype( &_attr_recursive, PTHREAD_MUTEX_RECURSIVE ); + } + + int err = 0; + err = pthread_mutex_init( &mutex, &_attr_recursive ); + } + + MutexLockRecursive::~MutexLockRecursive() throw() + { + if( _InterlockedDecrement( &_attr_refcount ) == 0 ) + pthread_mutexattr_destroy( &_attr_recursive ); + } + void MutexLock::Lock() { pthread_mutex_lock( &mutex ); diff --git a/pcsx2/GS.h b/pcsx2/GS.h index e9f4277a51..45f903be73 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -95,7 +95,7 @@ protected: MutexLock m_lock_RingRestart; // used to keep multiple threads from sending packets to the ringbuffer concurrently. - MutexLock m_PacketLocker; + MutexLockRecursive m_PacketLocker; // Used to delay the sending of events. Performance is better if the ringbuffer // has more than one command in it when the thread is kicked. diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 2666904251..1a65bdb9ee 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -94,7 +94,7 @@ mtgsThreadObject::mtgsThreadObject() : , m_WritePos( 0 ) , m_lock_RingRestart() -, m_PacketLocker( true ) // true - makes it a recursive lock +, m_PacketLocker() , m_CopyCommandTally( 0 ) , m_CopyDataTally( 0 ) diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index 1e98a3c803..416b9253af 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -378,3 +378,27 @@ Pcsx2App::~Pcsx2App() emuLog = NULL; } } +// ------------------------------------------------------------------------------------------ +// Using the MSVCRT to track memory leaks: +// ------------------------------------------------------------------------------------------ +// When exiting PCSX2 normally, the CRT will make a list of all memory that's leaked. The +// number inside {} can be pasted into the line below to cause MSVC to breakpoint on that +// allocation at the time it's made. And then using a stacktrace you can figure out what +// leaked! :D +// +// Limitations: Unfortunately, wxWidgets gui uses a lot of heap allocations while handling +// messages, and so any mouse movements will pretty much screw up the leak value. So to use +// this feature you need to execute pcsx in no-gui mode, and then not move the mouse or use +// the keyboard until you get to the leak. >_< +// +// (but this tool is still still better than nothing!) +struct CrtDebugBreak +{ + CrtDebugBreak( int spot ) + { + _CrtSetBreakAlloc( spot ); + } +}; + +//CrtDebugBreak breakAt( 157 ); + diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index b1259fa82f..f6d74a73fd 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -816,10 +816,6 @@ RelativePath="..\..\Vif.h" > - - @@ -828,6 +824,10 @@ RelativePath="..\..\Vif1Dma.cpp" > + + diff --git a/pcsx2_suite_2008.sln b/pcsx2_suite_2008.sln index 9680e84acd..db547687e8 100644 --- a/pcsx2_suite_2008.sln +++ b/pcsx2_suite_2008.sln @@ -215,8 +215,8 @@ Global {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release SSSE3|Win32.ActiveCfg = Release|Win32 {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release SSSE3|Win32.Build.0 = Release|Win32 {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release SSSE3|x64.ActiveCfg = Release|Win32 - {18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.ActiveCfg = Debug SSE4|Win32 - {18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.Build.0 = Debug SSE4|Win32 + {18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.ActiveCfg = Debug SSE2|Win32 + {18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.Build.0 = Debug SSE2|Win32 {18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|x64.ActiveCfg = Debug|Win32 {18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Devel|Win32.ActiveCfg = Release SSE2|Win32 {18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Devel|Win32.Build.0 = Release SSE2|Win32