Settings work again!

* Switched the SysCoreThread to a static (fully persistent) thread.
 * Added some listeners for when the CoreThread status changes
 * fixed some slowness in savestates, and the emu will now stall until savestates complete, if you try to exit too quick (avoids savestate corruption)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1993 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-10-09 15:17:53 +00:00
parent 2a69c92067
commit e8e61a5cf8
37 changed files with 480 additions and 355 deletions

View File

@ -83,20 +83,24 @@ public:
virtual inline void Add( const ListenerType& listener );
virtual inline void RemoveObject( const void* object );
Handle Add( void* objhandle, typename ListenerType::FuncType* fnptr )
void Add( void* objhandle, typename ListenerType::FuncType* fnptr )
{
return Add( Handle( objhandle, fnptr ) );
Add( ListenerType( objhandle, fnptr ) );
}
void Remove( void* objhandle, typename ListenerType::FuncType* fnptr )
{
Remove( Handle( objhandle, fnptr ) );
Remove( ListenerType( objhandle, fnptr ) );
}
void Dispatch( const wxCommandEvent& evt ) const
void Dispatch( const EvtType& evt ) const
{
Handle iter = m_listeners.begin();
while( iter != m_listeners.end() )
// Have to make a complete copy of the list, because the event stack can change:
ListenerList list( m_listeners );
typename ListenerList::const_iterator iter = list.begin();
while( iter != list.end() )
{
try
{
@ -108,7 +112,10 @@ public:
}
catch( Exception::BaseException& ex )
{
if( IsDevBuild ) throw;
Console.Error( L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage() );
}
++iter;
}
}
};

View File

@ -175,8 +175,8 @@ namespace Threading
// To use this as a base class for your threaded procedure, overload the following virtual
// methods:
// void OnStart();
// void ExecuteTask();
// void OnThreadCleanup();
// 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
@ -229,10 +229,10 @@ 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()=0;
virtual void OnThreadCleanup()=0;
virtual void OnCleanupInThread()=0;
// Implemented by derived class to handle threading actions!
virtual void ExecuteTask()=0;
virtual void ExecuteTaskInThread()=0;
// Inserts a thread cancellation point. If the thread has received a cancel request, this
// function will throw an SEH exception designed to exit the thread (so make sure to use C++
@ -372,7 +372,7 @@ namespace Threading
// all your necessary processing work here.
virtual void Task()=0;
virtual void ExecuteTask();
virtual void ExecuteTaskInThread();
};
//////////////////////////////////////////////////////////////////////////////////////////

View File

@ -122,7 +122,7 @@ namespace Threading
// Remarks:
// Provision of non-blocking Cancel() is probably academic, since destroying a PersistentThread
// object performs a blocking Cancel regardless of if you explicitly do a non-blocking Cancel()
// prior, since the ExecuteTask() method requires a valid object state. If you really need
// prior, since the ExecuteTaskInThread() method requires a valid object state. If you really need
// fire-and-forget behavior on threads, use pthreads directly for now.
//
// This function should not be called from the owner thread.
@ -263,7 +263,7 @@ namespace Threading
}
// invoked internally when canceling or exiting the thread. Extending classes should implement
// OnThreadCleanup() to extend cleanup functionality.
// OnCleanupInThread() to extend cleanup functionality.
void PersistentThread::_ThreadCleanup()
{
pxAssertMsg( IsSelf(), "Thread affinity error." ); // only allowed from our own thread, thanks.
@ -273,7 +273,7 @@ namespace Threading
// derived class is implemented.
ScopedLock startlock( m_lock_start );
_try_virtual_invoke( &PersistentThread::OnThreadCleanup );
_try_virtual_invoke( &PersistentThread::OnCleanupInThread );
m_running = false;
m_sem_finished.Post();
@ -288,11 +288,11 @@ namespace Threading
{
m_running = true;
_DoSetThreadName( m_name );
_try_virtual_invoke( &PersistentThread::ExecuteTask );
_try_virtual_invoke( &PersistentThread::ExecuteTaskInThread );
}
void PersistentThread::OnStart() {}
void PersistentThread::OnThreadCleanup() {}
void PersistentThread::OnCleanupInThread() {}
// passed into pthread_create, and is used to dispatch the thread's object oriented
// callback function
@ -391,7 +391,7 @@ namespace Threading
m_post_TaskComplete.Reset();
}
void BaseTaskThread::ExecuteTask()
void BaseTaskThread::ExecuteTaskInThread()
{
while( !m_Done )
{

View File

@ -128,7 +128,7 @@ FILE *_cdvdOpenNVM()
fd = fopen(file.data(), "wb");
if (fd == NULL)
{
Console.Error( "\tMEC File Creation failed!" );
Console.Error( "\tNVM File Creation failed!" );
throw Exception::CreateStream( file );
}
for (int i=0; i<1024; i++) fputc(0, fd);

View File

@ -442,7 +442,7 @@ __forceinline void rcntUpdate_vSync()
if (vsyncCounter.Mode == MODE_VSYNC)
{
eeRecIsReset = false;
mtgsThread.PollStatus();
mtgsThread.RethrowException();
SysCoreThread::Get().StateCheck();
if( eeRecIsReset )
{

View File

@ -126,9 +126,7 @@ public:
mtgsThreadObject();
virtual ~mtgsThreadObject() throw();
void Start();
void OnStart();
void PollStatus();
// Waits for the GS to empty out the entire ring buffer contents.
// Used primarily for plugin startup/shutdown.
@ -167,7 +165,7 @@ protected:
// Used internally by SendSimplePacket type functions
uint _PrepForSimplePacket();
void _FinishSimplePacket( uint future_writepos );
void ExecuteTask();
void ExecuteTaskInThread();
};
extern __aligned16 mtgsThreadObject mtgsThread;

View File

@ -110,13 +110,6 @@ mtgsThreadObject::mtgsThreadObject() :
m_name = L"MTGS";
}
void mtgsThreadObject::Start()
{
_parent::Start();
m_ExecMode = ExecMode_Suspending;
SetEvent();
}
void mtgsThreadObject::OnStart()
{
gsIsOpened = false;
@ -130,12 +123,10 @@ void mtgsThreadObject::OnStart()
m_packet_size = 0;
m_packet_ringpos = 0;
_parent::OnStart();
}
m_CopyCommandTally = 0;
m_CopyDataTally = 0;
void mtgsThreadObject::PollStatus()
{
RethrowException();
_parent::OnStart();
}
mtgsThreadObject::~mtgsThreadObject() throw()
@ -244,7 +235,7 @@ void mtgsThreadObject::OpenPlugin()
GSsetGameCRC( ElfCRC, 0 );
}
void mtgsThreadObject::ExecuteTask()
void mtgsThreadObject::ExecuteTaskInThread()
{
#ifdef RINGBUF_DEBUG_STACK
PacketTagType prevCmd;
@ -444,7 +435,7 @@ void mtgsThreadObject::WaitGS()
{
pxAssertDev( !IsSelf(), "This method is only allowed from threads *not* named MTGS." );
if( IsSuspended() ) return;
if( !pxAssertDev( m_ExecMode == ExecMode_Running, "MTGS Warning! WaitGS issued on a suspended/paused thread." ) ) return;
// FIXME : Use semaphores instead of spinwaits.
SetEvent();

View File

@ -114,7 +114,7 @@ vtlbHandler tlb_fallback_8;
vtlbHandler vu0_micro_mem[2]; // 0 - dynarec, 1 - interpreter
vtlbHandler vu1_micro_mem[2]; // 0 - dynarec, 1 - interpreter
vtlbHandler hw_by_page[0x10];
vtlbHandler hw_by_page[0x10] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
vtlbHandler gs_page_0;
vtlbHandler gs_page_1;
@ -599,6 +599,19 @@ void memShutdown()
vtlb_Term();
}
void memBindConditionalHandlers()
{
if( hw_by_page[0xf] == -1 ) return;
vtlbMemR32FP* page0F32( EmuConfig.Speedhacks.IntcStat ? hwRead32_page_0F_INTC_HACK : hwRead32_page_0F );
vtlbMemR64FP* page0F64( EmuConfig.Speedhacks.IntcStat ? hwRead64_generic_INTC_HACK : hwRead64_generic );
vtlb_ReassignHandler( hw_by_page[0xf],
_ext_memRead8<1>, _ext_memRead16<1>, page0F32, page0F64, hwRead128_generic,
_ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0F, hwWrite64_generic, hwWrite128_generic
);
}
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
void memReset()
{
@ -724,13 +737,8 @@ void memReset()
_ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0E, hwWrite64_page_0E, hwWrite128_generic
);
vtlbMemR32FP* page0F32( EmuConfig.Speedhacks.IntcStat ? hwRead32_page_0F_INTC_HACK : hwRead32_page_0F );
vtlbMemR64FP* page0F64( EmuConfig.Speedhacks.IntcStat ? hwRead64_generic_INTC_HACK : hwRead64_generic );
hw_by_page[0xf] = vtlb_RegisterHandler(
_ext_memRead8<1>, _ext_memRead16<1>, page0F32, page0F64, hwRead128_generic,
_ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0F, hwWrite64_generic, hwWrite128_generic
);
hw_by_page[0xf] = vtlb_NewHandler();
memBindConditionalHandlers();
//////////////////////////////////////////////////////////////////////
// GS Optimized Mappings

View File

@ -127,6 +127,7 @@ extern void memSetSupervisorMode();
extern void memSetUserMode();
extern void memSetPageAddr(u32 vaddr, u32 paddr);
extern void memClearPageAddr(u32 vaddr);
extern void memBindConditionalHandlers();
extern void memMapVUmicro();

View File

@ -915,7 +915,7 @@ void PluginManager::Open()
} while( ++pi, pi->shortname != NULL );
if (GSopen2) mtgsThread.WaitForOpen();
mtgsThread.PollStatus();
mtgsThread.RethrowException();
Console.Status( "Plugins opened successfully." );
}

