* Major cleanups and improvements to the Threading namespace.
 * Created CoreEmuThread class framework, which currently runs the EEcore, IOP, and VUs with threadsafe suspension, reset, and resume features.

git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxgui@1624 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-08-15 06:17:43 +00:00
parent 3544bcd118
commit c415d8d694
38 changed files with 3827 additions and 371 deletions

View File

@ -570,19 +570,14 @@ typedef struct _ptw32_handle_t {
#ifdef __cplusplus
// Added support for various operators so that the struct is
// more pthreads-compliant in behavior. (air)
const bool operator ==( const void* rightside )
const bool operator ==( const struct _ptw32_handle_t rightside ) const
{
return p == rightside;
return p == rightside.p;
}
const bool operator !=( const void* rightside )
const bool operator !=( const struct _ptw32_handle_t rightside ) const
{
return p != rightside;
}
bool operator =( void* rightside )
{
p = rightside;
return p != rightside.p;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -354,12 +354,16 @@ namespace Exception
explicit CreateStream(
const char* objname,
const char* msg=wxLt("File could not be created or opened") ) :
Stream( wxString::FromAscii( objname ), msg ) {}
Stream( wxString::FromAscii( objname ), msg ) {}
explicit CreateStream(
const wxString& objname=wxString(),
const char* msg=wxLt("File could not be created or opened") ) :
Stream( objname, msg ) {}
Stream( objname, msg ) {}
explicit CreateStream(
const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) :
Stream( objname, msg_eng, msg_xlt ) {}
};
// Exception thrown when an attempt to open a non-existent file is made.
@ -373,8 +377,11 @@ namespace Exception
explicit FileNotFound(
const wxString& objname=wxString(),
const char* msg="File not found" ) :
CreateStream( objname, msg ) {}
explicit FileNotFound( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) :
CreateStream( objname, msg_eng, msg_xlt ) {}
CreateStream( objname, msg ) {}
};
class AccessDenied : public CreateStream

View File

@ -24,9 +24,28 @@
#include "Pcsx2Defs.h"
namespace Exception
{
//////////////////////////////////////////////////////////////////////////////////////////
// Thread termination exception, used to quickly terminate threads from anywhere in the
// thread's call stack. This exception is handled by the PCSX2 PersistentThread class. Threads
// not derived from that class will not handle this exception.
//
class ThreadTermination : public BaseException
{
public:
virtual ~ThreadTermination() throw() {}
ThreadTermination( const ThreadTermination& src ) : BaseException( src ) {}
explicit ThreadTermination() :
BaseException( "Thread terminated" ) { }
};
}
namespace Threading
{
///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Define some useful object handles - wait events, mutexes.
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
@ -56,7 +75,8 @@ namespace Threading
void Post();
void Post( int multiple );
void Wait();
int Count();
void WaitNoCancel();
int Count();
};
struct MutexLock
@ -84,42 +104,42 @@ namespace Threading
extern void Sleep( int ms );
//////////////////////////////////////////////////////////////////////////////////////////
// Thread - Helper class for the basics of starting/managing simple threads.
// PersistentThread - Helper class for the basics of starting/managing persistent threads.
//
// Use this as a base class for your threaded procedure, and implement the 'int Callback()'
// method. Use Start() and Close() to start and shutdown the thread, and use m_post_event
// Use this as a base class for your threaded procedure, and implement the 'int ExecuteTask()'
// method. Use Start() and Cancel() to start and shutdown the thread, and use m_post_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).
//
// Notes:
// * To ensure thread safety against C++'s bizarre and not-thread-friendly object
// constructors and destructors, you *must* use Start() and Close(). There is a built-
// in Close() called on destruction, which should work for very simple threads (that
// do not have any special shutdown code of their own), but
//
// * Constructing threads as static vars isn't recommended since it can potentially con-
// fuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
// no dependency options for ensuring correct static var initializations).
// no dependency options for ensuring correct static var initializations). Use heap
// allocation to create thread objects instead.
//
class Thread : NoncopyableObject
class PersistentThread : NoncopyableObject
{
protected:
typedef int (*PlainJoeFP)();
pthread_t m_thread;
int m_returncode; // value returned from the thread on close.
bool m_terminated; // set true after the thread has been closed.
Semaphore m_post_event; // general wait event that's needed by most threads.
pthread_t m_thread;
sptr m_returncode; // value returned from the thread on close.
bool m_running;
Semaphore m_post_event; // general wait event that's needed by most threads.
public:
virtual ~Thread();
Thread();
virtual ~PersistentThread();
PersistentThread();
virtual void Start();
virtual void Close();
virtual void Cancel( bool isBlocking = true );
// Gets the return code of the thread.
// Throws std::logic_error if the thread has not terminated.
int GetReturnCode() const;
virtual int GetReturnCode() const;
virtual bool IsRunning() const;
virtual sptr Block();
protected:
// Used to dispatch the thread callback function.
@ -128,7 +148,20 @@ namespace Threading
static void* _internal_callback( void* func );
// Implemented by derived class to handle threading actions!
virtual int Callback()=0;
virtual sptr ExecuteTask()=0;
// ----------------------------------------------------------------------------
// Static Methods (PersistentThread)
// ----------------------------------------------------------------------------
public:
// performs a test on the given thread handle, returning true if the thread exists
// or false if the thread is dead/done/never existed.
static bool Exists( pthread_t pid )
{
// passing 0 to pthread_kill is a NOP, and returns the status of the thread only.
return ( ESRCH != pthread_kill( pid, 0 ) );
}
};
//////////////////////////////////////////////////////////////////////////////////////////
@ -136,22 +169,41 @@ namespace Threading
// Using this class provides an exception-safe (and generally clean) method of locking
// code inside a function or conditional block.
//
class ScopedLock : NoncopyableObject
class ScopedLock : public NoncopyableObject
{
protected:
MutexLock& m_lock;
bool m_IsLocked;
public:
virtual ~ScopedLock()
{
m_lock.Unlock();
if( m_IsLocked )
m_lock.Unlock();
}
ScopedLock( MutexLock& locker ) :
m_lock( locker )
m_lock( locker )
, m_IsLocked( true )
{
m_lock.Lock();
}
// Provides manual unlocking of a scoped lock prior to object destruction.
void Unlock()
{
if( !m_IsLocked ) return;
m_IsLocked = false;
m_lock.Unlock();
}
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
void Lock()
{
if( m_IsLocked ) return;
m_lock.Lock();
m_IsLocked = true;
}
};
//////////////////////////////////////////////////////////////////////////////////////////
@ -187,49 +239,49 @@ namespace Threading
// into smaller sections. For example, if you have 20,000 items to process, the task
// can be divided into two threads of 10,000 items each.
//
class BaseTaskThread : public Thread
class BaseTaskThread : public PersistentThread
{
protected:
volatile bool m_done;
volatile bool m_Done;
volatile bool m_TaskComplete;
Semaphore m_post_TaskComplete;
public:
virtual ~BaseTaskThread() {}
BaseTaskThread() :
m_done( false )
m_Done( false )
, m_TaskComplete( false )
, m_post_TaskComplete()
{
}
// Tells the thread to exit and then waits for thread termination.
// To force-terminate the thread without "nicely" waiting for the task to complete,
// explicitly use the Thread::Close parent implementation instead.
void Close()
sptr Block()
{
if( m_terminated ) return;
m_done = true;
if( !m_running ) return m_returncode;
m_Done = true;
m_post_event.Post();
pthread_join( m_thread, NULL );
return PersistentThread::Block();
}
// Initiates the new task. This should be called after your own StartTask has
// initialized internal variables / preparations for task execution.
void PostTask()
{
jASSUME( !m_terminated );
jASSUME( m_running );
m_TaskComplete = false;
m_post_TaskComplete.Reset();
m_post_event.Post();
}
// Blocks current thread execution pending the completion of the parallel task.
void WaitForResult() const
void WaitForResult()
{
if( m_terminated ) return;
while( !m_TaskComplete )
{
Timeslice();
SpinWait();
}
if( !m_running ) return;
if( !m_TaskComplete )
m_post_TaskComplete.Wait();
else
m_post_TaskComplete.Reset();
}
protected:
@ -237,18 +289,19 @@ namespace Threading
// all your necessary processing work here.
virtual void Task()=0;
int Callback()
sptr ExecuteTask()
{
do
{
// Wait for a job!
m_post_event.Wait();
if( m_done ) break;
if( m_Done ) break;
Task();
m_TaskComplete = true;
} while( !m_done );
m_post_TaskComplete.Post();
} while( !m_Done );
return 0;
}
};

