diff --git a/common/build/Utilities/Utilities.cbp b/common/build/Utilities/Utilities.cbp
index 78afe01da4..0e98cfa9e5 100644
--- a/common/build/Utilities/Utilities.cbp
+++ b/common/build/Utilities/Utilities.cbp
@@ -66,8 +66,8 @@
+
-
diff --git a/common/build/x86emitter/x86emitter.cbp b/common/build/x86emitter/x86emitter.cbp
index 7ff25bc070..001f582789 100644
--- a/common/build/x86emitter/x86emitter.cbp
+++ b/common/build/x86emitter/x86emitter.cbp
@@ -67,8 +67,8 @@
+
-
diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h
index 9c18e7f7fb..5c767d876f 100644
--- a/common/include/Utilities/Threading.h
+++ b/common/include/Utilities/Threading.h
@@ -1,6 +1,6 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
- *
+ *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see .
*/
-
+
#pragma once
#include
@@ -62,7 +62,7 @@ namespace Threading
// --------------------------------------------------------------------------------------
// 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 );
@@ -146,6 +146,7 @@ namespace Threading
void WaitRaw();
bool WaitRaw( const wxTimeSpan& timeout );
void WaitNoCancel();
+ void WaitNoCancel( const wxTimeSpan& timeout );
int Count();
void Wait();
@@ -161,7 +162,7 @@ namespace Threading
MutexLock();
virtual ~MutexLock() throw();
virtual bool IsRecursive() const { return false; }
-
+
void Recreate();
bool RecreateIfLocked();
void Detach();
@@ -173,10 +174,10 @@ namespace Threading
void LockRaw();
bool LockRaw( const wxTimeSpan& timeout );
-
+
void Wait();
bool Wait( const wxTimeSpan& timeout );
-
+
protected:
// empty constructor used by MutexLockRecursive
MutexLock( bool ) {}
@@ -217,7 +218,7 @@ namespace Threading
// --------------------------------------------------------------------------------------
// PersistentThread - Helper class for the basics of starting/managing persistent threads.
// --------------------------------------------------------------------------------------
-// This class is meant to be a helper for the typical threading model of "start once and
+// This class is meant to be a helper for the typical threading model of "start once and
// reuse many times." This class incorporates a lot of extra overhead in stopping and
// starting threads, but in turn provides most of the basic thread-safety and event-handling
// functionality needed for a threaded operation. In practice this model is usually an
@@ -230,7 +231,7 @@ namespace Threading
// void OnStart();
// void ExecuteTaskInThread();
// void OnCleanupInThread();
-//
+//
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
// m_sem_event internally to post/receive events for the thread (make a public accessor for
// it in your derived class if your thread utilizes the post).
@@ -247,14 +248,14 @@ namespace Threading
protected:
typedef int (*PlainJoeFP)();
-
+
wxString m_name; // diagnostic name for our thread.
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
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.
@@ -285,7 +286,7 @@ namespace Threading
// Start() once necessary locks have been obtained. Do not override Start() directly
// unless you're really sure that's what you need to do. ;)
virtual void OnStart();
-
+
virtual void OnStartInThread();
// This is called when the thread has been canceled or exits normally. The PersistentThread
@@ -327,7 +328,7 @@ namespace Threading
static void* _internal_callback( void* func );
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
@@ -370,7 +371,7 @@ namespace Threading
m_lock.Lock();
m_IsLocked = true;
}
-
+
bool IsLocked() const { return m_IsLocked; }
protected:
@@ -380,9 +381,9 @@ namespace Threading
, m_IsLocked( isTryLock ? m_lock.TryLock() : false )
{
}
-
+
};
-
+
class ScopedTryLock : public ScopedLock
{
public:
diff --git a/common/src/Utilities/Semaphore.cpp b/common/src/Utilities/Semaphore.cpp
index 7ac071a4a7..d25fc86d64 100644
--- a/common/src/Utilities/Semaphore.cpp
+++ b/common/src/Utilities/Semaphore.cpp
@@ -163,6 +163,14 @@ void Threading::Semaphore::WaitNoCancel()
pthread_setcancelstate( oldstate, NULL );
}
+void Threading::Semaphore::WaitNoCancel( const wxTimeSpan& timeout )
+{
+ int oldstate;
+ pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
+ WaitRaw( timeout );
+ pthread_setcancelstate( oldstate, NULL );
+}
+
int Threading::Semaphore::Count()
{
int retval;
diff --git a/pcsx2/Common.h b/pcsx2/Common.h
index 55ac5b74fa..8691369431 100644
--- a/pcsx2/Common.h
+++ b/pcsx2/Common.h
@@ -42,25 +42,3 @@
extern void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR);
extern u32 g_sseVUMXCSR, g_sseMXCSR;
-
-// SEH - "Built in" Structed Exception Handling support.
-// This should be available on Windows, via Microsoft or Intel compilers (I'm pretty sure Intel
-// supports native SEH model). GUNC in Windows, or any compiler in a non-windows platform, will
-// ned to use setjmp/longjmp instead to exit recompiled code.
-//
-#if defined(_WIN32) && !defined(__GNUG__)
-# define PCSX2_SEH
-#endif
-
-#ifndef PCSX2_SEH
-# include
-
- enum
- {
- SetJmp_Dispatcher = 1,
- SetJmp_Exit,
- };
-
- extern __threadlocal jmp_buf SetJmp_RecExecute;
- extern __threadlocal jmp_buf SetJmp_StateCheck;
-#endif
diff --git a/pcsx2/Linux/LnxHostSys.cpp b/pcsx2/Linux/LnxHostSys.cpp
index 2fa05e5406..aaa13173ae 100644
--- a/pcsx2/Linux/LnxHostSys.cpp
+++ b/pcsx2/Linux/LnxHostSys.cpp
@@ -44,15 +44,15 @@ void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * )
// get bad virtual address
uptr offset = (u8*)info->si_addr - psM;
- DevCon.Status( "Protected memory cleanup. Offset 0x%x", offset );
-
if (offset>=Ps2MemSize::Base)
{
// Bad mojo! Completely invalid address.
// Instigate a crash or abort emulation or something.
wxTrap();
- return;
+ if( !IsDebugBuild )
+ raise( SIGKILL );
}
+ DevCon.Status( "Protected memory cleanup. Offset 0x%x", offset );
mmap_ClearCpuBlock( offset & ~m_pagemask );
}
diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp
index 4a871a96ea..caa497e2c0 100644
--- a/pcsx2/Linux/pcsx2.cbp
+++ b/pcsx2/Linux/pcsx2.cbp
@@ -96,8 +96,8 @@
+
-
diff --git a/pcsx2/System.h b/pcsx2/System.h
index 549cea2563..21241154fe 100644
--- a/pcsx2/System.h
+++ b/pcsx2/System.h
@@ -1,6 +1,6 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
- *
+ *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
@@ -61,8 +61,9 @@ extern void SysClearExecutionCache(); // clears recompiled execution caches!
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
extern void vSyncDebugStuff( uint frame );
-//////////////////////////////////////////////////////////////////////////////////////////
-//
+// --------------------------------------------------------------------------------------
+// Memory Protection (Used by VTLB, Recompilers, and Texture caches)
+// --------------------------------------------------------------------------------------
#ifdef __LINUX__
# include
@@ -87,6 +88,33 @@ extern void vSyncDebugStuff( uint frame );
# error PCSX2 - Unsupported operating system platform.
#endif
+// --------------------------------------------------------------------------------------
+// PCSX2_SEH - Defines existence of "built in" Structed Exception Handling support.
+// --------------------------------------------------------------------------------------
+// This should be available on Windows, via Microsoft or Intel compilers (I'm pretty sure Intel
+// supports native SEH model). GNUC in Windows, or any compiler in a non-windows platform, will
+// need to use setjmp/longjmp instead to exit recompiled code.
+//
+#if defined(_WIN32) && !defined(__GNUC__)
+# define PCSX2_SEH
+#else
+
+# include
+
+ // Platforms without SEH need to use SetJmp / LongJmp to deal with exiting the recompiled
+ // code execution pipelines in an efficient manner, since standard C++ exceptions cannot
+ // unwind across dynamically recompiled code.
+
+ enum
+ {
+ SetJmp_Dispatcher = 1,
+ SetJmp_Exit,
+ };
+
+ extern jmp_buf SetJmp_RecExecute;
+ extern jmp_buf SetJmp_StateCheck;
+#endif
+
class pxMessageBoxEvent;
//////////////////////////////////////////////////////////////////////////////////////////
diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp
index a2bb5058b7..a1be4832ac 100644
--- a/pcsx2/gui/ConsoleLogger.cpp
+++ b/pcsx2/gui/ConsoleLogger.cpp
@@ -242,7 +242,7 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
{
m_TextCtrl.SetBackgroundColour( wxColor( 230, 235, 242 ) );
m_TextCtrl.SetDefaultStyle( m_ColorTable[DefaultConsoleColor] );
-
+
// create Log menu (contains most options)
wxMenuBar *pMenuBar = new wxMenuBar();
wxMenu& menuLog = *new wxMenu();
@@ -312,9 +312,7 @@ int m_pendingFlushes = 0;
// and this one will magically follow suite. :)
void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
{
-//#ifdef PCSX2_SEH
pthread_testcancel();
-//#endif
ScopedLock lock( m_QueueLock );
@@ -324,7 +322,7 @@ void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
}
if( (m_QueueColorSection.GetLength() == 0) || ((color != Color_Current) && (m_QueueColorSection.GetLast().color != color)) )
- {
+ {
++m_CurQueuePos; // Don't overwrite the NULL;
m_QueueColorSection.Add( ColorSection(color, m_CurQueuePos) );
}
@@ -333,10 +331,10 @@ void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
m_QueueBuffer.MakeRoomFor( endpos + 1 ); // and the null!!
memcpy_fast( &m_QueueBuffer[m_CurQueuePos], text.c_str(), sizeof(wxChar) * text.Length() );
m_CurQueuePos = endpos;
-
+
// this NULL may be overwritten if the next message sent doesn't perform a color change.
m_QueueBuffer[m_CurQueuePos] = 0;
-
+
// Idle events don't always pass (wx blocks them when moving windows or using menus, for
// example). So let's hackfix it so that an alternate message is posted if the queue is
// "piling up."
@@ -355,7 +353,7 @@ void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
++m_WaitingThreadsForFlush;
lock.Unlock();
- if( !m_sem_QueueFlushed.WaitRaw( wxTimeSpan( 0,0,0,500 ) ) )
+ 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!)
@@ -528,7 +526,7 @@ void ConsoleLogFrame::OnFlushEvent( wxCommandEvent& evt )
// the textctrl has focus or not. The wxWidgets AppendText() function uses EM_LINESCROLL
// instead, which tends to be much faster for high-volume logs, but also ends up refreshing
// the console in sloppy fashion for normal logging.
-
+
// (both are needed, the WM_VSCROLL makes the scrolling smooth, and the EM_LINESCROLL avoids
// weird errors when the buffer reaches "max" and starts clearing old history)
diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp
index 20234ac92e..3d26cc93d6 100644
--- a/pcsx2/x86/iR3000A.cpp
+++ b/pcsx2/x86/iR3000A.cpp
@@ -241,13 +241,19 @@ static DynGenFunc* _DynGen_DispatcherReg()
#endif
// Set to 0 for a speedup in release builds.
+// [doesn't apply to GCC/Mac, which must always align]
#define PCSX2_IOP_FORCED_ALIGN_STACK 0 //1
+
+// For overriding stackframe generation options in Debug builds (possibly useful for troubleshooting)
+// Typically this value should be the same as IsDevBuild.
+static const bool GenerateStackFrame = IsDevBuild;
+
static DynGenFunc* _DynGen_EnterRecompiledCode()
{
u8* retval = xGetPtr();
- bool allocatedStack = IsDevBuild || PCSX2_IOP_FORCED_ALIGN_STACK;
+ bool allocatedStack = GenerateStackFrame || PCSX2_IOP_FORCED_ALIGN_STACK;
// Optimization: The IOP never uses stack-based parameter invocation, so we can avoid
// allocating any room on the stack for it (which is important since the IOP's entry
@@ -274,7 +280,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
// this is usually worthless because CALL+PUSH leaves us 8 byte aligned instead (fail). So
// we have to do the usual set of stackframe alignments and simulated callstack mess
// *regardless*.
-
+
// MSVC/Intel compilers:
// The PCSX2_IOP_FORCED_ALIGN_STACK setting is 0, so we don't care. Just push regs like
// the good old days! (stack alignment will be indeterminate)
@@ -284,13 +290,12 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
xPUSH( ebx );
allocatedStack = false;
- CannotUseCallBecauseItWillUnalignTheGodDamnedStack = !!PCSX2_ASSUME_ALIGNED_STACK;
}
uptr* imm = NULL;
if( allocatedStack )
{
- if( IsDevBuild )
+ if( GenerateStackFrame )
{
// Simulate a CALL function by pushing the call address and EBP onto the stack.
// This retains proper stacktrace and stack unwinding (handy in devbuilds!)
@@ -301,12 +306,15 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
// This part simulates the "normal" stackframe prep of "push ebp, mov ebp, esp"
xMOV( ptr32[esp+0x08], ebp );
xLEA( ebp, ptr32[esp+0x08] );
-
- xMOV( &s_store_esp, esp );
- xMOV( &s_store_ebp, ebp );
}
}
+ if( IsDevBuild )
+ {
+ xMOV( &s_store_esp, esp );
+ xMOV( &s_store_ebp, ebp );
+ }
+
xJMP( iopDispatcherReg );
if( imm != NULL )
*imm = (uptr)xGetPtr();
@@ -319,7 +327,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
if( allocatedStack )
{
// pop the nested "simulated call" stackframe, if needed:
- if( IsDevBuild ) xLEAVE();
+ if( GenerateStackFrame ) xLEAVE();
xMOV( edi, ptr[ebp-12] );
xMOV( esi, ptr[ebp-8] );
xMOV( ebx, ptr[ebp-4] );
@@ -859,22 +867,22 @@ static __noinline s32 recExecuteBlock( s32 eeCycles )
// Register freezing note:
// The IOP does not use mmx/xmm registers, so we don't modify the status
// of the g_EEFreezeRegs here.
-
+
// [TODO] recExecuteBlock could be replaced by a direct call to the iopEnterRecompiledCode()
// (by assigning its address to the psxRec structure). But for that to happen, we need
// to move psxBreak/psxCycleEE update code to emitted assembly code. >_< --air
// Likely Disasm, as borrowed from MSVC:
-
+
// Entry:
-// mov eax,dword ptr [esp+4]
-// mov dword ptr [psxBreak (0E88DCCh)],0
-// mov dword ptr [psxCycleEE (832A84h)],eax
+// mov eax,dword ptr [esp+4]
+// mov dword ptr [psxBreak (0E88DCCh)],0
+// mov dword ptr [psxCycleEE (832A84h)],eax
// Exit:
-// mov ecx,dword ptr [psxBreak (0E88DCCh)]
-// mov edx,dword ptr [psxCycleEE (832A84h)]
-// lea eax,[edx+ecx]
+// mov ecx,dword ptr [psxBreak (0E88DCCh)]
+// mov edx,dword ptr [psxCycleEE (832A84h)]
+// lea eax,[edx+ecx]
iopEnterRecompiledCode();
diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp
index 6026bf9595..2201e6d479 100644
--- a/pcsx2/x86/ix86-32/iR5900-32.cpp
+++ b/pcsx2/x86/ix86-32/iR5900-32.cpp
@@ -684,8 +684,17 @@ static void StateThreadCheck_LongJmp()
{
setjmp( SetJmp_StateCheck );
+ int oldstate;
+
+ // Important! Most of the console logging and such has cancel points in it. This is great
+ // in Windows, where SEH lets us safely kill a thread from anywhere we want. This is bad
+ // in Linux, which cannot have a C++ exception cross the recompiler. Hence the changing
+ // of the cancelstate here!
+
+ pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
mtgsThread.RethrowException();
SysCoreThread::Get().StateCheckInThread();
+ pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
}
static void recExecute()
@@ -847,17 +856,17 @@ void recClear(u32 addr, u32 size)
}
-#ifdef __GNUG__
-__threadlocal jmp_buf SetJmp_RecExecute;
-__threadlocal jmp_buf SetJmp_StateCheck;
+#ifndef PCSX2_SEH
+ jmp_buf SetJmp_RecExecute;
+ jmp_buf SetJmp_StateCheck;
#endif
static void ExitRec()
{
-#ifdef __GNUG__
- longjmp( SetJmp_RecExecute, SetJmp_Exit );
-#else
+#ifdef PCSX2_SEH
throw Exception::ExitRecExecute();
+#else
+ longjmp( SetJmp_RecExecute, SetJmp_Exit );
#endif
}
@@ -1085,7 +1094,7 @@ static u32 eeScaleBlockCycles()
static void iBranchTest(u32 newpc)
{
_DynGen_StackFrameCheck();
-
+
if( g_ExecBiosHack ) CheckForBIOSEnd();
// Check the Event scheduler if our "cycle target" has been reached.
@@ -1313,7 +1322,7 @@ void __fastcall dyna_block_discard(u32 start,u32 sz)
recClear(start, sz);
// Stack trick: This function was invoked via a direct jmp, so manually pop the
- // EBP/stackframe before issuing a RET, else esp/ebp will be incorrect.
+ // EBP/stackframe before issuing a RET, else esp/ebp will be incorrect.
#ifdef _MSC_VER
__asm leave __asm jmp [ExitRecompiledCode]