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