View File

@ -58,7 +58,9 @@ R5900Exception::BaseExcept::~BaseExcept() throw (){}
void cpuReset()
{
mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case.
if( mtgsThread.IsExecMode_Running() )
mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case.
cpuIsInitialized = true;
memReset();

View File

@ -20,6 +20,7 @@
#include "zlib/zlib.h"
class _BaseStateThread;
static SafeArray<u8> state_buffer;
@ -33,6 +34,12 @@ bool sys_resume_lock = false;
static FnType_OnThreadComplete* Callback_FreezeFinished = NULL;
static void StateThread_OnAppStatus( void* thr, const enum AppStatusEvent& stat )
{
if( (thr == NULL) || (stat != AppStatus_Exiting) ) return;
((PersistentThread*)thr)->Cancel();
}
enum
{
StateThreadAction_None = 0,
@ -46,6 +53,9 @@ class _BaseStateThread : public PersistentThread
{
typedef PersistentThread _parent;
protected:
EventListenerBinding<AppStatusEvent> m_bind_OnExit;
public:
virtual ~_BaseStateThread() throw()
{
@ -53,7 +63,8 @@ public:
}
protected:
_BaseStateThread( const char* name, FnType_OnThreadComplete* onFinished )
_BaseStateThread( const char* name, FnType_OnThreadComplete* onFinished ) :
m_bind_OnExit( wxGetApp().Source_AppStatus(), EventListener<AppStatusEvent>( this, StateThread_OnAppStatus ) )
{
Callback_FreezeFinished = onFinished;
m_name = L"StateThread::" + fromUTF8(name);
@ -94,18 +105,18 @@ protected:
{
_parent::OnStart();
sys_resume_lock = true;
sCoreThread.Pause();
CoreThread.Pause();
}
void ExecuteTask()
void ExecuteTaskInThread()
{
memSavingState( state_buffer ).FreezeAll();
}
void OnThreadCleanup()
void OnCleanupInThread()
{
SendFinishEvent( StateThreadAction_Create );
_parent::OnThreadCleanup();
_parent::OnCleanupInThread();
}
};
@ -131,18 +142,18 @@ protected:
}
sys_resume_lock = true;
sCoreThread.Pause();
CoreThread.Pause();
}
void ExecuteTask()
void ExecuteTaskInThread()
{
memLoadingState( state_buffer ).FreezeAll();
}
void OnThreadCleanup()
void OnCleanupInThread()
{
SendFinishEvent( StateThreadAction_Restore );
_parent::OnThreadCleanup();
_parent::OnCleanupInThread();
}
};
@ -179,17 +190,28 @@ protected:
throw Exception::CreateStream( m_filename, "Cannot create savestate file for writing." );
}
void ExecuteTask()
void ExecuteTaskInThread()
{
Yield( 2 );
if( gzwrite( (gzFile)m_gzfp, state_buffer.GetPtr(), state_buffer.GetSizeInBytes() ) < state_buffer.GetSizeInBytes() )
throw Exception::BadStream();
Yield( 3 );
//if( gzwrite( m_gzfp, state_buffer.GetPtr(), state_buffer.GetSizeInBytes() ) < state_buffer.GetSizeInBytes() )
// throw Exception::BadStream();
static const int BlockSize = 0x10000;
int curidx = 0;
do
{
int thisBlockSize = std::min( BlockSize, state_buffer.GetSizeInBytes() - curidx );
if( gzwrite( m_gzfp, state_buffer.GetPtr(curidx), thisBlockSize ) < thisBlockSize )
throw Exception::BadStream( m_filename );
curidx += BlockSize;
Yield( 1 );
} while( curidx < state_buffer.GetSizeInBytes() );
}
void OnThreadCleanup()
void OnCleanupInThread()
{
SendFinishEvent( StateThreadAction_ZipToDisk );
_parent::OnThreadCleanup();
_parent::OnCleanupInThread();
}
};
@ -233,7 +255,7 @@ protected:
throw Exception::CreateStream( m_filename, "Cannot open savestate file for reading." );
}
void ExecuteTask()
void ExecuteTaskInThread()
{
// fixme: should start initially with the file size, and then grow from there.
@ -250,10 +272,10 @@ protected:
m_finished = true;
}
void OnThreadCleanup()
void OnCleanupInThread()
{
SendFinishEvent( StateThreadAction_UnzipFromDisk );
_parent::OnThreadCleanup();
_parent::OnCleanupInThread();
}
};
@ -288,7 +310,7 @@ void OnFinished_Resume( const wxCommandEvent& evt )
SysClearExecutionCache();
}
sCoreThread.Resume();
CoreThread.Resume();
}
static wxString zip_dest_filename;
@ -304,7 +326,9 @@ void OnFinished_ZipToDisk( const wxCommandEvent& evt )
}
// Phase 2: Record to disk!!
(new StateThread_ZipToDisk( OnFinished_Resume, zip_dest_filename ))->Start();
(new StateThread_ZipToDisk( NULL, zip_dest_filename ))->Start();
CoreThread.Resume();
}
void OnFinished_Restore( const wxCommandEvent& evt )
@ -331,7 +355,7 @@ void StateCopy_SaveToFile( const wxString& file )
void StateCopy_LoadFromFile( const wxString& file )
{
if( state_buffer_lock.IsLocked() ) return;
sCoreThread.Pause();
CoreThread.Pause();
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
}
@ -341,6 +365,8 @@ void StateCopy_LoadFromFile( const wxString& file )
// the one in the memory save. :)
void StateCopy_SaveToSlot( uint num )
{
if( state_buffer_lock.IsLocked() ) return;
zip_dest_filename = SaveStateBase::GetFilename( num );
(new StateThread_Freeze( OnFinished_ZipToDisk ))->Start();
Console.Status( "Saving savestate to slot %d...", num );
@ -361,7 +387,7 @@ void StateCopy_LoadFromSlot( uint slot )
Console.Status( "Loading savestate from slot %d...", slot );
Console.Status( wxsFormat(L"\tfilename: %s", file.c_str()) );
sCoreThread.Pause();
CoreThread.Pause();
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
}
@ -392,9 +418,21 @@ void StateCopy_ThawFromMem()
new StateThread_Thaw( OnFinished_Restore );
}
void State_ThawFromMem_Blocking()
{
if( !state_buffer_lock.TryLock() )
memLoadingState( state_buffer ).FreezeAll();
state_buffer_lock.Release();
}
void StateCopy_Clear()
{
if( state_buffer_lock.IsLocked() ) return;
state_buffer.Dispose();
}
bool StateCopy_IsBusy()
{
return state_buffer_lock.IsLocked();
}

