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]