View File

@ -80,7 +80,7 @@ namespace Exception
wxString Stream::DisplayMessage() const
{
return m_message + L"\n" + StreamName.c_str();
return m_message + L"\n\n" + StreamName;
}
// ------------------------------------------------------------------------

View File

@ -65,15 +65,4 @@ namespace Threading
// performance hint and isn't required).
__asm__ ( "pause" );
}
void* Thread::_internal_callback( void* itsme )
{
jASSUME( itsme != NULL );
Thread& owner = *((Thread*)itsme);
owner.m_returncode = owner.Callback();
owner.m_terminated = true;
return NULL;
}
}

View File

@ -23,40 +23,94 @@ using namespace Threading;
namespace Threading
{
Thread::Thread() :
PersistentThread::PersistentThread() :
m_thread()
, m_returncode( 0 )
, m_terminated( false )
, m_running( false )
, m_post_event()
{
}
Thread::~Thread()
// Perform a blocking termination of the thread, to ensure full object cleanup.
PersistentThread::~PersistentThread()
{
Close();
Cancel( false );
}
void Thread::Start()
void PersistentThread::Start()
{
m_terminated = false;
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
throw Exception::ThreadCreationError();
m_running = true;
}
void Thread::Close()
// 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
// fire-and-forget behavior on threads, use pthreads directly for now.
// (TODO : make a DetachedThread class?)
//
// Parameters:
// isBlocking - indicates if the Cancel action should block for thread completion or not.
//
void PersistentThread::Cancel( bool isBlocking )
{
if( !m_terminated )
pthread_cancel( m_thread );
pthread_join( m_thread, NULL );
if( !m_running ) return;
m_running = false;
pthread_cancel( m_thread );
if( isBlocking )
pthread_join( m_thread, (void**)&m_returncode );
else
pthread_detach( m_thread );
}
int Thread::GetReturnCode() const
// Blocks execution of the calling thread until this thread completes its task. The
// caller should make sure to signal the thread to exit, or else blocking may deadlock the
// calling thread. Classes which extend PersistentThread should override this method
// and signal any necessary thread exit variables prior to blocking.
//
// Returns the return code of the thread.
// This method is roughly the equivalent of pthread_join().
//
sptr PersistentThread::Block()
{
if( !m_terminated )
throw std::logic_error( "Thread is still running. No return code is available." );
bool isOwner = (pthread_self() == m_thread);
DevAssert( !isOwner, "Thread deadlock detected; Block() should never be called by the owner thread." );
pthread_join( m_thread, (void**)&m_returncode );
return m_returncode;
}
bool PersistentThread::IsRunning() const
{
return ( m_running && (ESRCH != pthread_kill( m_thread, 0 )) );
}
// Exceptions:
// InvalidOperation - thrown if the thread is still running or has never been started.
//
sptr PersistentThread::GetReturnCode() const
{
if( !m_running )
throw Exception::InvalidOperation( "Thread.GetReturnCode : thread has not been started." );
if( IsRunning() )
throw Exception::InvalidOperation( "Thread.GetReturnCode : thread is still running." );
return m_returncode;
}
void* PersistentThread::_internal_callback( void* itsme )
{
jASSUME( itsme != NULL );
PersistentThread& owner = *((PersistentThread*)itsme);
owner.m_returncode = owner.ExecuteTask();
return (void*)owner.m_returncode;
}
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
// Let's not use it. (Air)
@ -123,6 +177,22 @@ namespace Threading
sem_wait( &sema );
}
// Performs an uncancellable wait on a semaphore; restoring the thread's previous cancel state
// after the wait has completed. Useful for situations where the semaphore itself is stored on
// the stack and passed to another thread via GUI message or such, avoiding complications where
// the thread might be cancelled and the stack value becomes invalid.
//
// Performance note: this function has quite a bit more overhead compared to Semaphore::Wait(), so
// consider manually specifying the thread as uncancellable and using Wait() instead if you need
// to do a lot of no-cancel waits in a tight loop worker thread, for example.
void Semaphore::WaitNoCancel()
{
int oldstate;
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
Wait();
pthread_setcancelstate( oldstate, NULL );
}
int Semaphore::Count()
{
int retval;

View File

@ -72,20 +72,5 @@ namespace Threading
{
__asm { pause };
}
void* Thread::_internal_callback( void* itsme )
{
jASSUME( itsme != NULL );
//pthread_win32_thread_attach_np();
Thread& owner = *((Thread*)itsme);
owner.m_returncode = owner.Callback();
owner.m_terminated = true;
//pthread_win32_thread_detach_np();
return NULL;
}
}

View File

@ -526,7 +526,7 @@ void cdvdDetectDisk()
cdvd.Type = DoCDVDdetectDiskType();
wxString str;
int result = GetPS2ElfName(str);
GetPS2ElfName(str);
// Now's a good time to reload the ELF info...
if( ElfCRC == 0 )

View File