View File

@ -359,14 +359,10 @@ memSavingState::memSavingState( SafeArray<u8>& save_to ) :
// Saving of state data
void memSavingState::FreezeMem( void* data, int size )
{
const int end = m_idx+size;
m_memory.MakeRoomFor( end );
u8* dest = (u8*)m_memory.GetPtr();
const u8* src = (u8*)data;
for( ; m_idx<end; ++m_idx, ++src )
dest[m_idx] = *src;
u8* const dest = m_memory.GetPtr(m_idx);
m_idx += size;
m_memory.MakeRoomFor( m_idx );
memcpy_fast( dest, data, size );
}
memLoadingState::memLoadingState( const SafeArray<u8>& load_from ) :
@ -379,10 +375,7 @@ memLoadingState::~memLoadingState() { }
// Loading of state data
void memLoadingState::FreezeMem( void* data, int size )
{
const int end = m_idx+size;
const u8* src = (u8*)m_memory.GetPtr();
u8* dest = (u8*)data;
for( ; m_idx<end; ++m_idx, ++dest )
*dest = src[m_idx];
const u8* const src = m_memory.GetPtr(m_idx);
m_idx += size;
memcpy_fast( data, src, size );
}

View File

@ -204,4 +204,4 @@ extern void StateCopy_LoadFromFile( const wxString& file );
extern void StateCopy_SaveToSlot( uint num );
extern void StateCopy_LoadFromSlot( uint slot );
extern void StateCopy_Clear();
extern bool StateCopy_IsBusy();

View File

@ -45,6 +45,14 @@ SysSuspendableThread::~SysSuspendableThread() throw()
{
}
void SysSuspendableThread::Start()
{
_parent::Start();
m_ExecMode = ExecMode_Suspending;
m_sem_event.Post();
}
void SysSuspendableThread::OnStart()
{
if( !pxAssertDev( m_ExecMode == ExecMode_NoThreadYet, "SysSustainableThread:Start(): Invalid execution mode" ) ) return;
@ -65,51 +73,68 @@ void SysSuspendableThread::OnStart()
// is mostly useful for starting certain non-Emu related gui activities (improves gui
// responsiveness).
//
// Returns:
// The previous suspension state; true if the thread was running or false if it was
// suspended.
//
// Exceptions:
// CancelEvent - thrown if the thread is already in a Paused state. Because actions that
// pause emulation typically rely on plugins remaining loaded/active, Suspension must
// cansel itself forcefully or risk crashing whatever other action is in progress.
//
void SysSuspendableThread::Suspend( bool isBlocking )
bool SysSuspendableThread::Suspend( bool isBlocking )
{
if( IsSelf() || !IsRunning() ) return;
if( IsSelf() || !IsRunning() ) return false;
bool retval = false;
{
ScopedLock locker( m_lock_ExecMode );
if( m_ExecMode == ExecMode_Suspended )
return;
return false;
if( m_ExecMode == ExecMode_Pausing || m_ExecMode == ExecMode_Paused )
throw Exception::CancelEvent( "Another thread is pausing the VM state." );
if( m_ExecMode == ExecMode_Running )
{
m_ExecMode = ExecMode_Suspending;
retval = true;
}
pxAssertDev( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspending..." );
}
m_SuspendEvent.Reset();
m_sem_event.Post();
if( isBlocking ) m_SuspendEvent.WaitGui();
return retval;
}
void SysSuspendableThread::Pause()
bool SysSuspendableThread::Pause()
{
if( IsSelf() || !IsRunning() ) return;
if( IsSelf() || !IsRunning() ) return false;
bool retval = false;
{
ScopedLock locker( m_lock_ExecMode );
if( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused) ) return;
if( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused) ) return false;
if( m_ExecMode == ExecMode_Running )
{
m_ExecMode = ExecMode_Pausing;
retval = true;
}
pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
}
m_SuspendEvent.Reset();
m_sem_event.Post();
m_SuspendEvent.WaitGui();
return retval;
}
// Resumes the core execution state, or does nothing is the core is already running. If
@ -151,10 +176,10 @@ void SysSuspendableThread::Resume()
pxAssertDev( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused),
"SysSuspendableThread is not in a suspended/paused state? wtf!" );
m_ExecMode = ExecMode_Running;
m_ResumeProtection = true;
OnResumeReady();
m_ResumeProtection = false;
m_ExecMode = ExecMode_Running;
m_ResumeEvent.Post();
}
@ -164,11 +189,11 @@ void SysSuspendableThread::Resume()
// (Called from the context of this thread only)
// --------------------------------------------------------------------------------------
void SysSuspendableThread::OnThreadCleanup()
void SysSuspendableThread::OnCleanupInThread()
{
ScopedLock locker( m_lock_ExecMode );
m_ExecMode = ExecMode_NoThreadYet;
_parent::OnThreadCleanup();
_parent::OnCleanupInThread();
}
void SysSuspendableThread::StateCheck( bool isCancelable )
@ -244,11 +269,11 @@ void SysSuspendableThread::StateCheck( bool isCancelable )
// (Called form outside the context of this thread)
// --------------------------------------------------------------------------------------
SysCoreThread::SysCoreThread( PluginManager& plugins ) :
m_resetRecompilers( false )
, m_resetProfilers( false )
, m_shortSuspend( false )
, m_plugins( plugins )
SysCoreThread::SysCoreThread() :
m_resetRecompilers( true )
, m_resetProfilers( true )
, m_resetVirtualMachine( true )
, m_hasValidState( false )
{
m_name = L"EE Core";
}
@ -260,7 +285,8 @@ SysCoreThread::~SysCoreThread() throw()
void SysCoreThread::Start()
{
m_plugins.Init();
if( g_plugins == NULL ) return;
g_plugins->Init();
_parent::Start();
}
@ -275,16 +301,28 @@ void SysCoreThread::Start()
//
void SysCoreThread::OnResumeReady()
{
if( m_shortSuspend ) return;
if( m_resetVirtualMachine )
{
cpuReset();
m_resetVirtualMachine = false;
m_hasValidState = false;
}
if( m_resetRecompilers || m_resetProfilers )
if( m_resetRecompilers || m_resetProfilers || !m_hasValidState )
{
SysClearExecutionCache();
memBindConditionalHandlers();
m_resetRecompilers = false;
m_resetProfilers = false;
}
}
void SysCoreThread::Reset()
{
Suspend();
m_resetVirtualMachine = true;
}
// Applies a full suite of new settings, which will automatically facilitate the necessary
// resets of the core and components (including plugins, if needed). The scope of resetting
// is determined by comparing the current settings against the new settings.
@ -292,11 +330,12 @@ void SysCoreThread::ApplySettings( const Pcsx2Config& src )
{
if( src == EmuConfig ) return;
const bool resumeWhenDone = !m_ResumeProtection && !IsSuspended();
if( !m_ResumeProtection ) Suspend();
// Suspend only if ResumeProtection is false:
const bool resumeWhenDone = !m_ResumeProtection && Suspend();
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
const_cast<Pcsx2Config&>(EmuConfig) = src;
if( resumeWhenDone ) Resume();
@ -314,55 +353,44 @@ SysCoreThread& SysCoreThread::Get()
void SysCoreThread::CpuInitializeMess()
{
cpuReset();
SysClearExecutionCache();
if( StateCopy_IsValid() )
if( m_hasValidState ) return;
wxString elf_file;
if( EmuConfig.SkipBiosSplash )
{
// no need to boot bios or detect CDs when loading savestates.
// [TODO] : It might be useful to detect game SLUS/CRC and compare it against
// the savestate info, and issue a warning to the user since, chances are, they
// don't really want to run a game with the wrong ISO loaded into the emu.
StateCopy_ThawFromMem();
}
else
{
wxString elf_file;
if( EmuConfig.SkipBiosSplash )
// Fetch the ELF filename and CD type from the CDVD provider.
wxString ename;
int result = GetPS2ElfName( ename );
switch( result )
{
// Fetch the ELF filename and CD type from the CDVD provider.
wxString ename;
int result = GetPS2ElfName( ename );
switch( result )
{
case 0:
throw Exception::RuntimeError( wxLt("Fast Boot failed: CDVD image is not a PS1 or PS2 game.") );
case 0:
throw Exception::RuntimeError( wxLt("Fast Boot failed: CDVD image is not a PS1 or PS2 game.") );
case 1:
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
case 1:
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
case 2:
// PS2 game. Valid!
elf_file = ename;
break;
case 2:
// PS2 game. Valid!
elf_file = ename;
break;
jNO_DEFAULT
}
}
if( !elf_file.IsEmpty() )
{
// Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF
// executable data, and injects the cpuRegs.pc with the address of the
// execution start point.
//
// This hack is necessary for non-CD ELF files, and is optional for game CDs
// (though not recommended for games because of rare ill side effects).
cpuExecuteBios();
loadElfFile( elf_file );
jNO_DEFAULT
}
}
if( !elf_file.IsEmpty() )
{
// Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF
// executable data, and injects the cpuRegs.pc with the address of the
// execution start point.
//
// This hack is necessary for non-CD ELF files, and is optional for game CDs
// (though not recommended for games because of rare ill side effects).
cpuExecuteBios();
loadElfFile( elf_file );
}
m_hasValidState = true;
}
// special macro which disables inlining on functions that require their own function stackframe.
@ -384,33 +412,36 @@ void SysCoreThread::CpuExecute()
PCSX2_MEM_PROTECT_END();
}
void SysCoreThread::ExecuteTask()
void SysCoreThread::ExecuteTaskInThread()
{
tls_coreThread = this;
StateCheck();
CpuInitializeMess();
m_sem_event.Wait();
StateCheck();
CpuExecute();
}
void SysCoreThread::OnSuspendInThread()
{
if( !m_shortSuspend )
m_plugins.Close();
if( g_plugins == NULL ) return;
g_plugins->Close();
}
void SysCoreThread::OnResumeInThread( bool isSuspended )
{
if( isSuspended )
m_plugins.Open();
if( isSuspended && g_plugins != NULL )
{
CpuInitializeMess();
g_plugins->Open();
}
}
// Invoked by the pthread_exit or pthread_cancel
void SysCoreThread::OnThreadCleanup()
void SysCoreThread::OnCleanupInThread()
{
m_plugins.Shutdown();
_parent::OnThreadCleanup();
//if( g_plugins != NULL )
// g_plugins->Shutdown();
_parent::OnCleanupInThread();
}