@ -32,6 +32,14 @@ enum PluginsEnum_t
PluginId_Count
};
// This macro is actually useful for about any and every possible application of C++
// equality operators.
#define OpEqu( field ) (field == right.field)
//------------ DEFAULT sseMXCSR VALUES ---------------
#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop"
#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop"
/////////////////////////////////////////////////////////////////////////////////////////
// Pcsx2Config
//
@ -50,28 +58,56 @@ class Pcsx2Config
public:
struct ProfilerOptions
{
bool
Enabled:1, // universal toggle for the profiler.
RecBlocks_EE:1, // Enables per-block profiling for the EE recompiler [unimplemented]
RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented]
RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented]
RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented]
union
{
struct
{
bool
Enabled:1, // universal toggle for the profiler.
RecBlocks_EE:1, // Enables per-block profiling for the EE recompiler [unimplemented]
RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented]
RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented]
RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented]
};
u8 bits;
};
ProfilerOptions() : bits( 0 ) {}
void LoadSave( IniInterface& conf );
bool operator ==( const ProfilerOptions& right ) const
{
return OpEqu( bits );
}
bool operator !=( const ProfilerOptions& right ) const
{
return !this->operator ==( right );
}
};
// ------------------------------------------------------------------------
struct RecompilerOptions
{
bool
EnableEE:1,
EnableIOP:1,
EnableVU0:1,
EnableVU1:1;
bool
UseMicroVU0:1,
UseMicroVU1:1;
union
{
struct
{
bool
EnableEE:1,
EnableIOP:1,
EnableVU0:1,
EnableVU1:1;
bool
UseMicroVU0:1,
UseMicroVU1:1;
};
u8 bits;
};
RecompilerOptions() : bits( 0 ) { }
void Load( const wxString& srcfile );
void Load( const wxInputStream& srcstream );
@ -80,29 +116,64 @@ public:
void LoadSave( IniInterface& conf );
bool operator ==( const RecompilerOptions& right ) const
{
return OpEqu( bits );
}
bool operator !=( const RecompilerOptions& right ) const
{
return !this->operator ==( right );
}
} Recompiler;
// ------------------------------------------------------------------------
struct CpuOptions
{
RecompilerOptions Recompiler;
u32 sseMXCSR;
u32 sseVUMXCSR;
bool
vuOverflow:1,
vuExtraOverflow:1,
vuSignOverflow:1,
vuUnderflow:1;
bool
fpuOverflow:1,
fpuExtraOverflow:1,
fpuFullMode:1;
struct
{
union
{
bool
vuOverflow:1,
vuExtraOverflow:1,
vuSignOverflow:1,
vuUnderflow:1;
bool
fpuOverflow:1,
fpuExtraOverflow:1,
fpuFullMode:1;
};
u8 bits;
};
ProfilerOptions Profiler;
RecompilerOptions Recompiler;
CpuOptions() :
sseMXCSR( DEFAULT_sseMXCSR )
, sseVUMXCSR( DEFAULT_sseVUMXCSR )
, bits( 0 )
{
}
void LoadSave( IniInterface& conf );
bool operator ==( const CpuOptions& right ) const
{
return
OpEqu( sseMXCSR ) && OpEqu( sseVUMXCSR ) &&
OpEqu( bits ) && OpEqu( Recompiler );
}
bool operator !=( const CpuOptions& right ) const
{
return !this->operator ==( right );
}
};
// ------------------------------------------------------------------------
@ -128,36 +199,77 @@ public:
// ------------------------------------------------------------------------
struct GamefixOptions
{
bool
VuAddSubHack:1, // Fix for Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate.
VuClipFlagHack:1, // Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu.
FpuCompareHack:1, // Fix for Persona games, maybe others. It's to do with the VU clip flag (again).
FpuMulHack:1, // Fix for Tales of Destiny hangs.
XgKickHack:1; // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others.
union
{
struct
{
bool
VuAddSubHack:1, // Fix for Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate.
VuClipFlagHack:1, // Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu.
FpuCompareHack:1, // Fix for Persona games, maybe others. It's to do with the VU clip flag (again).
FpuMulHack:1, // Fix for Tales of Destiny hangs.
XgKickHack:1; // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others.
};
u8 bits;
};
GamefixOptions() : bits( 0 ) {}
void LoadSave( IniInterface& conf );
bool operator ==( const GamefixOptions& right ) const
{
return OpEqu( bits );
}
bool operator !=( const GamefixOptions& right ) const
{
return !this->operator ==( right );
}
};
// ------------------------------------------------------------------------
struct SpeedhackOptions
{
int
EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0)
VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3)
IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate
IntcStat:1, // tells Pcsx2 to fast-forward through intc_stat waits.
BIFC0:1, // enables BIFC0 detection and fast-forwarding
vuMinMax:1, // microVU specific MinMax hack; Can cause SPS, Black Screens, etc...
vuFlagHack:1; // MicroVU specific flag hack; Can cause Infinite loops, SPS, etc...
union
{
struct
{
int
EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0)
VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3)
IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate
IntcStat:1, // tells Pcsx2 to fast-forward through intc_stat waits.
BIFC0:1, // enables BIFC0 detection and fast-forwarding
vuMinMax:1, // microVU specific MinMax hack; Can cause SPS, Black Screens, etc...
vuFlagHack:1; // MicroVU specific flag hack; Can cause Infinite loops, SPS, etc...
};
u16 bits;
};
SpeedhackOptions() : bits( 0 ) {}
void LoadSave( IniInterface& conf );
bool operator ==( const SpeedhackOptions& right ) const
{
return OpEqu( bits );
}
bool operator !=( const SpeedhackOptions& right ) const
{
return !this->operator ==( right );
}
};
public:
bool CdvdVerboseReads:1; // enables cdvd read activity verbosely dumped to the console
bool CdvdDumpBlocks:1;
bool EnablePatches:1;
bool CdvdDumpBlocks:1; // enables cdvd block dumping
bool EnablePatches:1; // enables patch detection and application
// when enabled performs bios stub execution, skipping full sony bios + splash screens
bool SkipBiosSplash:1;
// Closes the GS/Video port on escape (good for fullscreen activity)
bool closeGSonEsc:1;
@ -169,6 +281,7 @@ public:
VideoOptions Video;
SpeedhackOptions Speedhacks;
GamefixOptions Gamefixes;
ProfilerOptions Profiler;
void Load( const wxString& srcfile );
void Load( const wxInputStream& srcstream );
@ -178,21 +291,6 @@ public:
void LoadSave( IniInterface& ini );
};
// Pauses the emulation state at the next PS2 vsync, and returns control to the calling
// thread; or does nothing if the core is already suspended. Calling this thread from the
// Core thread will result in deadlock.
extern void Core_Suspend();
// 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.
extern void Core_ApplySettings( const Pcsx2Config& src );
// Resumes the core execution state, or does nothing is the core is already running. If
// settings were changed, resets will be performed as needed and emulation state resumed from
// memory savestates.
extern void Core_Resume();
//////////////////////////////////////////////////////////////////////////
// Session Configuration Override Flags
//
@ -244,10 +342,6 @@ extern SessionOverrideFlags g_Session;
#define CHECK_FPU_EXTRA_FLAGS 1 // Always enabled now // Sets D/I flags on FPU instructions
#define CHECK_FPU_FULL (EmuConfig.Cpu.fpuFullMode)
//------------ DEFAULT sseMXCSR VALUES!!! ---------------
#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop"
#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop"
//------------ EE Recompiler defines - Comment to disable a recompiler ---------------
#define SHIFT_RECOMPILE // Speed majorly reduced if disabled

View File