View File

@ -25,8 +25,8 @@ public:
ISysThread() {}
virtual ~ISysThread() throw() {};
virtual bool IsSuspended() const { return false; }
virtual void Suspend( bool isBlocking = true ) { }
virtual bool Suspend( bool isBlocking = true ) { return false; }
virtual bool Pause() { return false; }
virtual void Resume() {}
};
@ -57,14 +57,14 @@ public:
explicit SysSuspendableThread();
virtual ~SysSuspendableThread() throw();
bool IsSuspended() const { return (m_ExecMode == ExecMode_Suspended); }
bool IsExecMode_Running() const { return m_ExecMode == ExecMode_Running; }
virtual void Suspend( bool isBlocking = true );
virtual bool Suspend( bool isBlocking = true );
virtual void Resume();
virtual void Pause();
virtual bool Pause();
virtual void StateCheck( bool isCancelable = true );
virtual void OnThreadCleanup();
virtual void OnCleanupInThread();
// This function is called by Resume immediately prior to releasing the suspension of
// the core emulation thread. You should overload this rather than Resume(), since
@ -74,7 +74,10 @@ public:
virtual void OnStart();
protected:
// Used internally from Resume(), so let's make it private here.
virtual void Start();
// Extending classes should implement this, but should not call it. The parent class
// handles invocation by the following guidelines: Called *in thread* from StateCheck()
// prior to suspending the thread (ie, when Suspend() has been called on a separate
@ -108,19 +111,24 @@ class SysCoreThread : public SysSuspendableThread
protected:
bool m_resetRecompilers;
bool m_resetProfilers;
bool m_shortSuspend;
PluginManager& m_plugins;
bool m_resetVirtualMachine;
bool m_hasValidState;
public:
static SysCoreThread& Get();
public:
explicit SysCoreThread( PluginManager& plugins );
explicit SysCoreThread();
virtual ~SysCoreThread() throw();
virtual void ApplySettings( const Pcsx2Config& src );
virtual void OnThreadCleanup();
virtual void OnResumeReady();
virtual void Reset();
bool HasValidState()
{
return m_hasValidState;
}
protected:
void CpuInitializeMess();
@ -130,5 +138,6 @@ protected:
virtual void OnSuspendInThread();
virtual void OnPauseInThread() {}
virtual void OnResumeInThread( bool IsSuspended );
virtual void ExecuteTask();
virtual void OnCleanupInThread();
virtual void ExecuteTaskInThread();
};

View File

@ -49,7 +49,7 @@ BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 )
DECLARE_EVENT_TYPE( pxEVT_SysExecute, -1 )
DECLARE_EVENT_TYPE( pxEVT_LoadPluginsComplete, -1 )
DECLARE_EVENT_TYPE( pxEVT_AppCoreThreadFinished, -1 )
DECLARE_EVENT_TYPE( pxEVT_CoreThreadStatus, -1 )
DECLARE_EVENT_TYPE( pxEVT_FreezeThreadFinished, -1 )
END_DECLARE_EVENT_TYPES()
@ -159,6 +159,12 @@ enum DialogIdentifiers
DialogId_About,
};
enum AppStatusEvent
{
// Maybe this will be expanded upon later..?
AppStatus_Exiting
};
// --------------------------------------------------------------------------------------
// KeyAcceleratorCode
// A custom keyboard accelerator that I like better than wx's wxAcceleratorEntry.
@ -324,7 +330,6 @@ protected:
public:
ScopedPtr<SysCoreAllocations> m_CoreAllocs;
ScopedPtr<PluginManager> m_CorePlugins;
ScopedPtr<SysCoreThread> m_CoreThread;
protected:
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
@ -345,7 +350,7 @@ public:
int ThreadedModalDialog( DialogIdentifiers dialogId );
void Ping() const;
bool PrepForExit();
bool PrepForExit( bool canCancel );
void SysExecute();
void SysExecute( CDVD_SourceType cdvdsrc );
@ -358,13 +363,8 @@ public:
const AppImageIds& GetImgId() const { return m_ImageId; }
MainEmuFrame& GetMainFrame() const;
SysCoreThread& GetCoreThread() const;
MainEmuFrame* GetMainFramePtr() const { return m_MainFrame; }
bool HasMainFrame() const { return m_MainFrame != NULL; }
bool HasCoreThread() const { return m_CoreThread != NULL; }
MainEmuFrame* GetMainFramePtr() const { return m_MainFrame; }
SysCoreThread* GetCoreThreadPtr() const { return m_CoreThread; }
void OpenGsFrame();
void OnGsFrameClosed();
@ -402,10 +402,12 @@ public:
protected:
CmdEvt_Source m_evtsrc_CorePluginStatus;
CmdEvt_Source m_evtsrc_CoreThreadStatus;
EventSource<AppStatusEvent> m_evtsrc_AppStatus;
public:
CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; }
CmdEvt_Source& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; }
EventSource<AppStatusEvent>& Source_AppStatus() { return m_evtsrc_AppStatus; }
protected:
void InitDefaultGlobalAccelerators();
@ -422,7 +424,7 @@ protected:
void OnLoadPluginsComplete( wxCommandEvent& evt );
void OnSemaphorePing( wxCommandEvent& evt );
void OnOpenModalDialog( wxCommandEvent& evt );
void OnCoreThreadTerminated( wxCommandEvent& evt );
void OnCoreThreadStatus( wxCommandEvent& evt );
void OnFreezeThreadFinished( wxCommandEvent& evt );
@ -449,6 +451,13 @@ protected:
// AppCoreThread class
// --------------------------------------------------------------------------------------
enum CoreThreadStatus
{
CoreStatus_Resumed,
CoreStatus_Suspended,
CoreStatus_Stopped,
};
class AppCoreThread : public SysCoreThread
{
typedef SysCoreThread _parent;
@ -457,18 +466,18 @@ protected:
wxKeyEvent m_kevt;
public:
AppCoreThread( PluginManager& plugins );
AppCoreThread();
virtual ~AppCoreThread() throw();
virtual void Suspend( bool isBlocking=true );
virtual bool Suspend( bool isBlocking=true );
virtual void Resume();
virtual void StateCheck( bool isCancelable=true );
virtual void ApplySettings( const Pcsx2Config& src );
protected:
virtual void OnResumeReady();
virtual void OnThreadCleanup();
virtual void ExecuteTask();
virtual void OnCleanupInThread();
virtual void ExecuteTaskInThread();
};
DECLARE_APP(Pcsx2App)
@ -481,8 +490,8 @@ DECLARE_APP(Pcsx2App)
// not be invoked, and an optional "else" clause cn be affixed for handling the end case.
//
// Usage Examples:
// sCoreThread.Suspend(); // Suspends the CoreThread, or does nothing if the CoreThread handle is NULL
// sCoreThread.Suspend(); else Console.WriteLn( "Judge Wapner" ); // 'else' clause for handling NULL scenarios.
// sMainFrame.ApplySettings();
// sMainFrame.ApplySettings(); else Console.WriteLn( "Judge Wapner" ); // 'else' clause for handling NULL scenarios.
//
// Note! These macros are not "syntax complete", which means they could generat unexpected
// syntax errors in some situatins, and more importantly they cannot be used for invoking
@ -497,9 +506,6 @@ DECLARE_APP(Pcsx2App)
#define sApp \
if( Pcsx2App* __app_ = (Pcsx2App*)wxApp::GetInstance() ) (*__app_)
#define sCoreThread \
if( SysCoreThread* __thread_ = GetCoreThreadPtr() ) (*__thread_)
#define sMainFrame \
if( MainEmuFrame* __frame_ = GetMainFramePtr() ) (*__frame_)
@ -523,11 +529,8 @@ extern bool SysHasValidState();
extern void SysStatus( const wxString& text );
extern bool HasMainFrame();
extern bool HasCoreThread();
extern bool HasMainFrame();
extern MainEmuFrame& GetMainFrame();
extern SysCoreThread& GetCoreThread();
extern MainEmuFrame* GetMainFramePtr();
extern SysCoreThread* GetCoreThreadPtr();
extern AppCoreThread CoreThread;

View File

@ -525,8 +525,7 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
AppLoadSettings();
AppApplySettings();
if( HasMainFrame() )
GetMainFrame().ReloadRecentLists();
sMainFrame.ReloadRecentLists();
g_Conf->Folders.Logs.Mkdir();

View File

@ -16,8 +16,9 @@
#include "PrecompiledHeader.h"
#include "MainFrame.h"
AppCoreThread::AppCoreThread( PluginManager& plugins ) :
SysCoreThread( plugins )
AppCoreThread CoreThread;
AppCoreThread::AppCoreThread() : SysCoreThread()
, m_kevt()
{
}
@ -26,11 +27,13 @@ AppCoreThread::~AppCoreThread() throw()
{
}
void AppCoreThread::Suspend( bool isBlocking )
bool AppCoreThread::Suspend( bool isBlocking )
{
_parent::Suspend( isBlocking );
if( HasMainFrame() )
GetMainFrame().ApplySettings();
bool retval = _parent::Suspend( isBlocking );
wxCommandEvent evt( pxEVT_CoreThreadStatus );
evt.SetInt( CoreStatus_Suspended );
wxGetApp().AddPendingEvent( evt );
// Clear the sticky key statuses, because hell knows what'll change while the PAD
// plugin is suspended.
@ -38,6 +41,8 @@ void AppCoreThread::Suspend( bool isBlocking )
m_kevt.m_shiftDown = false;
m_kevt.m_controlDown = false;
m_kevt.m_altDown = false;
return retval;
}
void AppCoreThread::Resume()
@ -55,26 +60,28 @@ void AppCoreThread::Resume()
void AppCoreThread::OnResumeReady()
{
if( m_shortSuspend ) return;
ApplySettings( g_Conf->EmuOptions );
if( GSopen2 != NULL )
wxGetApp().OpenGsFrame();
if( HasMainFrame() )
GetMainFrame().ApplySettings();
wxCommandEvent evt( pxEVT_CoreThreadStatus );
evt.SetInt( CoreStatus_Resumed );
wxGetApp().AddPendingEvent( evt );
_parent::OnResumeReady();
}
// Called whenever the thread has terminated, for either regular or irregular reasons.
// Typically the thread handles all its own errors, so there's no need to have error
// handling here. However it's a good idea to update the status of the GUI to reflect
// the new (lack of) thread status, so this posts a message to the App to do so.
void AppCoreThread::OnThreadCleanup()
void AppCoreThread::OnCleanupInThread()
{
wxCommandEvent evt( pxEVT_AppCoreThreadFinished );
wxCommandEvent evt( pxEVT_CoreThreadStatus );
evt.SetInt( CoreStatus_Stopped );
wxGetApp().AddPendingEvent( evt );
_parent::OnThreadCleanup();
_parent::OnCleanupInThread();
}
#ifdef __WXGTK__
@ -84,11 +91,12 @@ void AppCoreThread::OnThreadCleanup()
void AppCoreThread::StateCheck( bool isCancelable )
{
_parent::StateCheck( isCancelable );
if( !pxAssert(g_plugins!=NULL) ) return;
const keyEvent* ev = PADkeyEvent();
if( ev == NULL || (ev->key == 0) ) return;
m_plugins.KeyEvent( *ev );
g_plugins->KeyEvent( *ev );
m_kevt.SetEventType( ( ev->evt == KEYPRESS ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP );
const bool isDown = (ev->evt == KEYPRESS);
@ -116,7 +124,8 @@ void AppCoreThread::StateCheck( bool isCancelable )
// suspended. If the thread has mot been suspended, this call will fail *silently*.
void AppCoreThread::ApplySettings( const Pcsx2Config& src )
{
if( !IsSuspended() ) return;
if( m_ExecMode != ExecMode_Suspended ) return;
if( src == EmuConfig ) return;
// Re-entry guard protects against cases where code wants to manually set core settings
// which are not part of g_Conf. The subsequent call to apply g_Conf settings (which is
@ -128,19 +137,18 @@ void AppCoreThread::ApplySettings( const Pcsx2Config& src )
SysCoreThread::ApplySettings( src );
}
void AppCoreThread::ExecuteTask()
void AppCoreThread::ExecuteTaskInThread()
{
try
{
SysCoreThread::ExecuteTask();
SysCoreThread::ExecuteTaskInThread();
}
// ----------------------------------------------------------------------------
catch( Exception::FileNotFound& ex )
{
m_plugins.Close();
if( g_plugins != NULL ) g_plugins->Close();
if( ex.StreamName == g_Conf->FullpathToBios() )
{
m_plugins.Close();
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
_("\n\nPress Ok to go to the BIOS Configuration Panel.") );
@ -160,7 +168,7 @@ void AppCoreThread::ExecuteTask()
// ----------------------------------------------------------------------------
catch( Exception::PluginError& ex )
{
m_plugins.Close();
if( g_plugins != NULL ) g_plugins->Close();
Console.Error( ex.FormatDiagnosticMessage() );
Msgbox::Alert( ex.FormatDisplayMessage(), _("Plugin Open Error") );
@ -176,7 +184,7 @@ void AppCoreThread::ExecuteTask()
catch( Exception::BaseException& ex )
{
// Sent the exception back to the main gui thread?
m_plugins.Close();
if( g_plugins != NULL ) g_plugins->Close();
Msgbox::Alert( ex.FormatDisplayMessage() );
}
}

View File

@ -224,7 +224,7 @@ bool Pcsx2App::OnInit()
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
Connect( pxEVT_AppCoreThreadFinished, wxCommandEventHandler( Pcsx2App::OnCoreThreadTerminated ) );
Connect( pxEVT_CoreThreadStatus, wxCommandEventHandler( Pcsx2App::OnCoreThreadStatus ) );
Connect( pxEVT_FreezeThreadFinished, wxCommandEventHandler( Pcsx2App::OnFreezeThreadFinished ) );
Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
@ -335,11 +335,10 @@ bool Pcsx2App::OnInit()
void Pcsx2App::CleanupMess()
{
CoreThread.Cancel();
if( m_CorePlugins )
{
m_CorePlugins->Close();
m_CorePlugins->Shutdown();
}
// Notice: deleting the plugin manager (unloading plugins) here causes Lilypad to crash,
// likely due to some pending message in the queue that references lilypad procs.

View File

@ -32,7 +32,7 @@ DEFINE_EVENT_TYPE( pxEVT_OpenModalDialog );
DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
DEFINE_EVENT_TYPE( pxEVT_SysExecute );
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
DEFINE_EVENT_TYPE( pxEVT_AppCoreThreadFinished );
DEFINE_EVENT_TYPE( pxEVT_CoreThreadStatus );
DEFINE_EVENT_TYPE( pxEVT_FreezeThreadFinished );
bool UseAdminMode = false;
@ -118,13 +118,13 @@ void Pcsx2App::Ping() const
// Pcsx2App Event Handlers
// ----------------------------------------------------------------------------
// Invoked by the AppCoreThread when the thread has terminated itself.
void Pcsx2App::OnCoreThreadTerminated( wxCommandEvent& evt )
// Invoked by the AppCoreThread when it's internal status has changed.
// evt.GetInt() reflects the status at the time the message was sent, which may differ
// from the actual status. Typically listeners bound to this will want to use direct
// polling of the CoreThread rather than the belated status.
void Pcsx2App::OnCoreThreadStatus( wxCommandEvent& evt )
{
if( HasMainFrame() )
GetMainFrame().ApplySettings();
m_CoreThread = NULL;
m_evtsrc_CoreThreadStatus.Dispatch( evt );
}
void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt )
@ -220,7 +220,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
{
// Saved state load failed.
Console.Notice( ex.FormatDiagnosticMessage() );
sCoreThread.Resume();
CoreThread.Resume();
}
// ----------------------------------------------------------------------------
catch( Exception::PluginError& ex )
@ -243,6 +243,14 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
}
}
static void OnStateSaveFinished( void* obj, const wxCommandEvent& evt )
{
if( evt.GetInt() == CoreStatus_Resumed )
{
wxGetApp().PostMenuAction( MenuId_Exit );
wxGetApp().Source_CoreThreadStatus().Remove( NULL, OnStateSaveFinished );
}
}
// Common exit handler which can be called from any event (though really it should
// be called only from CloseWindow handlers since that's the more appropriate way
@ -250,17 +258,37 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
//
// returns true if the app can close, or false if the close event was canceled by
// the glorious user, whomever (s)he-it might be.
bool Pcsx2App::PrepForExit()
bool Pcsx2App::PrepForExit( bool canCancel )
{
m_CoreThread = NULL;
CleanupMess();
// If a savestate is saving, we should wait until it finishes. Otherwise the user
// might lose data.
if( StateCopy_IsBusy() )
{
Source_CoreThreadStatus().Add( NULL, OnStateSaveFinished );
throw Exception::CancelEvent( "Savestate in progress, cannot close program (close event delayed)" );
}
if( canCancel )
{
bool resume = CoreThread.Suspend();
if( /* TODO: Confirm with the user? */ false )
{
if(resume) CoreThread.Resume();
return false;
}
}
else
{
m_evtsrc_AppStatus.Dispatch( AppStatus_Exiting );
CleanupMess();
}
return true;
}
int Pcsx2App::OnExit()
{
PrepForExit();
CleanupMess();
if( g_Conf )
AppSaveSettings();
@ -283,16 +311,6 @@ MainEmuFrame& Pcsx2App::GetMainFrame() const
return *m_MainFrame;
}
// This method generates debug assertions if the CoreThread handle is NULL (typically
// indicating that there is no active emulation session). In most cases you'll want
// to use HasCoreThread() to test for thread validity first, or use GetCoreThreadPtr()
// and manually check for NULL (choice is a matter of programmer preference).
SysCoreThread& Pcsx2App::GetCoreThread() const
{
pxAssert( m_CoreThread != NULL );
return *m_CoreThread;
}
void AppApplySettings( const AppConfig* oldconf )
{
AllowFromMainThreadOnly();
@ -306,6 +324,8 @@ void AppApplySettings( const AppConfig* oldconf )
g_Conf->EmuOptions.BiosFilename = g_Conf->FullpathToBios();
bool resume = CoreThread.Suspend();
// Update the compression attribute on the Memcards folder.
// Memcards generally compress very well via NTFS compression.
@ -323,10 +343,10 @@ void AppApplySettings( const AppConfig* oldconf )
}
}
if( HasMainFrame() )
GetMainFrame().ApplySettings();
if( HasCoreThread() )
GetCoreThread().ApplySettings( g_Conf->EmuOptions );
CoreThread.ApplySettings( g_Conf->EmuOptions );
if( resume )
CoreThread.Resume();
}
void AppLoadSettings()
@ -368,8 +388,7 @@ void Pcsx2App::OpenGsFrame()
void Pcsx2App::OnGsFrameClosed()
{
if( m_CoreThread != NULL )
m_CoreThread->Suspend();
CoreThread.Suspend();
m_gsFrame = NULL;
}
@ -446,17 +465,16 @@ void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
// it, because apparently too much stuff is going on and the emulation states are wonky.
if( !m_CorePlugins ) return;
if( evt.GetInt() != -1 ) SysReset();
if( evt.GetInt() != -1 ) SysReset(); else CoreThread.Suspend();
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
if( evt.GetInt() != -1 ) CDVDsys_ChangeSource( (CDVD_SourceType)evt.GetInt() );
m_CoreThread = new AppCoreThread( *m_CorePlugins );
m_CoreThread->Resume();
CoreThread.Resume();
}
void Pcsx2App::SysReset()
{
m_CoreThread = NULL;
CoreThread.Reset();
}
// Returns true if there is a "valid" virtual machine state from the user's perspective. This
@ -466,8 +484,7 @@ void Pcsx2App::SysReset()
// state (such as saving it), you *must* suspend the Corethread first!
__forceinline bool SysHasValidState()
{
bool isRunning = HasCoreThread() ? GetCoreThread().IsRunning() : false;
return isRunning || StateCopy_HasFullState();
return CoreThread.HasValidState() || StateCopy_HasFullState();
}
// Writes text to console and updates the window status bar and/or HUD or whateverness.
@ -476,8 +493,7 @@ void SysStatus( const wxString& text )
{
// mirror output to the console!
Console.Status( text.c_str() );
if( HasMainFrame() )
GetMainFrame().SetStatusText( text );
sMainFrame.SetStatusText( text );
}
bool HasMainFrame()
@ -485,11 +501,6 @@ bool HasMainFrame()
return wxTheApp && wxGetApp().HasMainFrame();
}
bool HasCoreThread()
{
return wxTheApp && wxGetApp().HasCoreThread();
}
// This method generates debug assertions if either the wxApp or MainFrame handles are
// NULL (typically indicating that PCSX2 is running in NoGUI mode, or that the main
// frame has been closed). In most cases you'll want to use HasMainFrame() to test
@ -500,11 +511,6 @@ MainEmuFrame& GetMainFrame()
return wxGetApp().GetMainFrame();
}
SysCoreThread& GetCoreThread()
{
return wxGetApp().GetCoreThread();
}
// Returns a pointer to the main frame of the GUI (frame may be hidden from view), or
// NULL if no main frame exists (NoGUI mode and/or the frame has been destroyed). If
// the wxApp is NULL then this will also return NULL.
@ -512,10 +518,3 @@ MainEmuFrame* GetMainFramePtr()
{
return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL;
}
// Returns a pointer to the CoreThread of the GUI (thread may be stopped or suspended),
// or NULL if no core thread exists, or if the wxApp is also NULL.
SysCoreThread* GetCoreThreadPtr()
{
return wxTheApp ? wxGetApp().GetCoreThreadPtr() : NULL;
}