@ -505,28 +505,27 @@ u32 loadElfCRC( const char* filename )
return crcval;
}
int loadElfFile(const wxString& filename)
// Loads the elf binary data from the specified file into PS2 memory, and injects the ELF's
// starting execution point into cpuRegs.pc. If the filename is a cdrom URI in the form
// of "cdrom0:" or "cdrom1:" then the CDVD is used as the source; otherwise the ELF is loaded
// from the host filesystem.
//
// If the specified filename is empty then no action is taken (PS2 will continue booting
// normally as if it has no CD
//
// Throws exception on error:
//
void loadElfFile(const wxString& filename)
{
// Reset all recompilers prior to initiating a BIOS or new ELF. The cleaner the
// slate, the happier the recompiler!
SysClearExecutionCache();
if( filename.IsEmpty() )
{
Console::Notice( "Running the PS2 BIOS..." );
return -1;
}
// We still need to run the BIOS stub, so that all the EE hardware gets initialized correctly.
cpuExecuteBios();
if( filename.IsEmpty() ) return;
int elfsize;
Console::Status( wxsFormat( L"loadElfFile: %s", filename.c_str() ) );
const wxCharBuffer buffer( filename.ToAscii() );
const char* fnptr = buffer.data();
bool useCdvdSource=false;
if( !filename.StartsWith( L"cdrom0:" ) && !filename.StartsWith( L"cdrom1:" ) )
{
// Loading from a file (or non-cd image)
@ -536,23 +535,25 @@ int loadElfFile(const wxString& filename)
else
{
// Loading from a CD rom or CD image.
useCdvdSource = true;
TocEntry toc;
IsoFS_init( );
if ( IsoFS_findFile( fnptr + strlen( "cdromN:" ), &toc ) == -1 )
return -1;
throw Exception::FileNotFound( filename, wxLt("ELF file was not found on the CDVD source media.") );
elfsize = toc.fileSize;
}
Console::Status( wxsFormat(L"loadElfFile: %d", elfsize) );
if( elfsize == 0 ) return -1;
if( elfsize == 0 )
throw Exception::BadStream( filename, wxLt("Unexpected end of ELF file: ") );
ElfObject elfobj( filename, elfsize );
if( elfobj.proghead == NULL )
{
throw Exception::CpuStateShutdown(
wxsFormat( L"Invalid ELF header encountered in file:\n\t%s", elfobj.filename.c_str() ),
wxsFormat( L"Invalid ELF header, file: %s", elfobj.filename.c_str() )
throw Exception::BadStream( filename, useCdvdSource ?
wxLt("Invalid ELF file header. The CD-Rom may be damaged, or the ISO image corrupted.") :
wxLt("Invalid ELF file.")
);
}
@ -583,6 +584,6 @@ int loadElfFile(const wxString& filename)
ElfApplyPatches();
return 0;
return;
}

View File

@ -24,9 +24,9 @@ extern char args[256]; //to be filled by GUI
extern unsigned int args_ptr;
//-------------------
int loadElfFile(const wxString& filename);
u32 loadElfCRC(const char *filename);
void ElfApplyPatches();
extern void loadElfFile(const wxString& filename);
extern u32 loadElfCRC(const char *filename);
extern void ElfApplyPatches();
extern u32 ElfCRC;

View File

@ -154,7 +154,7 @@ enum GS_RINGTYPE
, GS_RINGTYPE_QUIT
};
class mtgsThreadObject : public Threading::Thread
class mtgsThreadObject : public Threading::PersistentThread
{
friend class SaveState;
@ -225,7 +225,7 @@ public:
virtual ~mtgsThreadObject();
void Start();
void Close();
void Cancel();
void Reset();
void GIFSoftReset( int mask );
@ -276,7 +276,7 @@ protected:
uint _PrepForSimplePacket();
void _FinishSimplePacket( uint future_writepos );
int Callback();
sptr ExecuteTask();
};
extern mtgsThreadObject* mtgsThread;

View File

@ -177,7 +177,7 @@ typedef void (*GIFRegHandler)(const u32* data);
static GIFRegHandler s_GSHandlers[3] = { RegHandlerSIGNAL, RegHandlerFINISH, RegHandlerLABEL };
mtgsThreadObject::mtgsThreadObject() :
Thread()
PersistentThread()
, m_RingPos( 0 )
, m_WritePos( 0 )
@ -204,7 +204,7 @@ mtgsThreadObject::mtgsThreadObject() :
void mtgsThreadObject::Start()
{
Thread::Start();
PersistentThread::Start();
// Wait for the thread to finish initialization (it runs GSopen, which can take
// some time since it's creating a new window and all), and then check for errors.
@ -217,10 +217,10 @@ void mtgsThreadObject::Start()
mtgsThreadObject::~mtgsThreadObject()
{
Close();
Cancel();
}
void mtgsThreadObject::Close()
void mtgsThreadObject::Cancel()
{
Console::WriteLn( "MTGS > Closing GS thread..." );
SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 );
@ -499,7 +499,7 @@ struct PacketTagType
#ifndef __LINUX__
extern bool renderswitch;
#endif
int mtgsThreadObject::Callback()
sptr mtgsThreadObject::ExecuteTask()
{
Console::WriteLn("MTGS > Thread Started, Opening GS Plugin...");

View File

@ -805,7 +805,7 @@ void memReset()
wxString Bios( g_Conf->FullpathToBios() );
long filesize = Path::GetFileSize( Bios );
if( filesize <= 0 )
if( filesize > 0 )
{
wxFile fp( Bios.c_str() );
fp.Read( PS2MEM_ROM, min( (long)Ps2MemSize::Rom, filesize ) );
@ -813,7 +813,14 @@ void memReset()
else
{
// Translated: Bios file not found or not specified ... A bios is required for Pcsx2 to run!
throw Exception::FileNotFound( Bios, wxLt("Bios not found") );
throw Exception::FileNotFound( Bios,
L"Configured Bios file does not exist",
pxE( ".Error:BiosNotFound",
L"The configured BIOS file does not exist, or no BIOS has been configured.\n\n"
L"PCSX2 requires a PS2 BIOS to run; and the BIOS *must* be obtained from an actual PS2 unit\n"
L"that you own (borrowing doesn't count). Please consult the FAQs and Guides for further instructions."
)
);
}
BiosVersion = GetBiosVersion();

View File

@ -237,6 +237,10 @@ bool IsBIOS(const wxString& filename, wxString& description)
return false; //fail quietly
}
// return value:
// 0 - Invalid or unknown disc.
// 1 - PS1 CD
// 2 - PS2 CD
int GetPS2ElfName( wxString& name )
{
int f;
@ -262,7 +266,7 @@ int GetPS2ElfName( wxString& name )
if (pos==NULL){
pos=strstr(buffer, "BOOT");
if (pos==NULL) {
Console::Error("Boot Error > This is not a PS2 game!");
Console::Error("Boot failed: This is not a Playstation or PS2 game!");
return 0;
}
return 1;
@ -453,7 +457,7 @@ void ProcessFKeys(int fkey, struct KeyModifiers *keymod)
wxsFormat( L"Error! Could not load from saveslot %d\n", StatesC ) + ex.LogMessage(),
// translated message:
wxsFormat( L"Error loading saveslot %d. Emulator reset.", StatesC )
wxsFormat( _("Error loading saveslot %d. Emulator reset."), StatesC )
);
}
break;

View File

@ -76,7 +76,6 @@ void Pcsx2Config::CpuOptions::LoadSave( IniInterface& ini )
IniBitBool( fpuFullMode, false );
Recompiler.LoadSave( ini );
Profiler.LoadSave( ini );
ini.SetPath( L".." );
}
@ -112,6 +111,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini )
Cpu.LoadSave( ini );
Video.LoadSave( ini );
Gamefixes.LoadSave( ini );
Profiler.LoadSave( ini );
ini.SetPath( L".." );
ini.Flush();

View File

@ -720,14 +720,7 @@ void InitPlugins()
return 0;*/
}
// ----------------------------------------------------------------------------
// Opens all plugins and initializes the CDVD plugin to use the given filename. If the filename is null
// then the cdvd plugin uses whatever file it has been configured to use. If plugin have not been
// initialized by an explicit call to InitializePlugins, this method will do so for you.
//
// fixme: the cdvd filename really should be passed to the cdvd plugin as a separate API call. >_<
//
void OpenPlugins(const char* cdvdFilename)
void OpenPlugins()
{
/*if (!plugins_initialized)
{

View File

@ -113,7 +113,7 @@ extern PluginManager* g_plugins;
void LoadPlugins();
void ReleasePlugins();
void OpenPlugins(const char* pTitleFilename);
void OpenPlugins();
void ClosePlugins( bool closegs );
void CloseGS();

View File

@ -47,7 +47,7 @@ PCSX2_ALIGNED16(fpuRegisters fpuRegs);
PCSX2_ALIGNED16(tlbs tlb[48]);
R5900cpu *Cpu = NULL;
u32 bExecBIOS = 0; // set if the BIOS has already been executed
bool g_ExecBiosHack = false; // set if the BIOS has already been executed
static bool cpuIsInitialized = false;
static const uint eeWaitCycles = 3072;
@ -556,21 +556,27 @@ __forceinline void cpuTestHwInts() {
// memory and hardware. It forcefully breaks execution when the stub is finished, prior
// to the PS2 logos being displayed. This allows us to "shortcut" right into a game
// without having to wait through the logos or endure game/bios localization checks.
//
// Use of this function must be followed by the proper injection of the elf header's code
// execution entry point into cpuRegs.pc. Failure to modify cpuRegs.pc will result in the
// bios continuing its normal unimpeeded splashscreen execution.
//
void cpuExecuteBios()
{
// Set the video mode to user's default request:
gsSetRegionMode( (GS_RegionMode)EmuConfig.Video.DefaultRegionMode );
Console::Notice( "* PCSX2 *: ExecuteBios" );
Console::Status( "Executing Bios Stub..." );
bExecBIOS = TRUE;
while (cpuRegs.pc != 0x00200008 &&
cpuRegs.pc != 0x00100008) {
g_ExecBiosHack = true;
while( cpuRegs.pc != 0x00200008 &&
cpuRegs.pc != 0x00100008 )
{
g_nextBranchCycle = cpuRegs.cycle;
Cpu->ExecuteBlock();
}
g_ExecBiosHack = false;
bExecBIOS = FALSE;
// {
// FILE* f = fopen("eebios.bin", "wb");
// fwrite(PSM(0x80000000), 0x100000, 1, f);
@ -586,12 +592,12 @@ void cpuExecuteBios()
// REC_CLEARM(0x00100008);
// REC_CLEARM(cpuRegs.pc);
// Reset the EErecs here, because the bios generates "slow" blocks that have hacky
// bBiosEnd checks in them and stuff. This deletes them so that the recs replace them
// Reset the EErecs here, because the bios generates "slow" blocks that have
// g_ExecBiosHack checks in them. This deletes them so that the recs replace them
// with new faster versions:
Cpu->Reset();
Console::Notice("* PCSX2 *: ExecuteBios Complete");
Console::Notice("Execute Bios Stub Complete");
//GSprintf(5, "PCSX2 " PCSX2_VERSION "\nExecuteBios Complete\n");
}

View File

@ -28,7 +28,7 @@ extern const char* const bios[256];
extern s32 EEsCycle;
extern u32 EEoCycle;
extern u32 bExecBIOS;
extern bool g_ExecBiosHack;
union GPR_reg { // Declare union type GPR register
u64 UD[2]; //128 bits

View File

@ -80,7 +80,7 @@ namespace StateRecovery {
void Recover()
{
// Just in case they weren't initialized earlier (no harm in calling this multiple times)
OpenPlugins(NULL);
OpenPlugins();
if( g_RecoveryState != NULL )
{

View File

@ -48,7 +48,7 @@ static void _loadStateOrExcept( const wxString& file )
// Make sure the cpu and plugins are ready to be state-ified!
cpuReset();
OpenPlugins( NULL );
OpenPlugins();
joe.FreezeAll();

View File

@ -33,7 +33,7 @@
using namespace std;
Pcsx2Config EmuConfig = {0};
Pcsx2Config EmuConfig;
// disable all session overrides by default...
SessionOverrideFlags g_Session = {false};
@ -334,54 +334,6 @@ void SysEndExecution()
g_ReturnToGui = true;
}
// Runs an ELF image directly (ISO or ELF program or BIN)
// Used by Run::FromCD, and Run->Execute when no active emulation state is present.
// elf_file - if NULL, the CDVD plugin is queried for the ELF file.
// use_bios - forces the game to boot through the PS2 bios, instead of bypassing it.
void SysPrepareExecution( const wxString& elf_file, bool use_bios )
{
if( !g_EmulationInProgress )
{
try
{
cpuReset();
}
catch( Exception::BaseException& ex )
{
Msgbox::Alert( ex.DisplayMessage() );
return;
}
//g_Startup.BootMode = (elf_file) ? BootMode_Elf : BootMode_Normal;
OpenPlugins(NULL);
if( elf_file.IsEmpty() )
{
if( !StateRecovery::HasState() )
{
// Not recovering a state, so need to execute the bios and load the ELF information.
// (note: gsRecoveries are done from ExecuteCpu)
wxString ename;
if( !use_bios )
GetPS2ElfName( ename );
loadElfFile( ename );
}
}
else
{
// Custom ELF specified (not using CDVD).
// Run the BIOS and load the ELF.
loadElfFile( elf_file );
}
}
StateRecovery::Recover();
HostGui::BeginExecution();
}
void SysRestorableReset()
{
if( !g_EmulationInProgress ) return;

View File

@ -35,8 +35,7 @@ extern void SysShutdownMem();
extern void SysRestorableReset(); // Saves the current emulation state prior to spu reset.
extern void SysClearExecutionCache(); // clears recompiled execution caches!
extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end.
extern void SysPrepareExecution( const wxString& elf_file, bool use_bios=false );
extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end.
// initiates high-speed execution of the emulation state. This function is currently
// designed to be run from an event loop, but will eventually be re-tooled with threading
@ -82,6 +81,8 @@ extern void vSyncDebugStuff( uint frame );
//
namespace Msgbox
{
extern void OnEvent( wxCommandEvent& evt );
// Pops up an alert Dialog Box with a singular "OK" button.
// Always returns false. Replacement for SysMessage.
extern bool Alert( const wxString& text );
@ -91,3 +92,4 @@ namespace Msgbox
extern bool OkCancel( const wxString& text );
}
DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 );

View File

@ -45,11 +45,11 @@ static const bool EnableThreadedLoggingTest = false; //true;
// ConsoleThreadTest -- useful class for unit testing the thread safety and general performance
// of the console logger.
//
class ConsoleTestThread : public Thread
class ConsoleTestThread : public PersistentThread
{
protected:
volatile bool m_done;
int Callback();
sptr ExecuteTask();
public:
ConsoleTestThread() :
@ -275,6 +275,7 @@ public:
protected:
void ReadUserModeSettings();
bool TryOpenConfigCwd();
void OnMessageBox( wxCommandEvent& evt );
};
DECLARE_APP(Pcsx2App)

View File

@ -45,7 +45,7 @@ DEFINE_EVENT_TYPE(wxEVT_SemaphoreWait);
using Console::Colors;
// ----------------------------------------------------------------------------
int ConsoleTestThread::Callback()
sptr ConsoleTestThread::ExecuteTask()
{
static int numtrack = 0;
@ -602,17 +602,72 @@ namespace Console
}
}
#define wxEVT_BOX_ALERT 78
using namespace Threading;
DEFINE_EVENT_TYPE( pxEVT_MSGBOX );
namespace Msgbox
{
struct InstanceData
{
Semaphore WaitForMe;
int result;
InstanceData() :
WaitForMe(), result( 0 )
{
}
};
// parameters:
// flags - messagebox type flags, such as wxOK, wxCANCEL, etc.
//
static int ThreadedMessageBox( int flags, const wxString& text )
{
// must pass the message to the main gui thread, and then stall this thread, to avoid
// threaded chaos where our thread keeps running while the popup is awaiting input.
InstanceData instdat;
wxCommandEvent tevt( pxEVT_MSGBOX );
tevt.SetString( text );
tevt.SetClientData( &instdat );
tevt.SetExtraLong( flags );
wxGetApp().AddPendingEvent( tevt );
instdat.WaitForMe.WaitNoCancel(); // Important! disable cancellation since we're using local stack vars.
return instdat.result;
}
void OnEvent( wxCommandEvent& evt )
{
// Must be called from the GUI thread ONLY.
wxASSERT( wxThread::IsMain() );
int result = Alert( evt.GetString() );
InstanceData* instdat = (InstanceData*)evt.GetClientData();
instdat->result = result;
instdat->WaitForMe.Post();
}
bool Alert( const wxString& text )
{
wxMessageBox( text, L"Pcsx2 Message", wxOK, wxGetApp().GetTopWindow() );
if( wxThread::IsMain() )
wxMessageBox( text, L"Pcsx2 Message", wxOK, wxGetApp().GetTopWindow() );
else
ThreadedMessageBox( wxOK, text );
return false;
}
bool OkCancel( const wxString& text )
{
int result = wxMessageBox( text, L"Pcsx2 Message", wxOK | wxCANCEL, wxGetApp().GetTopWindow() );
return result == wxOK;
if( wxThread::IsMain() )
{
return wxOK == wxMessageBox( text, L"Pcsx2 Message", wxOK | wxCANCEL, wxGetApp().GetTopWindow() );
}
else
{
return wxOK == ThreadedMessageBox( wxOK | wxCANCEL, text );
}
}
}

View File

@ -17,7 +17,7 @@
*/
#include "PrecompiledHeader.h"
#include "App.h"
#include "Mainframe.h"
// This API is likely obsolete for the most part, so I've just included a few dummies
// to keep things compiling until I can get to the point of tying up loose ends.
@ -44,6 +44,8 @@ namespace HostGui
void BeginExecution()
{
wxASSERT( g_EmuThread != NULL );
g_EmuThread->Resume();
}
void __fastcall KeyEvent( keyEvent* ev )

View File

@ -167,8 +167,7 @@ void MainEmuFrame::ConnectMenus()
ConnectMenu( Menu_RunELF, Menu_OpenELF_Click );
ConnectMenu( Menu_Run_Exit, Menu_Exit_Click );
ConnectMenu( Menu_SuspendExec, Menu_Suspend_Click );
ConnectMenu( Menu_ResumeExec, Menu_Resume_Click );
ConnectMenu( Menu_PauseExec, Menu_Pause_Click );
ConnectMenu( Menu_Reset, Menu_Reset_Click );
ConnectMenu( Menu_State_LoadOther, Menu_LoadStateOther_Click );
@ -224,7 +223,9 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
m_LoadStatesSubmenu( *MakeStatesSubMenu( Menu_State_Load01 ) ),
m_SaveStatesSubmenu( *MakeStatesSubMenu( Menu_State_Save01 ) ),
m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, Menu_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) )
m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, Menu_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) ),
m_IsPaused( false )
{
// ------------------------------------------------------------------------
// Initial menubar setup. This needs to be done first so that the menu bar's visible size
@ -275,15 +276,14 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
m_menuRun.Append(Menu_RunIso, _("Run ISO"), MakeIsoMenu() );
m_menuRun.Append(Menu_BootCDVD, _("Run CDVD"), MakeCdvdMenu() );
m_menuRun.Append(Menu_RunWithoutDisc,_("Run without Disc"), _("Use this to access the PS2 system configuration menu"));
m_menuRun.Append(Menu_RunELF, _("Run ELF File..."), _("For running raw PS2 binaries."));
m_menuRun.Append(Menu_SkipBiosToggle,_("ELF Injection Hack"), _("Skips PS2 splash screens when booting from Iso or CDVD media"));
m_menuRun.AppendSeparator();
m_menuRun.Append(Menu_SkipBiosToggle,_("Skip Bios on Boot"), _("Enable this to skip PS2 bootup screens (may hurt compat)"));
m_menuRun.Append(Menu_RunWithoutDisc,_("Boot without Disc"), _("Use this to access the PS2 system configuration menu"));
m_menuRun.Append(Menu_RunELF, _("Run ELF File..."), _("For running raw binaries"));
m_menuRun.AppendSeparator();
m_menuRun.Append(Menu_SuspendExec, _("Suspend"), _("Stops emulation dead in its tracks"));
m_menuRun.Append(Menu_ResumeExec, _("Resume"), _("Resumes suspended emulation"));
m_menuRun.Append(Menu_PauseExec, _("Pause"), _("Stops emulation dead in its tracks"));
m_menuRun.Append(Menu_States, _("States"), MakeStatesMenu(), wxEmptyString);
m_menuRun.Append(Menu_Reset, _("Reset"), _("Resets emulation state and reloads plugins"));
@ -337,4 +337,3 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
Connect( wxEVT_MOVE, wxMoveEventHandler (MainEmuFrame::OnMoveAround) );
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MainEmuFrame::OnCloseWindow) );
}