View File

@ -99,7 +99,7 @@ void pxLogConsole::DoLog( wxLogLevel level, const wxChar *szString, time_t t )
// ----------------------------------------------------------------------------
void ConsoleTestThread::ExecuteTask()
void ConsoleTestThread::ExecuteTaskInThread()
{
static int numtrack = 0;

View File

@ -70,7 +70,7 @@ class ConsoleTestThread : public Threading::PersistentThread
{
protected:
volatile bool m_done;
void ExecuteTask();
void ExecuteTaskInThread();
public:
ConsoleTestThread() :
@ -85,7 +85,7 @@ public:
protected:
void OnStart() {}
void OnThreadCleanup() {}
void OnCleanupInThread() {}
};
// --------------------------------------------------------------------------------------

View File

@ -54,8 +54,7 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title):
GSFrame::~GSFrame() throw()
{
if( HasCoreThread() )
GetCoreThread().Suspend(); // Just in case...!
CoreThread.Suspend(); // Just in case...!
}
void GSFrame::OnCloseWindow(wxCloseEvent& evt)

View File

@ -71,14 +71,12 @@ namespace Implementations
void Sys_Suspend()
{
if( HasCoreThread() )
GetCoreThread().Suspend();
CoreThread.Suspend();
}
void Sys_Resume()
{
if( HasCoreThread() )
GetCoreThread().Resume();
CoreThread.Resume();
}
void Sys_TakeSnapshot()
@ -88,10 +86,9 @@ namespace Implementations
void Sys_RenderToggle()
{
if( !HasCoreThread() ) return;
sCoreThread.Suspend();
bool resume = CoreThread.Suspend();
renderswitch = !renderswitch;
sCoreThread.Resume();
if( resume ) CoreThread.Resume();
}
void Sys_LoggingToggle()