View File

@ -23,6 +23,9 @@
#include <wx/docview.h>
#include "App.h"
#include "PS2/CoreEmuThread.h"
extern CoreEmuThread* g_EmuThread;
//////////////////////////////////////////////////////////////////////////////////////////
//
@ -50,8 +53,7 @@ protected:
Menu_RunELF,
Menu_SkipBiosToggle, // enables the Bios Skip speedhack
Menu_EnableSkipBios, // check marked menu that toggles Skip Bios boot feature.
Menu_SuspendExec, // suspends active emulation
Menu_ResumeExec, // restores active emulation
Menu_PauseExec, // suspends/resumes active emulation
Menu_Reset, // Issues a complete reset.
Menu_States, // Opens states submenu
Menu_Run_Exit = wxID_EXIT,
@ -134,6 +136,8 @@ protected:
wxMenuItem& m_MenuItem_Console;
bool m_IsPaused;
// ------------------------------------------------------------------------
// MainEmuFrame Constructors and Member Methods
// ------------------------------------------------------------------------
@ -142,6 +146,8 @@ public:
MainEmuFrame(wxWindow* parent, const wxString& title);
void OnLogBoxHidden();
bool IsPaused() const { return m_IsPaused; }
protected:
void InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf );
@ -160,8 +166,7 @@ protected:
void Menu_SaveStateOther_Click(wxCommandEvent &event);
void Menu_Exit_Click(wxCommandEvent &event);
void Menu_Suspend_Click(wxCommandEvent &event);
void Menu_Resume_Click(wxCommandEvent &event);
void Menu_Pause_Click(wxCommandEvent &event);
void Menu_Reset_Click(wxCommandEvent &event);
void Menu_Debug_Open_Click(wxCommandEvent &event);