View File

@ -149,7 +149,7 @@ void MainEmuFrame::OnCloseWindow(wxCloseEvent& evt)
}
else
{
isClosing = wxGetApp().PrepForExit();
isClosing = wxGetApp().PrepForExit( evt.CanVeto() );
if( !isClosing ) evt.Veto( true );
}
@ -223,7 +223,7 @@ void MainEmuFrame::ConnectMenus()
ConnectMenu( MenuId_Exit, Menu_Exit_Click );
ConnectMenu( MenuId_Sys_SuspendResume, Menu_SuspendResume_Click );
ConnectMenu( MenuId_Sys_Reset, Menu_EmuReset_Click );
ConnectMenu( MenuId_Sys_Reset, Menu_SysReset_Click );
ConnectMenu( MenuId_State_LoadOther, Menu_LoadStateOther_Click );
@ -260,6 +260,13 @@ void MainEmuFrame::InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf )
}
}
static void OnCoreThreadStatusChanged( void* obj, const wxCommandEvent& evt )
{
if( obj == NULL ) return;
MainEmuFrame* mframe = (MainEmuFrame*)obj;
mframe->ApplySettings();
}
// ------------------------------------------------------------------------
MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
wxFrame(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER) ),
@ -286,7 +293,9 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
m_LoadStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Load01 ) ),
m_SaveStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Save01 ) ),
m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, MenuId_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) )
m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, MenuId_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) ),
m_Listener_CoreThreadStatus( wxGetApp().Source_CoreThreadStatus(), CmdEvt_Listener( this, OnCoreThreadStatusChanged ) )
{
// ------------------------------------------------------------------------
// Initial menubar setup. This needs to be done first so that the menu bar's visible size
@ -495,8 +504,7 @@ void MainEmuFrame::ApplySettings()
GetMenuBar()->Enable( MenuId_Sys_SuspendResume, SysHasValidState() );
if( HasCoreThread() )
GetMenuBar()->SetLabel( MenuId_Sys_SuspendResume, GetCoreThread().IsSuspended() ? _("Resume") :_("Suspend") );
GetMenuBar()->SetLabel( MenuId_Sys_SuspendResume, CoreThread.IsExecMode_Running() ? _("Suspend") :_("Resume") );
if( m_RecentIsoList )
{

View File

@ -47,22 +47,24 @@ protected:
wxStatusBar& m_statusbar;
wxStaticBitmap m_background;
wxMenuBar& m_menubar;
wxMenuBar& m_menubar;
wxMenu& m_menuBoot;
wxMenu& m_menuEmu;
wxMenu& m_menuConfig;
wxMenu& m_menuMisc;
wxMenu& m_menuDebug;
wxMenu& m_menuBoot;
wxMenu& m_menuEmu;
wxMenu& m_menuConfig;
wxMenu& m_menuMisc;
wxMenu& m_menuDebug;
wxMenu& m_menuVideo;
wxMenu& m_menuAudio;
wxMenu& m_menuPad;
wxMenu& m_menuVideo;
wxMenu& m_menuAudio;
wxMenu& m_menuPad;
wxMenu& m_LoadStatesSubmenu;
wxMenu& m_SaveStatesSubmenu;
wxMenu& m_LoadStatesSubmenu;
wxMenu& m_SaveStatesSubmenu;
wxMenuItem& m_MenuItem_Console;
wxMenuItem& m_MenuItem_Console;
CmdEvt_ListenerBinding m_Listener_CoreThreadStatus;
// ------------------------------------------------------------------------
// MainEmuFrame Constructors and Member Methods
@ -107,7 +109,7 @@ protected:
void Menu_Exit_Click(wxCommandEvent &event);
void Menu_SuspendResume_Click(wxCommandEvent &event);
void Menu_EmuReset_Click(wxCommandEvent &event);
void Menu_SysReset_Click(wxCommandEvent &event);
void Menu_ConfigPlugin_Click(wxCommandEvent &event);

View File

@ -82,13 +82,13 @@ bool MainEmuFrame::_DoSelectIsoBrowser()
void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
{
sCoreThread.Suspend();
CoreThread.Suspend();
if( !wxFileExists( g_Conf->CurrentIso ) )
{
if( !_DoSelectIsoBrowser() )
{
sCoreThread.Resume();
CoreThread.Resume();
return;
}
}
@ -100,7 +100,7 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
if( !result )
{
sCoreThread.Resume();
CoreThread.Resume();
return;
}
}
@ -113,18 +113,18 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
void MainEmuFrame::Menu_IsoBrowse_Click( wxCommandEvent &event )
{
sCoreThread.Suspend();
bool resume = CoreThread.Suspend();
_DoSelectIsoBrowser();
sCoreThread.Resume();
if( resume ) CoreThread.Resume();
}
void MainEmuFrame::Menu_RunIso_Click( wxCommandEvent &event )
{
sCoreThread.Suspend();
CoreThread.Suspend();
if( !_DoSelectIsoBrowser() )
{
sCoreThread.Resume();
CoreThread.Resume();
return;
}
@ -190,23 +190,19 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
{
if( !SysHasValidState() ) return;
if( SysCoreThread* thr = GetCoreThreadPtr() )
{
if( thr->IsSuspended() )
thr->Resume();
else
thr->Suspend();
}
if( !CoreThread.Suspend() )
CoreThread.Resume();
}
void MainEmuFrame::Menu_EmuReset_Click(wxCommandEvent &event)
void MainEmuFrame::Menu_SysReset_Click(wxCommandEvent &event)
{
if( !SysHasValidState() ) return;
bool wasSuspended = HasCoreThread() ? GetCoreThread().IsSuspended() : true;
bool resume = CoreThread.Suspend();
sApp.SysReset();
if( !wasSuspended )
if( resume )
sApp.SysExecute();
}

View File

@ -412,8 +412,8 @@ namespace Panels
protected:
void OnStart() {}
void ExecuteTask();
void OnThreadCleanup() {}
void ExecuteTaskInThread();
void OnCleanupInThread() {}
};
// This panel contains all of the plugin combo boxes. We stick them

View File

@ -83,9 +83,10 @@ bool Panels::StaticApplyState::ApplyPage( int pageid, bool saveOnSuccess )
// If an exception is thrown above, this code below won't get run.
// (conveniently skipping any option application! :D)
// Note: apply first, then save -- in case the apply fails.
AppApplySettings( &confcopy );
if( saveOnSuccess )
AppSaveSettings();
if( saveOnSuccess ) AppSaveSettings();
}
catch( Exception::CannotApplySettings& ex )
{

View File

@ -310,7 +310,7 @@ void Panels::PluginSelectorPanel::Apply()
if( pi->shortname != NULL )
{
if( wxGetApp().m_CoreThread )
if( CoreThread.IsRunning() )
{
// [TODO] : Post notice that this shuts down existing emulation, and may not safely recover.
}
@ -554,7 +554,7 @@ void Panels::PluginSelectorPanel::EnumThread::DoNextPlugin( int curidx )
m_master.GetEventHandler()->AddPendingEvent( yay );
}
void Panels::PluginSelectorPanel::EnumThread::ExecuteTask()
void Panels::PluginSelectorPanel::EnumThread::ExecuteTaskInThread()
{
DevCon.Status( "Plugin Enumeration Thread started..." );

View File

@ -58,8 +58,8 @@ public:
protected:
void OnStart() {}
void OnThreadCleanup();
void ExecuteTask();
void OnCleanupInThread();
void ExecuteTaskInThread();
};
LoadPluginsTask::~LoadPluginsTask() throw()
@ -67,7 +67,7 @@ LoadPluginsTask::~LoadPluginsTask() throw()
PersistentThread::Cancel();
}
void LoadPluginsTask::ExecuteTask()
void LoadPluginsTask::ExecuteTaskInThread()
{
wxGetApp().Ping();
Yield(3);
@ -78,13 +78,13 @@ void LoadPluginsTask::ExecuteTask()
Result = PluginManager_Create( m_folders );
}
void LoadPluginsTask::OnThreadCleanup()
void LoadPluginsTask::OnCleanupInThread()
{
wxCommandEvent evt( pxEVT_LoadPluginsComplete );
evt.SetClientData( this );
wxGetApp().AddPendingEvent( evt );
_parent::OnThreadCleanup();
_parent::OnCleanupInThread();
}
/////////////////////////////////////////////////////////////////////////////////////////
@ -127,7 +127,7 @@ static bool plugin_load_lock = false;
void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt )
{
if( plugin_load_lock ) return;
m_CoreThread = NULL;
CoreThread.Cancel();
m_CorePlugins = NULL;
wxString passins[PluginId_Count];
@ -203,7 +203,7 @@ void LoadPluginsImmediate()
{
if( g_plugins != NULL ) return;
wxGetApp().m_CoreThread = NULL;
CoreThread.Cancel();
wxString passins[PluginId_Count];
ConvertPluginFilenames( passins );
@ -213,6 +213,6 @@ void LoadPluginsImmediate()
void UnloadPlugins()
{
wxGetApp().m_CoreThread = NULL;
CoreThread.Cancel();
wxGetApp().m_CorePlugins = NULL;
}

View File

@ -309,20 +309,17 @@ void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console.
// VTLB Public API -- Init/Term/RegisterHandler stuff
//
// Registers a handler into the VTLB's internal handler array. The handler defines specific behavior
// Assigns or re-assigns the callbacks for a VTLB memory handler. The handler defines specific behavior
// for how memory pages bound to the handler are read from / written to. If any of the handler pointers
// are NULL, the memory operations will be mapped to the BusError handler (thus generating BusError
// exceptions if the emulated app attempts to access them).
//
// Note: All handlers persist across calls to vtlb_Reset(), but are wiped/invalidated by calls to vtlb_Init()
//
// Returns a handle for the newly created handler See .vtlb_MapHandler for use of the return value.
vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
void vtlb_ReassignHandler( vtlbHandler rv,
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128 )
{
//write the code :p
vtlbHandler rv=vtlbHandlerCount++;
vtlbdata.RWFT[0][0][rv] = (r8!=0) ? (void*)(r8): (void*)vtlbDefaultPhyRead8;
vtlbdata.RWFT[1][0][rv] = (r16!=0) ? (void*)r16: (void*)vtlbDefaultPhyRead16;
vtlbdata.RWFT[2][0][rv] = (r32!=0) ? (void*)r32: (void*)vtlbDefaultPhyRead32;
@ -340,10 +337,32 @@ vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP
vtlbdata.RWFT[2][1][rv] = (void*)((w32!=0) ? w32:vtlbDefaultPhyWrite32);
vtlbdata.RWFT[3][1][rv] = (void*)((w64!=0) ? w64:vtlbDefaultPhyWrite64);
vtlbdata.RWFT[4][1][rv] = (void*)((w128!=0) ? w128:vtlbDefaultPhyWrite128);
}
vtlbHandler vtlb_NewHandler()
{
pxAssertDev( vtlbHandlerCount < 127, "VTLB allowed handler count exceeded!" );
return vtlbHandlerCount++;
}
// Registers a handler into the VTLB's internal handler array. The handler defines specific behavior
// for how memory pages bound to the handler are read from / written to. If any of the handler pointers
// are NULL, the memory operations will be mapped to the BusError handler (thus generating BusError
// exceptions if the emulated app attempts to access them).
//
// Note: All handlers persist across calls to vtlb_Reset(), but are wiped/invalidated by calls to vtlb_Init()
//
// Returns a handle for the newly created handler See vtlb_MapHandler for use of the return value.
//
vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
{
vtlbHandler rv = vtlb_NewHandler();
vtlb_ReassignHandler( rv, r8, r16, r32, r64, r128, w8, w16, w32, w64, w128 );
return rv;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Maps the given hander (created with vtlb_RegisterHandler) to the specified memory region.
// New mappings always assume priority over previous mappings, so place "generic" mappings for

View File

@ -26,9 +26,18 @@ extern u8* vtlb_malloc( uint size, uint align );
extern void vtlb_free( void* pmem, uint size );
//physical stuff
vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128);
extern vtlbHandler vtlb_NewHandler();
extern vtlbHandler vtlb_RegisterHandler(
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128
);
extern void vtlb_ReassignHandler( vtlbHandler rv,
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128
);
extern void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size);
extern void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize=0);

View File

@ -169,7 +169,7 @@ public:
protected:
void OnStart() {}
void ExecuteTask()
void ExecuteTaskInThread()
{
try
{
@ -188,7 +188,7 @@ protected:
}
}
void OnThreadCleanup() { }
void OnCleanupInThread() { }
};
// --------------------------------------------------------------------------------------

View File

@ -309,6 +309,8 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
}*/
IsOpened = true;
lClocks = (cyclePtr!=NULL) ? *cyclePtr : 0;
try
{
SndBuffer::Init();

View File

@ -276,17 +276,23 @@ u32 TicksThread = 0;
__forceinline void TimeUpdate(u32 cClocks)
{
s32 dClocks = cClocks-lClocks;
u32 dClocks = cClocks - lClocks;
// [Air]: Sanity Check
// If for some reason our clock value seems way off base, just mix
// out a little bit, skip the rest, and hope the ship "rights" itself later on.
// Sanity Checks:
// It's not totally uncommon for the IOP's clock to jump backwards a cycle or two, and in
// such cases we just want to ignore the TimeUpdate call.
if( dClocks > (u32)-15 ) return;
// But if for some reason our clock value seems way off base (typically due to bad dma
// timings from PCSX2), just mix out a little bit, skip the rest, and hope the ship
// "rights" itself later on.
if( dClocks > TickInterval*SanityInterval )
{
ConLog( " * SPU2 > TimeUpdate Sanity Check (Tick Delta: %d) (PS2 Ticks: %d)\n", dClocks/TickInterval, cClocks/TickInterval );
dClocks = TickInterval*SanityInterval;
lClocks = cClocks-dClocks;
dClocks = TickInterval * SanityInterval;
lClocks = cClocks - dClocks;
}
//UpdateDebugDialog();
@ -350,8 +356,8 @@ __forceinline void TimeUpdate(u32 cClocks)
}
}
dClocks-=TickInterval;
lClocks+=TickInterval;
dClocks -= TickInterval;
lClocks += TickInterval;
Cycles++;
// Note: IOP does not use MMX regs, so no need to save them.