View File

@ -17,6 +17,7 @@
*/
#include "PrecompiledHeader.h"
#include "HostGui.h"
#include "CDVD/CDVD.h"
#include "MainFrame.h"
@ -37,20 +38,63 @@ static const wxChar* isoFilterTypes =
void MainEmuFrame::Menu_RunIso_Click(wxCommandEvent &event)
{
g_EmuThread->Suspend();
Console::Status( L"Default Folder: " + g_Conf->Folders.RunIso.ToString() );
wxFileDialog ctrl( this, _("Run PS2 Iso..."), g_Conf->Folders.RunIso.ToString(), wxEmptyString,
isoFilterTypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
if( ctrl.ShowModal() == wxID_CANCEL ) return;
g_Conf->Folders.RunIso = ctrl.GetPath();
//g_Conf->Save();
if( EmuConfig.SkipBiosSplash )
{
// Fetch the ELF filename and CD type from the CDVD provider.
wxString ename( ctrl.GetFilename() );
int result = GetPS2ElfName( ename );
g_EmuThread->SetElfFile( wxEmptyString );
switch( result )
{
case 0:
Msgbox::Alert( _("Boot failed: CDVD image is not a PS1 or PS2 game.") );
return;
case 1:
Msgbox::Alert( _("Boot failed: PCSX2 does not support emulation of PS1 games.") );
return;
case 2:
// PS2 game. Valid!
g_EmuThread->SetElfFile( ename );
break;
}
}
}
void MainEmuFrame::Menu_RunWithoutDisc_Click(wxCommandEvent &event)
{
if( g_EmuThread->IsRunning() )
{
g_EmuThread->Suspend();
// [TODO] : Add one of 'dems checkboxes that read like "[x] don't show this stupid shit again, kthx."
bool result = Msgbox::OkCancel( pxE( ".Popup:ConfirmEmuReset", L"This will reset the emulator and your current emulation session will be lost. Are you sure?") );
if( !result )
{
if( !IsPaused() )
g_EmuThread->Resume();
return;
}
}
g_EmuThread->Reset();
CDVDsys_ChangeSource( CDVDsrc_NoDisc );
SysPrepareExecution( wxEmptyString, true );
g_EmuThread->Resume();
//HostGui::BeginExecution();
}
void MainEmuFrame::Menu_IsoRecent_Click(wxCommandEvent &event)
@ -76,11 +120,7 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
Close();
}
void MainEmuFrame::Menu_Suspend_Click(wxCommandEvent &event)
{
}
void MainEmuFrame::Menu_Resume_Click(wxCommandEvent &event)
void MainEmuFrame::Menu_Pause_Click(wxCommandEvent &event)
{
}

View File

@ -306,7 +306,7 @@ namespace Panels
}
};
class EnumThread : public Threading::Thread
class EnumThread : public Threading::PersistentThread
{
public:
EnumeratedPluginInfo* Results; // array of plugin results.
@ -317,10 +317,10 @@ namespace Panels
public:
virtual ~EnumThread();
EnumThread( PluginSelectorPanel& master );
void Close();
void Cancel();
protected:
int Callback();
sptr ExecuteTask();
};
// This panel contains all of the plugin combo boxes. We stick them

View File

@ -337,7 +337,7 @@ void Panels::PluginSelectorPanel::OnProgress( wxCommandEvent& evt )
// EnumThread Method Implementations
Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master ) :
Thread()
PersistentThread()
, Results( new EnumeratedPluginInfo[master.FileCount()] )
, m_master( master )
, m_cancel( false )
@ -347,17 +347,17 @@ Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master
Panels::PluginSelectorPanel::EnumThread::~EnumThread()
{
safe_delete_array( Results );
Close();
Cancel();
}
void Panels::PluginSelectorPanel::EnumThread::Close()
void Panels::PluginSelectorPanel::EnumThread::Cancel()
{
m_cancel = true;
Threading::Sleep( 1 );
Thread::Close();
PersistentThread::Cancel();
}
int Panels::PluginSelectorPanel::EnumThread::Callback()
sptr Panels::PluginSelectorPanel::EnumThread::ExecuteTask()
{
for( int curidx=0; curidx < m_master.FileCount() && !m_cancel; ++curidx )
{

View File

@ -30,11 +30,12 @@ IMPLEMENT_APP(Pcsx2App)
AppConfig* g_Conf = NULL;
wxFileHistory* g_RecentIsoList = NULL;
CoreEmuThread* g_EmuThread = NULL;
namespace Exception
{
// --------------------------------------------------------------------------
// Exception used to perfom an "errorless" termination of the app during OnInit
// Exception used to perform an "errorless" termination of the app during OnInit
// procedures. This happens when a user cancels out of startup prompts/wizards.
//
class StartupAborted : public BaseException
@ -166,6 +167,7 @@ bool Pcsx2App::OnInit()
wxApp::OnInit();
g_Conf = new AppConfig();
g_EmuThread = new CoreEmuThread();
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
@ -231,10 +233,17 @@ bool Pcsx2App::OnInit()
{
Dialogs::ConfigurationDialog( m_MainFrame ).ShowModal();
}*/
Connect( pxEVT_MSGBOX, wxCommandEventHandler( Pcsx2App::OnMessageBox ) );
return true;
}
void Pcsx2App::OnMessageBox( wxCommandEvent& evt )
{
Msgbox::OnEvent( evt );
}
// 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
// to handle window closures)

212
pcsx2/ps2/CoreEmuThread.cpp Normal file
View File

@ -0,0 +1,212 @@
/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2009 Pcsx2 Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "PrecompiledHeader.h"
#include "System.h"
#include "SaveState.h"
#include "ElfHeader.h"
#include "Plugins.h"
#include "CoreEmuThread.h"
#include "R5900.h"
#include "R3000A.h"
#include "VUmicro.h"
sptr CoreEmuThread::ExecuteTask()
{
while( !m_Done && (m_ExecMode != ExecMode_Running) )
{
m_ResumeEvent.Wait();
}
try
{
cpuReset();
SysClearExecutionCache();
OpenPlugins();
if( StateRecovery::HasState() )
{
// 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.
StateRecovery::Recover();
}
else
{
ScopedLock lock( m_lock_elf_file );
if( !m_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( m_elf_file );
}
}
}
catch( Exception::BaseException& ex )
{
Msgbox::Alert( ex.DisplayMessage() );
}
StateCheck();
return 0;
}
void CoreEmuThread::StateCheck()
{
{
ScopedLock locker( m_lock_ExecMode );
switch( m_ExecMode )
{
case ExecMode_Idle:
// threads should never have an idle execution state set while the
// thread is in any way active or alive.
DevAssert( false, "Invalid execution state detected." );
break;
// These are not the case statements you're looking for. Move along.
case ExecMode_Running: break;
case ExecMode_Suspended: break;
case ExecMode_Suspending:
m_ExecMode = ExecMode_Suspended;
m_SuspendEvent.Post();
break;
}
}
while( (m_ExecMode == ExecMode_Suspended) && !m_Done )
{
m_ResumeEvent.Wait();
}
}
void CoreEmuThread::Start()
{
if( IsRunning() ) return;
m_running = false;
m_ExecMode = ExecMode_Idle;
m_Done = false;
m_resetProfilers = false;
m_resetRecompilers = false;
m_elf_file = wxEmptyString;
m_ResumeEvent.Reset();
m_SuspendEvent.Reset();
PersistentThread::Start();
pthread_detach( m_thread );
}
void CoreEmuThread::Reset()
{
Cancel();
StateRecovery::Clear();
}
// Resumes the core execution state, or does nothing is the core is already running. If
// settings were changed, resets will be performed as needed and emulation state resumed from
// memory savestates.
void CoreEmuThread::Resume()
{
Start();
{
ScopedLock locker( m_lock_ExecMode );
if( m_ExecMode == ExecMode_Running )
return;
if( m_ExecMode == ExecMode_Suspending )
{
// if there are resets to be done, then we need to make sure and wait for the
// emuThread to enter a fully suspended state before continuing...
if( m_resetRecompilers || m_resetProfilers )
{
locker.Unlock(); // no deadlocks please, thanks. :)
m_SuspendEvent.Wait();
}
else
{
m_ExecMode = ExecMode_Running;
return;
}
}
DevAssert( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Idle),
"EmuCoreThread is not in a suspended or idle state? wtf!" );
}
if( m_resetRecompilers || m_resetProfilers )
{
SysClearExecutionCache();
m_resetRecompilers = false;
m_resetProfilers = false;
}
m_ExecMode = ExecMode_Running;
m_ResumeEvent.Post();
}
// Pauses the emulation state at the next PS2 vsync, and returns control to the calling
// thread; or does nothing if the core is already suspended. Calling this thread from the
// Core thread will result in deadlock.
//
// Parameters:
// isNonblocking - if set to true then the function will not block for emulation suspension.
// Defaults to false if parameter is not specified. Performing non-blocking suspension
// is mostly useful for starting certain non-Emu related gui activities (improves gui
// responsiveness).
//
void CoreEmuThread::Suspend( bool isBlocking )
{
{
ScopedLock locker( m_lock_ExecMode );
if( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Idle) )
return;
if( m_ExecMode == ExecMode_Running )
m_ExecMode = ExecMode_Suspending;
DevAssert( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspended..." );
}
m_SuspendEvent.Wait();
}
// 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.
void CoreEmuThread::ApplySettings( const Pcsx2Config& src )
{
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
EmuConfig = src;
}

86
pcsx2/ps2/CoreEmuThread.h Normal file
View File

@ -0,0 +1,86 @@
/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2009 Pcsx2 Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#pragma once
#include "Utilities/Threading.h"
using namespace Threading;
/////////////////////////////////////////////////////////////////////////////////////////
// CoreEmuThread
//
class CoreEmuThread : public PersistentThread
{
public:
enum ExecutionMode
{
ExecMode_Idle,
ExecMode_Running,
ExecMode_Suspending,
ExecMode_Suspended
};
protected:
volatile ExecutionMode m_ExecMode;
volatile bool m_Done;
Semaphore m_ResumeEvent;
Semaphore m_SuspendEvent;
bool m_resetRecompilers;
bool m_resetProfilers;
wxString m_elf_file;
MutexLock m_lock_elf_file;
MutexLock m_lock_ExecMode;
public:
CoreEmuThread() :
m_ExecMode( ExecMode_Idle )
, m_Done( false )
, m_ResumeEvent()
, m_SuspendEvent()
, m_resetRecompilers( false )
, m_resetProfilers( false )
, m_elf_file()
, m_lock_elf_file()
, m_lock_ExecMode()
{
}
void SetElfFile( const wxString& text )
{
ScopedLock lock( m_lock_elf_file );
m_elf_file = text;
}
void Start();
void Reset();
bool IsSuspended() const { return (m_ExecMode == ExecMode_Suspended); }
void Suspend( bool isBlocking = true );
void Resume();
void ApplySettings( const Pcsx2Config& src );
protected:
sptr ExecuteTask();
void StateCheck();
};

View File

@ -262,62 +262,6 @@
<Filter
Name="Misc"
>
<File
RelativePath="..\..\AsciiString.cpp"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Devel|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\AsciiString.h"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCustomBuildTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Devel|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCustomBuildTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCustomBuildTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\Dump.cpp"
>
@ -1098,6 +1042,14 @@
RelativePath="..\..\x86\BaseblockEx.h"
>
</File>
<File
RelativePath="..\..\ps2\CoreEmuThread.cpp"
>
</File>
<File
RelativePath="..\..\ps2\CoreEmuThread.h"
>
</File>
<File
RelativePath="..\..\MemoryCard.cpp"
>
@ -1974,10 +1926,6 @@
RelativePath="..\..\gui\i18n.cpp"
>
</File>
<File
RelativePath="..\..\gui\i18n.h"
>
</File>
<File
RelativePath="..\..\gui\IniInterface.cpp"
>

View File

@ -1043,7 +1043,7 @@ static u32 eeScaleBlockCycles()
// setting "branch = 2";
static void iBranchTest(u32 newpc, bool noDispatch)
{
if( bExecBIOS ) CheckForBIOSEnd();
if( g_ExecBiosHack ) CheckForBIOSEnd();
// Check the Event scheduler if our "cycle target" has been reached.
// Equiv code to: