Mostly-new host exception system (host meaning the C++ / SEH exceptions, not the VM's PS2/MIPS exceptions). Main purpose is to make specifying diagnostic and end-user messages more sane. Secondary goal was to remove the need for C++ multiple and virtual inheritance, which are buggy in MSVC still, and problematic even when they aren't buggy.

I also re-implemented R5900 runtime exception handling for TLB Miss and such (devbuilds only, for now).

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3335 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-06-28 18:03:54 +00:00
parent f058e38f5b
commit 1c7fc3e176
60 changed files with 827 additions and 774 deletions

View File

@ -122,7 +122,7 @@ extern pxDoAssertFnType* pxDoAssert;
# define pxAssertDev(cond, msg) pxAssertRel(cond, msg) # define pxAssertDev(cond, msg) pxAssertRel(cond, msg)
# define pxAssumeMsg(cond, msg) (__assume(cond)) # define pxAssumeMsg(cond, msg) (__assume(cond))
# define pxAssumeDev(cond, msg) pxAssumeMsg(cond, msg) # define pxAssumeDev(cond, msg) pxAssumeRel(cond, msg)
# define pxFail(msg) (__assume(false)) # define pxFail(msg) (__assume(false))
# define pxFailDev(msg) pxAssumeDev(false, msg) # define pxFailDev(msg) pxAssumeDev(false, msg)

View File

@ -108,6 +108,30 @@ static const pxEnumEnd_t pxEnumEnd = {};
classname& operator=(const classname&) classname& operator=(const classname&)
#endif #endif
// --------------------------------------------------------------------------------------
// ScopedBool - Makes sure a boolean is set back to FALSE when current scope is left
// --------------------------------------------------------------------------------------
// Exception-safe way of tracking entry and exit of various functions of execution zones.
//
class ScopedBool
{
protected:
bool* m_boolme;
public:
ScopedBool(bool& boolme)
{
boolme = true;
m_boolme = &boolme;
}
~ScopedBool() throw()
{
m_boolme = false;
}
};
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// macro provided for tagging translation strings, without actually running them through the // macro provided for tagging translation strings, without actually running them through the
// translator (which the _() does automatically, and sometimes we don't want that). This is // translator (which the _() does automatically, and sometimes we don't want that). This is

View File

@ -66,7 +66,6 @@ namespace Exception
protected: protected:
wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred! wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred! wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
wxString m_stacktrace; // contains the stack trace string dump (unimplemented)
public: public:
virtual ~BaseException() throw()=0; // the =0; syntax forces this class into "abstract" mode. virtual ~BaseException() throw()=0; // the =0; syntax forces this class into "abstract" mode.
@ -77,23 +76,20 @@ namespace Exception
wxString& DiagMsg() { return m_message_diag; } wxString& DiagMsg() { return m_message_diag; }
wxString& UserMsg() { return m_message_user; } wxString& UserMsg() { return m_message_user; }
BaseException& SetBothMsgs( const char* msg_diag );
BaseException& SetDiagMsg( const wxString& msg_diag );
BaseException& SetUserMsg( const wxString& msg_user );
// Returns a message suitable for diagnostic / logging purposes. // Returns a message suitable for diagnostic / logging purposes.
// This message is always in English, and includes a full stack trace. // This message is always in English, and includes a full stack trace.
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
// Returns a message suitable for end-user display. // Returns a message suitable for end-user display.
// This message is usually meant for display in a user popup or such. // This message is usually meant for display in a user popup or such.
virtual wxString FormatDisplayMessage() const { return m_message_user; } virtual wxString FormatDisplayMessage() const;
virtual void Rethrow() const=0; virtual void Rethrow() const=0;
virtual BaseException* Clone() const=0; virtual BaseException* Clone() const=0;
protected:
// Construction using two pre-formatted pre-translated messages
void InitBaseEx( const wxString& msg_eng, const wxString& msg_xlt );
// Construction using one translation key.
void InitBaseEx( const char* msg_eng );
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -118,6 +114,9 @@ namespace Exception
virtual u32 GetPc() const=0; virtual u32 GetPc() const=0;
virtual bool IsDelaySlot() const=0; virtual bool IsDelaySlot() const=0;
virtual wxString Message() const { return m_message; } virtual wxString Message() const { return m_message; }
virtual void Rethrow() const=0;
virtual Ps2Generic* Clone() const=0;
}; };
// Some helper macros for defining the standard constructors of internationalized constructors // Some helper macros for defining the standard constructors of internationalized constructors
@ -129,46 +128,44 @@ namespace Exception
// it will be optionally translated. // it will be optionally translated.
// //
// BUGZ?? I'd rather use 'classname' on the Clone() prototype, but for some reason it generates // BUGZ?? I'd rather use 'classname' on the Clone() prototype, but for some reason it generates
// ambiguity errors on virtual inheritence (it really shouldn't!). So I have to force it to the // ambiguity errors on virtual inheritance (it really shouldn't!). So I have to force it to the
// BaseException base class. Not sure if this is Stupid Standard Tricks or Stupid MSVC Tricks. --air // BaseException base class. Not sure if this is Stupid Standard Tricks or Stupid MSVC Tricks. --air
// //
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010). // (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
// //
#define DEFINE_EXCEPTION_COPYTORS( classname ) \ #define DEFINE_EXCEPTION_COPYTORS( classname, parent ) \
virtual ~classname() throw() {} \ private: \
virtual void Rethrow() const { throw *this; } \ typedef parent _parent; \
virtual BaseException* Clone() const { return new classname( *this ); } public: \
// This is here because MSVC's support for covariant return types on Clone() is broken, and will
// not work with virtual class inheritance (see DEFINE_EXCEPTION_COPYTORS for details)
#define DEFINE_EXCEPTION_COPYTORS_COVARIANT( classname ) \
virtual ~classname() throw() {} \ virtual ~classname() throw() {} \
virtual void Rethrow() const { throw *this; } \ virtual void Rethrow() const { throw *this; } \
virtual classname* Clone() const { return new classname( *this ); } virtual classname* Clone() const { return new classname( *this ); }
#define DEFINE_RUNTIME_EXCEPTION( classname, defmsg ) \ #define DEFINE_EXCEPTION_MESSAGES( classname ) \
DEFINE_EXCEPTION_COPYTORS( classname ) \ public: \
\ classname& SetBothMsgs( const char* msg_diag ) { BaseException::SetBothMsgs(msg_diag); return *this; } \
explicit classname( const char* msg=defmsg ) { BaseException::InitBaseEx( msg ); } \ classname& SetDiagMsg( const wxString& msg_diag ) { m_message_diag = msg_diag; return *this; } \
explicit classname( const wxString& msg_eng, const wxString& msg_xlt ) { BaseException::InitBaseEx( msg_eng, msg_xlt); } classname& SetUserMsg( const wxString& msg_user ) { m_message_user = msg_user; return *this; }
#define DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \
DEFINE_EXCEPTION_COPYTORS( classname, parent ) \
classname() { SetDiagMsg(wxT(message)); } \
DEFINE_EXCEPTION_MESSAGES( classname )
#define DEFINE_LOGIC_EXCEPTION( classname, defmsg ) \
DEFINE_EXCEPTION_COPYTORS( classname ) \
\
explicit classname( const char* msg=defmsg ) { BaseException::InitBaseEx( msg ); } \
explicit classname( const wxString& msg_eng ) { BaseException::InitBaseEx( msg_eng, wxEmptyString ); }
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// RuntimeError - Generalized Exceptions with Recoverable Traits! // RuntimeError - Generalized Exceptions with Recoverable Traits!
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
class RuntimeError : public virtual BaseException class RuntimeError : public BaseException
{ {
DEFINE_EXCEPTION_COPYTORS( RuntimeError, BaseException )
DEFINE_EXCEPTION_MESSAGES( RuntimeError )
public: public:
bool IsSilent; bool IsSilent;
public:
DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
RuntimeError() { IsSilent = false; }
RuntimeError( const std::runtime_error& ex, const wxString& prefix=wxEmptyString ); RuntimeError( const std::runtime_error& ex, const wxString& prefix=wxEmptyString );
RuntimeError( const std::exception& ex, const wxString& prefix=wxEmptyString ); RuntimeError( const std::exception& ex, const wxString& prefix=wxEmptyString );
}; };
@ -182,18 +179,12 @@ namespace Exception
// //
// I chose to have this exception derive from RuntimeError, since if one is thrown from outside // I chose to have this exception derive from RuntimeError, since if one is thrown from outside
// an App message loop we'll still want it to be handled in a reasonably graceful manner. // an App message loop we'll still want it to be handled in a reasonably graceful manner.
class CancelEvent : public virtual RuntimeError class CancelEvent : public RuntimeError
{ {
DEFINE_RUNTIME_EXCEPTION( CancelEvent, RuntimeError, "No reason given." )
public: public:
DEFINE_EXCEPTION_COPYTORS( CancelEvent ) explicit CancelEvent( const wxString& logmsg )
explicit CancelEvent( const char* logmsg )
{
m_message_diag = fromUTF8( logmsg );
// overridden message formatters only use the diagnostic version...
}
explicit CancelEvent( const wxString& logmsg=L"No reason given." )
{ {
m_message_diag = logmsg; m_message_diag = logmsg;
// overridden message formatters only use the diagnostic version... // overridden message formatters only use the diagnostic version...
@ -203,38 +194,33 @@ namespace Exception
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
}; };
// -------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
class ObjectIsNull : public virtual CancelEvent // OutOfMemory
// ---------------------------------------------------------------------------------------
// This exception has a custom-formatted Diagnostic string. The parameter give when constructing
// the exception is a block/alloc name, which is used as a formatting parameter in the diagnostic
// output. The default diagnostic message is "Out of memory exception, while allocating the %s."
// where %s is filled in with the block name.
//
// The user string is not custom-formatted, and should contain *NO* %s tags.
//
class OutOfMemory : public RuntimeError
{ {
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxLt("Out of memory?!") )
public: public:
wxString ObjectName; wxString AllocDescription;
DEFINE_EXCEPTION_COPYTORS( ObjectIsNull ) public:
OutOfMemory( const wxString& allocdesc );
explicit ObjectIsNull( const char* objname="unspecified" )
{
m_message_diag = fromUTF8( objname );
// overridden message formatters only use the diagnostic version...
}
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
}; };
// ---------------------------------------------------------------------------------------
// OutOfMemory / InvalidOperation / InvalidArgument / ParseError
// ---------------------------------------------------------------------------------------
class OutOfMemory : public virtual RuntimeError
{
public:
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, wxLt("Out of Memory") )
};
class ParseError : public RuntimeError class ParseError : public RuntimeError
{ {
public: DEFINE_RUNTIME_EXCEPTION( ParseError, RuntimeError, "Parse error" );
DEFINE_RUNTIME_EXCEPTION( ParseError, "Parse error" );
}; };
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
@ -245,16 +231,15 @@ namespace Exception
// This exception is a specific type of OutOfMemory error that isn't "really" an out of // This exception is a specific type of OutOfMemory error that isn't "really" an out of
// memory error. More likely it's caused by a plugin or driver reserving a range of memory // memory error. More likely it's caused by a plugin or driver reserving a range of memory
// we'd really like to have access to. // we'd really like to have access to.
class VirtualMemoryMapConflict : public virtual OutOfMemory class VirtualMemoryMapConflict : public OutOfMemory
{ {
public: DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") )
DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") )
}; };
class HardwareDeficiency : public virtual RuntimeError class HardwareDeficiency : public RuntimeError
{ {
public: public:
DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") ); DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, RuntimeError, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") );
}; };
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
@ -262,51 +247,28 @@ namespace Exception
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream // Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
#define DEFINE_STREAM_EXCEPTION( classname, defmsg ) \ #define DEFINE_STREAM_EXCEPTION_ACCESSORS( classname ) \
DEFINE_EXCEPTION_COPYTORS( classname ) \ virtual classname& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \
\ virtual classname& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; }
explicit classname( const wxString& objname=wxString(), const char* msg=defmsg ) \
{ \ #define DEFINE_STREAM_EXCEPTION( classname, parent, message ) \
BaseException::InitBaseEx( msg ); \ DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \
StreamName = objname; \ classname( const wxString& filename ) { \
StreamName = filename; \
SetBothMsgs(message); \
} \ } \
explicit classname( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) \ DEFINE_STREAM_EXCEPTION_ACCESSORS( classname )
{ \
BaseException::InitBaseEx( msg_eng, msg_xlt ); \
StreamName = objname; \
} \
explicit classname( const char* objname, const char* msg=defmsg ) \
{ \
BaseException::InitBaseEx( msg ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const char* objname, const wxString& msg_eng, const wxString& msg_xlt ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_xlt ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const char* objname, const wxString& msg_eng ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_eng ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const wxString& objname, const wxString& msg_eng ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_eng ); \
StreamName = objname; \
}
// Generic stream error. Contains the name of the stream and a message. // Generic stream error. Contains the name of the stream and a message.
// This exception is usually thrown via derived classes, except in the (rare) case of a // This exception is usually thrown via derived classes, except in the (rare) case of a
// generic / unknown error. // generic / unknown error.
// //
class Stream : public virtual RuntimeError class Stream : public RuntimeError
{ {
public: DEFINE_STREAM_EXCEPTION( Stream, RuntimeError, wxLt("General file operation error.") )
wxString StreamName; // name of the stream (if applicable)
public: public:
DEFINE_STREAM_EXCEPTION( Stream, "General file operation error." ) wxString StreamName; // name of the stream (if applicable)
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
@ -316,42 +278,40 @@ namespace Exception
// connection, or anything else that would indicate a failure to read the data after the // connection, or anything else that would indicate a failure to read the data after the
// stream was successfully opened. // stream was successfully opened.
// //
class BadStream : public virtual Stream class BadStream : public Stream
{ {
public: DEFINE_STREAM_EXCEPTION( BadStream, Stream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
DEFINE_STREAM_EXCEPTION( BadStream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
}; };
// A generic exception for odd-ball stream creation errors. // A generic exception for odd-ball stream creation errors.
// //
class CannotCreateStream : public virtual Stream class CannotCreateStream : public Stream
{ {
public: DEFINE_STREAM_EXCEPTION( CannotCreateStream, Stream, wxLt("File could not be created or opened.") )
DEFINE_STREAM_EXCEPTION( CannotCreateStream, wxLt("File could not be created or opened.") )
}; };
// Exception thrown when an attempt to open a non-existent file is made. // Exception thrown when an attempt to open a non-existent file is made.
// (this exception can also mean file permissions are invalid) // (this exception can also mean file permissions are invalid)
// //
class FileNotFound : public virtual CannotCreateStream class FileNotFound : public CannotCreateStream
{ {
public: public:
DEFINE_STREAM_EXCEPTION( FileNotFound, wxLt("File not found.") ) DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream, wxLt("File not found.") )
}; };
class AccessDenied : public virtual CannotCreateStream class AccessDenied : public CannotCreateStream
{ {
public: public:
DEFINE_STREAM_EXCEPTION( AccessDenied, wxLt("Permission denied to file.") ) DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream, wxLt("Permission denied to file.") )
}; };
// EndOfStream can be used either as an error, or used just as a shortcut for manual // EndOfStream can be used either as an error, or used just as a shortcut for manual
// feof checks. // feof checks.
// //
class EndOfStream : public virtual Stream class EndOfStream : public Stream
{ {
public: public:
DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") ); DEFINE_STREAM_EXCEPTION( EndOfStream, Stream, wxLt("Unexpected end of file or stream.") );
}; };
#ifdef __WXMSW__ #ifdef __WXMSW__
@ -360,13 +320,14 @@ namespace Exception
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class WinApiError : public RuntimeError class WinApiError : public RuntimeError
{ {
DEFINE_EXCEPTION_COPYTORS( WinApiError, RuntimeError )
DEFINE_EXCEPTION_MESSAGES( WinApiError )
public: public:
int ErrorId; int ErrorId;
public: public:
DEFINE_EXCEPTION_COPYTORS( WinApiError ) WinApiError();
WinApiError( const char* msg="" );
wxString GetMsgFromWindows() const; wxString GetMsgFromWindows() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;

View File

@ -233,8 +233,8 @@ template< int Precision >
FixedInt<Precision> FixedInt<Precision>::FromString( const wxString parseFrom ) FixedInt<Precision> FixedInt<Precision>::FromString( const wxString parseFrom )
{ {
FixedInt<Precision> dest; FixedInt<Precision> dest;
if( !TryFromString( dest, parseFrom ) ) throw Exception::ParseError( if( !TryFromString( dest, parseFrom ) ) throw Exception::ParseError()
wxsFormat(L"Parse error on FixedInt<%d>::FromString", Precision), wxEmptyString .SetDiagMsg(wxsFormat(L"Parse error on FixedInt<%d>::FromString", Precision));
);
return dest; return dest;
} }

View File

@ -22,30 +22,6 @@
namespace Threading namespace Threading
{ {
// --------------------------------------------------------------------------------------
// IThread - Interface for the public access to pxThread.
// --------------------------------------------------------------------------------------
// Class usage: Can be used for allowing safe nullification of a thread handle. Rather
// than being NULL'd, the handle can be mapped to an IThread implementation which acts
// as a do-nothing placebo or an assertion generator.
//
class IThread
{
DeclareNoncopyableObject(IThread);
public:
IThread() {}
virtual ~IThread() throw() {}
virtual bool IsSelf() const { return false; }
virtual bool IsRunning() { return false; }
virtual void Start() {}
virtual void Cancel( bool isBlocking = true ) {}
virtual void Block() {}
virtual bool Detach() { return false; }
};
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ThreadDeleteEvent // ThreadDeleteEvent
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -109,7 +85,7 @@ namespace Threading
// no dependency options for ensuring correct static var initializations). Use heap // no dependency options for ensuring correct static var initializations). Use heap
// allocation to create thread objects instead. // allocation to create thread objects instead.
// //
class pxThread : public virtual IThread class pxThread
{ {
DeclareNoncopyableObject(pxThread); DeclareNoncopyableObject(pxThread);

View File

@ -93,7 +93,7 @@ protected:
m_size = initSize; m_size = initSize;
if( m_ptr == NULL ) if( m_ptr == NULL )
throw Exception::OutOfMemory(); throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initSize));
} }
virtual T* _virtual_realloc( int newsize ) virtual T* _virtual_realloc( int newsize )
@ -138,7 +138,7 @@ public:
m_size = initialSize; m_size = initialSize;
if( (initialSize != 0) && (m_ptr == NULL) ) if( (initialSize != 0) && (m_ptr == NULL) )
throw Exception::OutOfMemory(); throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initialSize));
} }
// Clears the contents of the array to zero, and frees all memory allocations. // Clears the contents of the array to zero, and frees all memory allocations.
@ -163,17 +163,10 @@ public:
m_ptr = _virtual_realloc( newsize ); m_ptr = _virtual_realloc( newsize );
if( m_ptr == NULL ) if( m_ptr == NULL )
{ throw Exception::OutOfMemory(Name +
throw Exception::OutOfMemory( wxsFormat(L" (SafeArray::ExactAlloc) [oldsize=%d] [newsize=%d]", m_size, newsize)
wxsFormat( // english (for diagnostic)
L"Out-of-memory on SafeArray block re-allocation.\n"
L"Old size: %d bytes, New size: %d bytes.",
m_size, newsize
),
// internationalized!
wxsFormat( _("Out of memory, trying to allocate %d bytes."), newsize )
); );
}
m_size = newsize; m_size = newsize;
} }
@ -262,24 +255,27 @@ public:
safe_free( m_ptr ); safe_free( m_ptr );
} }
explicit SafeList( const wxChar* name=L"Unnamed" ) : explicit SafeList( const wxChar* name=L"Unnamed" )
Name( name ) : Name( name )
, ChunkSize( DefaultChunkSize )
, m_ptr( NULL )
, m_allocsize( 0 )
, m_length( 0 )
{ {
ChunkSize = DefaultChunkSize;
m_ptr = NULL;
m_allocsize = 0;
m_length = 0;
} }
explicit SafeList( int initialSize, const wxChar* name=L"Unnamed" ) : explicit SafeList( int initialSize, const wxChar* name=L"Unnamed" )
Name( name ) : Name( name )
, ChunkSize( DefaultChunkSize )
, m_ptr( (T*)malloc( initialSize * sizeof(T) ) )
, m_allocsize( initialSize )
, m_length( 0 )
{ {
ChunkSize = DefaultChunkSize;
m_allocsize = initialSize;
m_length = 0;
m_ptr = (T*)malloc( initialSize * sizeof(T) );
if( m_ptr == NULL ) if( m_ptr == NULL )
throw Exception::OutOfMemory(); throw Exception::OutOfMemory(Name +
wxsFormat(L" (SafeList::Constructor) [length=%d]", m_length)
);
for( int i=0; i<m_allocsize; ++i ) for( int i=0; i<m_allocsize; ++i )
{ {
@ -310,18 +306,9 @@ public:
const int newalloc = blockSize + ChunkSize; const int newalloc = blockSize + ChunkSize;
m_ptr = _virtual_realloc( newalloc ); m_ptr = _virtual_realloc( newalloc );
if( m_ptr == NULL ) if( m_ptr == NULL )
{ throw Exception::OutOfMemory(Name +
throw Exception::OutOfMemory( wxsFormat(L" (SafeList::MakeRoomFor) [oldlen=%d] [newlen=%d]", m_length, blockSize)
// English Diagnostic message:
wxsFormat(
L"Out-of-memory on SafeList block re-allocation.\n"
L"Name: %s, Old size: %d bytes, New size: %d bytes",
Name.c_str(), m_allocsize, newalloc
),
wxsFormat( _("Out of memory, trying to allocate %d bytes."), newalloc )
); );
}
for( ; m_allocsize<newalloc; ++m_allocsize ) for( ; m_allocsize<newalloc; ++m_allocsize )
{ {

View File

@ -63,23 +63,30 @@ namespace Threading
namespace Exception namespace Exception
{ {
class BaseThreadError : public virtual RuntimeError class BaseThreadError : public RuntimeError
{ {
DEFINE_EXCEPTION_COPYTORS( BaseThreadError, RuntimeError )
DEFINE_EXCEPTION_MESSAGES( BaseThreadError )
public: public:
Threading::pxThread* m_thread; Threading::pxThread* m_thread;
DEFINE_EXCEPTION_COPYTORS( BaseThreadError ) protected:
BaseThreadError() {
explicit BaseThreadError( Threading::pxThread* _thread=NULL ) m_thread = NULL;
{
m_thread = _thread;
BaseException::InitBaseEx( "Unspecified thread error" );
} }
BaseThreadError( Threading::pxThread& _thread ) public:
explicit BaseThreadError( Threading::pxThread* _thread )
{
m_thread = _thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
explicit BaseThreadError( Threading::pxThread& _thread )
{ {
m_thread = &_thread; m_thread = &_thread;
BaseException::InitBaseEx( "Unspecified thread error" ); m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
} }
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
@ -89,27 +96,21 @@ namespace Exception
const Threading::pxThread& Thread() const; const Threading::pxThread& Thread() const;
}; };
class ThreadCreationError : public virtual BaseThreadError class ThreadCreationError : public BaseThreadError
{ {
public: DEFINE_EXCEPTION_COPYTORS( ThreadCreationError, BaseThreadError )
DEFINE_EXCEPTION_COPYTORS( ThreadCreationError )
explicit ThreadCreationError( Threading::pxThread* _thread=NULL, const char* msg="Creation of thread '%s' failed." ) public:
explicit ThreadCreationError( Threading::pxThread* _thread )
{ {
m_thread = _thread; m_thread = _thread;
BaseException::InitBaseEx( msg ); SetBothMsgs( "Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
} }
ThreadCreationError( Threading::pxThread& _thread, const char* msg="Creation of thread '%s' failed." ) explicit ThreadCreationError( Threading::pxThread& _thread )
{ {
m_thread = &_thread; m_thread = &_thread;
BaseException::InitBaseEx( msg ); SetBothMsgs( "Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
}
ThreadCreationError( Threading::pxThread& _thread, const wxString& msg_diag, const wxString& msg_user )
{
m_thread = &_thread;
BaseException::InitBaseEx( msg_diag, msg_user );
} }
}; };
} }

View File

@ -109,7 +109,7 @@ T* Threading::TlsVariable<T>::GetPtr() const
{ {
pthread_setspecific( m_thread_key, result = (T*)_aligned_malloc( sizeof(T), 16 ) ); pthread_setspecific( m_thread_key, result = (T*)_aligned_malloc( sizeof(T), 16 ) );
if( result == NULL ) if( result == NULL )
throw Exception::OutOfMemory( "Out of memory allocating thread local storage variable." ); throw Exception::OutOfMemory( L"Out of memory allocating thread local storage variable." );
*result = m_initval; *result = m_initval;
} }
return result; return result;

View File

@ -23,14 +23,9 @@
#include <signal.h> #include <signal.h>
#endif #endif
wxString GetEnglish( const char* msg ) static wxString GetTranslation( const char* msg )
{ {
return fromUTF8(msg); return msg ? wxGetTranslation( fromUTF8(msg) ) : wxString();
}
wxString GetTranslation( const char* msg )
{
return wxGetTranslation( fromUTF8(msg) );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -132,71 +127,91 @@ __forceinline void pxOnAssert( const DiagnosticOrigin& origin, const char* msg)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Exception Namespace Implementations (Format message handlers for general exceptions) // BaseException (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
BaseException::~BaseException() throw() {} BaseException::~BaseException() throw() {}
void BaseException::InitBaseEx( const wxString& msg_eng, const wxString& msg_xlt ) BaseException& BaseException::SetBothMsgs( const char* msg_diag )
{ {
m_message_diag = msg_eng; m_message_user = GetTranslation( msg_diag );
m_message_user = msg_xlt.IsEmpty() ? msg_eng : msg_xlt; return SetDiagMsg( fromUTF8(msg_diag) );
// Linux/GCC exception handling is still suspect (this is likely to do with GCC more
// than linux), and fails to propagate exceptions up the stack from EErec code. This
// could likely be because of the EErec using EBP. So to ensure the user at least
// gets a log of the error, we output to console here in the constructor.
#ifdef __LINUX__
//wxLogError( msg_eng.c_str() );
Console.Error( msg_eng );
#endif
} }
// given message is assumed to be a translation key, and will be stored in translated BaseException& BaseException::SetDiagMsg( const wxString& msg_diag )
// and untranslated forms.
void BaseException::InitBaseEx( const char* msg_eng )
{ {
m_message_diag = GetEnglish( msg_eng ); m_message_diag = msg_diag;
m_message_user = GetTranslation( msg_eng ); return *this;
}
#ifdef __LINUX__ BaseException& BaseException::SetUserMsg( const wxString& msg_user )
//wxLogError( m_message_diag.c_str() ); {
Console.Error( msg_eng ); m_message_user = msg_user;
#endif return *this;
} }
wxString BaseException::FormatDiagnosticMessage() const wxString BaseException::FormatDiagnosticMessage() const
{ {
return m_message_diag + L"\n\n" + m_stacktrace; return m_message_diag;
} }
// ------------------------------------------------------------------------ wxString BaseException::FormatDisplayMessage() const
{
return m_message_user.IsEmpty() ? m_message_diag : m_message_user;
}
// --------------------------------------------------------------------------------------
// Exception::RuntimeError (implementations)
// --------------------------------------------------------------------------------------
Exception::RuntimeError::RuntimeError( const std::runtime_error& ex, const wxString& prefix ) Exception::RuntimeError::RuntimeError( const std::runtime_error& ex, const wxString& prefix )
{ {
IsSilent = false;
const wxString msg( wxsFormat( L"STL Runtime Error%s: %s", const wxString msg( wxsFormat( L"STL Runtime Error%s: %s",
(prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()), (prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()),
fromUTF8( ex.what() ).c_str() fromUTF8( ex.what() ).c_str()
) ); ) );
BaseException::InitBaseEx( msg, msg ); SetDiagMsg( msg );
} }
// ------------------------------------------------------------------------
Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString& prefix ) Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString& prefix )
{ {
IsSilent = false;
const wxString msg( wxsFormat( L"STL Exception%s: %s", const wxString msg( wxsFormat( L"STL Exception%s: %s",
(prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()), (prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()),
fromUTF8( ex.what() ).c_str() fromUTF8( ex.what() ).c_str()
) ); ) );
BaseException::InitBaseEx( msg, msg ); SetDiagMsg( msg );
} }
// --------------------------------------------------------------------------------------
// Exception::OutOfMemory (implementations)
// --------------------------------------------------------------------------------------
Exception::OutOfMemory::OutOfMemory( const wxString& allocdesc )
{
AllocDescription = allocdesc;
m_message_diag = L"Out of memory exception, while allocating the %s.";
m_message_user = _("Memory allocation failure! Your system has insufficient memory or resources to meet PCSX2's lofty needs.");
}
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
{
return wxsFormat(m_message_diag, AllocDescription.c_str());
}
wxString Exception::OutOfMemory::FormatDisplayMessage() const
{
if (m_message_user.IsEmpty()) return FormatDisplayMessage();
return m_message_user + wxsFormat( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str());
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
wxString Exception::CancelEvent::FormatDiagnosticMessage() const wxString Exception::CancelEvent::FormatDiagnosticMessage() const
{ {
// FIXME: This should probably just log a single line from the stacktrace.. ?
return L"Action canceled: " + m_message_diag; return L"Action canceled: " + m_message_diag;
} }
@ -205,35 +220,20 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const
return L"Action canceled: " + m_message_diag; return L"Action canceled: " + m_message_diag;
} }
// ------------------------------------------------------------------------
wxString Exception::ObjectIsNull::FormatDiagnosticMessage() const
{
return wxsFormat(
L"reference to '%s' failed : handle is null.",
m_message_diag.c_str()
) + m_stacktrace;
}
wxString Exception::ObjectIsNull::FormatDisplayMessage() const
{
return wxsFormat(
L"reference to '%s' failed : handle is null.",
m_message_diag.c_str()
);
}
// ------------------------------------------------------------------------
wxString Exception::Stream::FormatDiagnosticMessage() const wxString Exception::Stream::FormatDiagnosticMessage() const
{ {
return wxsFormat( return wxsFormat(
L"Stream exception: %s\n\tFile/Object: %s", L"%s\n\tFile/Object: %s",
m_message_diag.c_str(), StreamName.c_str() m_message_diag.c_str(), StreamName.c_str()
) + m_stacktrace; );
} }
wxString Exception::Stream::FormatDisplayMessage() const wxString Exception::Stream::FormatDisplayMessage() const
{ {
return m_message_user + L"\n\n" + wxString retval( m_message_user );
wxsFormat( _("Name: %s"), StreamName.c_str() ); if (!StreamName.IsEmpty())
retval += L"\n\n" + wxsFormat( _("Path: %s"), StreamName.c_str() );
return retval;
} }

View File

@ -72,7 +72,7 @@ Threading::MutexRecursive::MutexRecursive() : Mutex( false )
if( _InterlockedIncrement( &_attr_refcount ) == 1 ) if( _InterlockedIncrement( &_attr_refcount ) == 1 )
{ {
if( 0 != pthread_mutexattr_init( &_attr_recursive ) ) if( 0 != pthread_mutexattr_init( &_attr_recursive ) )
throw Exception::OutOfMemory( "Out of memory error initializing the Mutex attributes for recursive mutexing." ); throw Exception::OutOfMemory(L"Recursive mutexing attributes");
pthread_mutexattr_settype( &_attr_recursive, PTHREAD_MUTEX_RECURSIVE ); pthread_mutexattr_settype( &_attr_recursive, PTHREAD_MUTEX_RECURSIVE );
} }

View File

@ -246,7 +246,7 @@ void Threading::pxThread::Start()
RethrowException(); RethrowException();
// And if the thread threw nothing of its own: // And if the thread threw nothing of its own:
throw Exception::ThreadCreationError( this, "(%s thread) Start error: created thread never posted startup semaphore." ); throw Exception::ThreadCreationError( this ).SetDiagMsg( L"Thread creation error: %s thread never posted startup semaphore." );
} }
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the // Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the

View File

@ -201,3 +201,35 @@ wxString GetOSVersionString()
return retval; return retval;
} }
// --------------------------------------------------------------------------------------
// Exception::WinApiError (implementations)
// --------------------------------------------------------------------------------------
Exception::WinApiError::WinApiError()
{
ErrorId = GetLastError();
m_message_diag = L"Unspecified Windows API error.";
}
wxString Exception::WinApiError::GetMsgFromWindows() const
{
if (!ErrorId) return L"No valid error number was assigned to this exception!";
const DWORD BUF_LEN = 2048;
TCHAR t_Msg[BUF_LEN];
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg );
return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId );
}
wxString Exception::WinApiError::FormatDisplayMessage() const
{
return m_message_user + L"\n\n" + GetMsgFromWindows();
}
wxString Exception::WinApiError::FormatDiagnosticMessage() const
{
return m_message_diag + L"\n\t" + GetMsgFromWindows();
}

View File

@ -96,12 +96,7 @@ FILE *_cdvdOpenMechaVer()
Console.Warning("MEC File Not Found , Creating Blank File"); Console.Warning("MEC File Not Found , Creating Blank File");
fd = fopen(file, "wb"); fd = fopen(file, "wb");
if (fd == NULL) if (fd == NULL)
{ throw Exception::CannotCreateStream(mecfile.GetFullPath());
Console.Error( "MEC File Creation failed!" );
throw Exception::CannotCreateStream( file );
//Msgbox::Alert( "_cdvdOpenMechaVer: Error creating %s", file);
//exit(1);
}
fputc(0x03, fd); fputc(0x03, fd);
fputc(0x06, fd); fputc(0x06, fd);
@ -136,10 +131,8 @@ FILE *_cdvdOpenNVM()
Console.Warning("NVM File Not Found , Creating Blank File"); Console.Warning("NVM File Not Found , Creating Blank File");
fd = fopen(file, "wb"); fd = fopen(file, "wb");
if (fd == NULL) if (fd == NULL)
{ throw Exception::CannotCreateStream(nvmfile.GetFullPath());
Console.Error( "NVM File Creation failed!" );
throw Exception::CannotCreateStream( file );
}
for (int i=0; i<1024; i++) fputc(0, fd); for (int i=0; i<1024; i++) fputc(0, fd);
} }
return fd; return fd;
@ -809,7 +802,7 @@ __forceinline void cdvdReadInterrupt()
// Any other value besides 0 should be considered invalid here (wtf is that wacky // Any other value besides 0 should be considered invalid here (wtf is that wacky
// plugin trying to do?) // plugin trying to do?)
jASSUME( cdvd.RErr == 0 ); pxAssume( cdvd.RErr == 0 );
} }
if (cdvdReadSector() == -1) if (cdvdReadSector() == -1)

View File

@ -94,7 +94,8 @@ IsoDirectory::IsoDirectory(SectorSource& r)
} }
if( !isValid ) if( !isValid )
throw Exception::FileNotFound( "IsoFS", "Root directory not found on ISO image." ); throw Exception::FileNotFound(L"IsoFS") // FIXME: Should report the name of the ISO here...
.SetDiagMsg(L"IsoFS could not find the root directory on the ISO image.");
DevCon.WriteLn( L"(IsoFS) Filesystem is " + FStype_ToString() ); DevCon.WriteLn( L"(IsoFS) Filesystem is " + FStype_ToString() );
Init( rootDirEntry ); Init( rootDirEntry );
@ -153,7 +154,7 @@ int IsoDirectory::GetIndexOf(const wxString& fileName) const
if(files[i].name == fileName) return i; if(files[i].name == fileName) return i;
} }
throw Exception::FileNotFound( fileName ); throw Exception::FileNotFound(fileName);
} }
const IsoFileDescriptor& IsoDirectory::GetEntry(const wxString& fileName) const const IsoFileDescriptor& IsoDirectory::GetEntry(const wxString& fileName) const

View File

@ -242,7 +242,7 @@ bool ElfObject::hasHeaders() { return (hasProgramHeaders() && hasSectionHeaders(
void ElfObject::readIso(IsoFile file) void ElfObject::readIso(IsoFile file)
{ {
int rsize = file.read(data.GetPtr(), data.GetSizeInBytes()); int rsize = file.read(data.GetPtr(), data.GetSizeInBytes());
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream( filename ); if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
} }
void ElfObject::readFile() void ElfObject::readFile()
@ -257,19 +257,19 @@ void ElfObject::readFile()
rsize = fread(data.GetPtr(), 1, data.GetSizeInBytes(), f); rsize = fread(data.GetPtr(), 1, data.GetSizeInBytes(), f);
fclose( f ); fclose( f );
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream( filename ); if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
} }
void ElfObject::checkElfSize(s64 elfsize) void ElfObject::checkElfSize(s64 elfsize)
{ {
if (elfsize > 0xfffffff) if (elfsize > 0xfffffff)
throw Exception::BadStream( filename, wxLt("Illegal ELF file size, over 2GB!") ); throw Exception::BadStream(filename).SetBothMsgs(wxLt("Illegal ELF file size over 2GB!"));
if (elfsize == -1) if (elfsize == -1)
throw Exception::BadStream( filename, wxLt("Elf file does not exist! ") ); throw Exception::BadStream(filename).SetBothMsgs(wxLt("ELF file does not exist!"));
if (elfsize == 0) if (elfsize == 0)
throw Exception::BadStream( filename, wxLt("Unexpected end of ELF file: ") ); throw Exception::BadStream(filename).SetBothMsgs(wxLt("Unexpected end of ELF file."));
} }
u32 ElfObject::getCRC() u32 ElfObject::getCRC()
@ -473,12 +473,14 @@ int GetPS2ElfName( wxString& name )
return 0; return 0;
} }
} }
catch (Exception::BadStream&) catch (Exception::BadStream& ex)
{ {
Console.Error(ex.FormatDiagnosticMessage());
return 0; // ISO error return 0; // ISO error
} }
catch( Exception::FileNotFound& ) catch( Exception::FileNotFound& ex )
{ {
Console.Warning(ex.FormatDiagnosticMessage());
return 0; // no SYSTEM.CNF, not a PS1/PS2 disc. return 0; // no SYSTEM.CNF, not a PS1/PS2 disc.
} }

View File

@ -18,6 +18,7 @@
#include "Common.h" #include "Common.h"
#include "R5900OpcodeTables.h" #include "R5900OpcodeTables.h"
#include "R5900Exceptions.h"
#include "System/SysThreads.h" #include "System/SysThreads.h"
#include "Elfheader.h" #include "Elfheader.h"
@ -419,6 +420,12 @@ static void intClear(u32 Addr, u32 Size)
static void intShutdown() { static void intShutdown() {
} }
static void intThrowException( const BaseR5900Exception& ex )
{
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
ex.Rethrow();
}
R5900cpu intCpu = R5900cpu intCpu =
{ {
intAlloc, intAlloc,
@ -429,5 +436,6 @@ R5900cpu intCpu =
intExecute, intExecute,
intCheckExecutionState, intCheckExecutionState,
intThrowException,
intClear, intClear,
}; };

View File

@ -38,7 +38,7 @@ void psxMemAlloc()
m_psxAllMem = vtlb_malloc( m_psxMemSize, 4096 ); m_psxAllMem = vtlb_malloc( m_psxMemSize, 4096 );
if( m_psxAllMem == NULL) if( m_psxAllMem == NULL)
throw Exception::OutOfMemory( "psxMemAlloc > failed allocating memory for the IOP processor." ); throw Exception::OutOfMemory( L"IOP system ram (and roms)" );
u8* curpos = m_psxAllMem; u8* curpos = m_psxAllMem;
psxM = curpos; curpos += Ps2MemSize::IopRam; psxM = curpos; curpos += Ps2MemSize::IopRam;
@ -54,8 +54,8 @@ void psxMemAlloc()
// which is performed by MemInit and PsxMemInit() // which is performed by MemInit and PsxMemInit()
void psxMemReset() void psxMemReset()
{ {
jASSUME( psxMemWLUT != NULL ); pxAssume( psxMemWLUT != NULL );
jASSUME( m_psxAllMem != NULL ); pxAssume( m_psxAllMem != NULL );
DbgCon.WriteLn( "IOP Resetting physical ram..." ); DbgCon.WriteLn( "IOP Resetting physical ram..." );

View File

@ -936,10 +936,11 @@ void SysMtgsThread::WaitForOpen()
RethrowException(); RethrowException();
// Not opened yet, and no exceptions. Weird? You decide! // Not opened yet, and no exceptions. Weird? You decide!
// TODO : implement a user confirmation to cancel the action and exit the // [TODO] : implement a user confirmation to cancel the action and exit the
// emulator forcefully, or to continue waiting on the GS. // emulator forcefully, or to continue waiting on the GS.
throw Exception::PluginOpenError( PluginId_GS, "The MTGS thread has become unresponsive while waiting for the GS plugin to open." ); throw Exception::PluginOpenError( PluginId_GS )
.SetBothMsgs(wxLt("The MTGS thread has become unresponsive while waiting for the GS plugin to open."));
} }
} }

View File

@ -639,7 +639,7 @@ void memAlloc()
m_psAllMem = vtlb_malloc( m_allMemSize, 4096 ); m_psAllMem = vtlb_malloc( m_allMemSize, 4096 );
if( m_psAllMem == NULL) if( m_psAllMem == NULL)
throw Exception::OutOfMemory( "memAlloc > failed to allocate PS2's base ram/rom/scratchpad." ); throw Exception::OutOfMemory( L"memAlloc > failed to allocate PS2's base ram/rom/scratchpad." );
u8* curpos = m_psAllMem; u8* curpos = m_psAllMem;
psM = curpos; curpos += Ps2MemSize::Base; psM = curpos; curpos += Ps2MemSize::Base;

View File

@ -617,18 +617,22 @@ PluginManager *g_plugins = NULL;
// Plugin-related Exception Implementations // Plugin-related Exception Implementations
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid, const wxString& objname, const char* eng ) Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid )
{ {
BaseException::InitBaseEx( eng );
StreamName = objname;
PluginId = pid; PluginId = pid;
m_message_diag = L"%s plugin failed to open!";
m_message_user = L"%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.";
} }
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid, const wxString& objname, Exception::PluginInitError::PluginInitError( PluginsEnum_t pid )
const wxString& eng_msg, const wxString& xlt_msg ) {
PluginId = pid;
m_message_diag = L"%s plugin initialization failed!";
m_message_user = L"%s plugin failed to initialize. Your system may have insufficient memory or resources needed.";
}
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
{ {
BaseException::InitBaseEx( eng_msg, xlt_msg );
StreamName = objname;
PluginId = pid; PluginId = pid;
} }
@ -659,7 +663,7 @@ wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const
return wxsFormat( return wxsFormat(
L"%s plugin returned an error while saving the state.\n\n", L"%s plugin returned an error while saving the state.\n\n",
tbl_PluginInfo[PluginId].shortname tbl_PluginInfo[PluginId].shortname
) + m_stacktrace; );
} }
wxString Exception::FreezePluginFailure::FormatDisplayMessage() const wxString Exception::FreezePluginFailure::FormatDisplayMessage() const
@ -673,7 +677,7 @@ wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const
return wxsFormat( return wxsFormat(
L"%s plugin returned an error while loading the state.\n\n", L"%s plugin returned an error while loading the state.\n\n",
tbl_PluginInfo[PluginId].shortname tbl_PluginInfo[PluginId].shortname
) + m_stacktrace; );
} }
wxString Exception::ThawPluginFailure::FormatDisplayMessage() const wxString Exception::ThawPluginFailure::FormatDisplayMessage() const
@ -726,17 +730,15 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
IsOpened = false; IsOpened = false;
if( Filename.IsEmpty() ) if( Filename.IsEmpty() )
throw Exception::PluginInitError( pid, "Empty plugin filename." ); throw Exception::PluginInitError( pid ).SetDiagMsg( L"Empty plugin filename" );
if( !wxFile::Exists( Filename ) ) if( !wxFile::Exists( Filename ) )
throw Exception::PluginLoadError( pid, srcfile, throw Exception::PluginLoadError( pid ).SetStreamName(srcfile)
wxLt("The configured %s plugin file was not found") .SetBothMsgs(wxLt("The configured %s plugin file was not found"));
);
if( !Lib.Load( Filename ) ) if( !Lib.Load( Filename ) )
throw Exception::PluginLoadError( pid, Filename, throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
wxLt("The configured %s plugin file is not a valid dynamic library") .SetBothMsgs(wxLt("The configured %s plugin file is not a valid dynamic library"));
);
// Try to enumerate the new v2.0 plugin interface first. // Try to enumerate the new v2.0 plugin interface first.
@ -752,10 +754,9 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
_PS2EsetEmuVersion SetEmuVersion = (_PS2EsetEmuVersion) Lib.GetSymbol( L"PS2EsetEmuVersion" ); _PS2EsetEmuVersion SetEmuVersion = (_PS2EsetEmuVersion) Lib.GetSymbol( L"PS2EsetEmuVersion" );
if( GetLibName == NULL || GetLibVersion2 == NULL ) if( GetLibName == NULL || GetLibVersion2 == NULL )
throw Exception::PluginLoadError( pid, Filename, throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
L"\nMethod binding failure on GetLibName or GetLibVersion2.\n", .SetDiagMsg(L"%s plugin init failed: Method binding failure on GetLibName or GetLibVersion2.")
_( "Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2." ) .SetUserMsg(_( "The configured %s plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2."));
);
if( SetEmuVersion != NULL ) if( SetEmuVersion != NULL )
SetEmuVersion( "PCSX2", (0ul << 24) | (9ul<<16) | (7ul<<8) | 0 ); SetEmuVersion( "PCSX2", (0ul << 24) | (9ul<<16) | (7ul<<8) | 0 );
@ -778,10 +779,9 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
int testres = CommonBindings.Test(); int testres = CommonBindings.Test();
if( testres != 0 ) if( testres != 0 )
throw Exception::PluginLoadError( pid, Filename, throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
wxsFormat( L"Plugin Test failure, return code: %d", testres ), .SetDiagMsg(wxsFormat( L"Plugin Test failure, return code: %d", testres ))
_( "The plugin reports that your hardware or software/drivers are not supported." ) .SetUserMsg(_("The plugin reports that your hardware or software/drivers are not supported."));
);
} }
void PluginManager::PluginStatus_t::BindCommon( PluginsEnum_t pid ) void PluginManager::PluginStatus_t::BindCommon( PluginsEnum_t pid )
@ -800,10 +800,9 @@ void PluginManager::PluginStatus_t::BindCommon( PluginsEnum_t pid )
if( *target == NULL ) if( *target == NULL )
{ {
throw Exception::PluginLoadError( pid, Filename, throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName( pid ).c_str() ), .SetDiagMsg(wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName( pid ).c_str() ))
_( "Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2." ) .SetUserMsg(_("Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2."));
);
} }
target++; target++;
@ -827,10 +826,9 @@ void PluginManager::PluginStatus_t::BindRequired( PluginsEnum_t pid )
if( *(current->Dest) == NULL ) if( *(current->Dest) == NULL )
{ {
throw Exception::PluginLoadError( pid, Filename, throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName().c_str() ), .SetDiagMsg(wxsFormat( L"\n%s plugin init error; Method binding failed: %s\n", current->GetMethodName().c_str() ))
_( "Configured plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2." ) .SetUserMsg(_( "Configured %s plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2."));
);
} }
current++; current++;
@ -929,7 +927,7 @@ void PluginManager::Load( const wxString (&folders)[PluginId_Count] )
if( m_mcdPlugin == NULL ) if( m_mcdPlugin == NULL )
{ {
// fixme: use plugin's GetLastError (not implemented yet!) // fixme: use plugin's GetLastError (not implemented yet!)
throw Exception::PluginLoadError( PluginId_Mcd, wxEmptyString, "Internal Memorycard Plugin failed to load." ); throw Exception::PluginLoadError( PluginId_Mcd ).SetDiagMsg(L"Internal Memorycard Plugin failed to load.");
} }
SendLogFolder(); SendLogFolder();
@ -1246,7 +1244,8 @@ void PluginManager::Init()
if( SysPlugins.Mcd == NULL ) if( SysPlugins.Mcd == NULL )
{ {
// fixme: use plugin's GetLastError (not implemented yet!) // fixme: use plugin's GetLastError (not implemented yet!)
throw Exception::PluginInitError( PluginId_Mcd, "Internal Memorycard Plugin failed to initialize." ); throw Exception::PluginInitError( PluginId_Mcd )
.SetBothMsgs(wxLt("Internal Memorycard Plugin failed to initialize."));
} }
} }

View File

@ -55,24 +55,21 @@ struct PluginInfo
namespace Exception namespace Exception
{ {
// Exception thrown when a corrupted or truncated savestate is encountered. // Exception thrown when a corrupted or truncated savestate is encountered.
class SaveStateLoadError : public virtual BadStream class SaveStateLoadError : public BadStream
{ {
public: DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream, wxLt("The savestate appears to be corrupt or incomplete.") )
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, wxLt("Load failed: The savestate appears to be corrupt or incomplete.") )
}; };
class PluginError : public virtual RuntimeError class PluginError : public RuntimeError
{ {
DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, "Generic plugin error")
public: public:
PluginsEnum_t PluginId; PluginsEnum_t PluginId;
public: public:
DEFINE_EXCEPTION_COPYTORS( PluginError ) explicit PluginError( PluginsEnum_t pid )
PluginError() {}
PluginError( PluginsEnum_t pid, const char* msg="Generic plugin error" )
{ {
BaseException::InitBaseEx( msg );
PluginId = pid; PluginId = pid;
} }
@ -83,15 +80,22 @@ namespace Exception
// Plugin load errors occur when initially trying to load plugins during the // Plugin load errors occur when initially trying to load plugins during the
// creation of a PluginManager object. The error may either be due to non-existence, // creation of a PluginManager object. The error may either be due to non-existence,
// corruption, or incompatible versioning. // corruption, or incompatible versioning.
class PluginLoadError : public virtual PluginError, public virtual BadStream class PluginLoadError : public PluginError
{ {
DEFINE_EXCEPTION_COPYTORS( PluginLoadError, PluginError )
DEFINE_EXCEPTION_MESSAGES( PluginLoadError )
public: public:
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginLoadError ) wxString StreamName;
PluginLoadError( PluginsEnum_t pid, const wxString& objname, const char* eng ); protected:
PluginLoadError() {}
PluginLoadError( PluginsEnum_t pid, const wxString& objname, public:
const wxString& eng_msg, const wxString& xlt_msg ); PluginLoadError( PluginsEnum_t pid );
virtual PluginLoadError& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \
virtual PluginLoadError& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; }
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
@ -100,44 +104,46 @@ namespace Exception
// Thrown when a plugin fails it's init() callback. The meaning of this error is entirely // Thrown when a plugin fails it's init() callback. The meaning of this error is entirely
// dependent on the plugin and, in most cases probably never happens (most plugins do little // dependent on the plugin and, in most cases probably never happens (most plugins do little
// more than a couple basic memory reservations during init) // more than a couple basic memory reservations during init)
class PluginInitError : public virtual PluginError class PluginInitError : public PluginError
{ {
public: DEFINE_EXCEPTION_COPYTORS( PluginInitError, PluginError )
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginInitError ) DEFINE_EXCEPTION_MESSAGES( PluginInitError )
explicit PluginInitError( PluginsEnum_t pid, protected:
const char* msg=wxLt("%s plugin failed to initialize. Your system may have insufficient memory or resources needed.") ) PluginInitError() {}
{
BaseException::InitBaseEx( msg ); public:
PluginId = pid; PluginInitError( PluginsEnum_t pid );
}
}; };
// Plugin failed to open. Typically this is a non-critical error that means the plugin has // Plugin failed to open. Typically this is a non-critical error that means the plugin has
// not been configured properly by the user, but may also be indicative of a system // not been configured properly by the user, but may also be indicative of a system
class PluginOpenError : public virtual PluginError class PluginOpenError : public PluginError
{ {
public: DEFINE_EXCEPTION_COPYTORS( PluginOpenError, PluginError )
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginOpenError ) DEFINE_EXCEPTION_MESSAGES( PluginOpenError )
explicit PluginOpenError( PluginsEnum_t pid, protected:
const char* msg=wxLt("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.") ) PluginOpenError() {}
{
BaseException::InitBaseEx( msg ); public:
PluginId = pid; explicit PluginOpenError( PluginsEnum_t pid );
}
}; };
// This exception is thrown when a plugin returns an error while trying to save itself. // This exception is thrown when a plugin returns an error while trying to save itself.
// Typically this should be a very rare occurance since a plugin typically shoudn't // Typically this should be a very rare occurance since a plugin typically shoudn't
// be doing memory allocations or file access during state saving. // be doing memory allocations or file access during state saving.
// //
class FreezePluginFailure : public virtual PluginError class FreezePluginFailure : public PluginError
{ {
public: DEFINE_EXCEPTION_COPYTORS( FreezePluginFailure, PluginError )
DEFINE_EXCEPTION_COPYTORS( FreezePluginFailure ) DEFINE_EXCEPTION_MESSAGES( FreezePluginFailure )
explicit FreezePluginFailure( PluginsEnum_t pid) protected:
FreezePluginFailure() {}
public:
explicit FreezePluginFailure( PluginsEnum_t pid )
{ {
PluginId = pid; PluginId = pid;
} }
@ -146,11 +152,18 @@ namespace Exception
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
}; };
class ThawPluginFailure : public virtual PluginError, public virtual SaveStateLoadError class ThawPluginFailure : public SaveStateLoadError
{ {
public: DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure, SaveStateLoadError )
DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure ) DEFINE_EXCEPTION_MESSAGES( ThawPluginFailure )
public:
PluginsEnum_t PluginId;
protected:
ThawPluginFailure() {}
public:
explicit ThawPluginFailure( PluginsEnum_t pid ) explicit ThawPluginFailure( PluginsEnum_t pid )
{ {
PluginId = pid; PluginId = pid;

View File

@ -50,9 +50,6 @@ static const uint eeWaitCycles = 3072;
bool eeEventTestIsActive = false; bool eeEventTestIsActive = false;
R5900Exception::BaseExcept::~BaseExcept() throw (){}
void cpuReset() void cpuReset()
{ {
if( GetMTGS().IsOpen() ) if( GetMTGS().IsOpen() )
@ -367,7 +364,7 @@ u32 g_nextBranchCycle = 0;
// and the recompiler. (moved here to help alleviate redundant code) // and the recompiler. (moved here to help alleviate redundant code)
__forceinline void _cpuBranchTest_Shared() __forceinline void _cpuBranchTest_Shared()
{ {
eeEventTestIsActive = true; ScopedBool etest(eeEventTestIsActive);
g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles; g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles;
// ---- Counters ------------- // ---- Counters -------------
@ -475,8 +472,6 @@ __forceinline void _cpuBranchTest_Shared()
// Apply vsync and other counter nextCycles // Apply vsync and other counter nextCycles
cpuSetNextBranch( nextsCounter, nextCounter ); cpuSetNextBranch( nextsCounter, nextCounter );
eeEventTestIsActive = false;
// ---- INTC / DMAC Exceptions ----------------- // ---- INTC / DMAC Exceptions -----------------
// Raise the INTC and DMAC interrupts here, which usually throw exceptions. // Raise the INTC and DMAC interrupts here, which usually throw exceptions.
// This should be done last since the IOP and the VU0 can raise several EE // This should be done last since the IOP and the VU0 can raise several EE

View File

@ -15,11 +15,11 @@
#pragma once #pragma once
////////////////////////////////////////////////////////////////////////////////////////// class BaseR5900Exception;
#ifndef __LINUX__
#pragma region Recompiler Stuffs
#endif
// --------------------------------------------------------------------------------------
// Recompiler Stuffs
// --------------------------------------------------------------------------------------
// This code section contains recompiler vars that are used in "shared" code. Placing // This code section contains recompiler vars that are used in "shared" code. Placing
// them in iR5900.h would mean having to include that into more files than I care to // them in iR5900.h would mean having to include that into more files than I care to
// right now, so we're sticking them here for now until a better solution comes along. // right now, so we're sticking them here for now until a better solution comes along.
@ -39,12 +39,10 @@ namespace Exception
explicit ExitCpuExecute() { } explicit ExitCpuExecute() { }
}; };
} }
#ifndef __LINUX__
#pragma endregion
#endif
////////////////////////////////////////////////////////////////////////////////////////// // --------------------------------------------------------------------------------------
// EE Bios function name tables. // EE Bios function name tables.
// --------------------------------------------------------------------------------------
namespace R5900 { namespace R5900 {
extern const char* const bios[256]; extern const char* const bios[256];
} }
@ -349,6 +347,11 @@ struct R5900cpu
// //
void (*CheckExecutionState)(); void (*CheckExecutionState)();
// Safely throws host exceptions from executing code (either recompiled or interpreted).
// If this function is called outside the context of the CPU's code execution, then the
// given exception will be re-thrown automatically.
void (*ThrowException)( const BaseR5900Exception& ex );
// Manual recompiled code cache clear; typically useful to recompilers only. Size is // Manual recompiled code cache clear; typically useful to recompilers only. Size is
// in MIPS words (32 bits). Dev note: this callback is nearly obsolete, and might be // in MIPS words (32 bits). Dev note: this callback is nearly obsolete, and might be
// better off replaced with some generic API callbacks from VTLB block protection. // better off replaced with some generic API callbacks from VTLB block protection.

View File

@ -13,60 +13,65 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _R5900_EXCEPTIONS_H_ #pragma once
#define _R5900_EXCEPTIONS_H_
namespace R5900Exception // --------------------------------------------------------------------------------------
// BaseR5900Exception
// --------------------------------------------------------------------------------------
// Abstract base class for R5900 exceptions; contains the cpuRegs instance at the
// time the exception is raised.
//
// Translation note: EE Emulation exceptions are untranslated only. There's really no
// point in providing translations for this hardcore mess. :)
//
class BaseR5900Exception : public Exception::Ps2Generic
{ {
using Exception::Ps2Generic; DEFINE_EXCEPTION_COPYTORS(BaseR5900Exception, Exception::Ps2Generic)
////////////////////////////////////////////////////////////////////////////////////////// public:
// Abstract base class for R5900 exceptions; contains the cpuRegs instance at the
// time the exception is raised.
//
// Translation note: EE Emulation exceptions are untranslated only. There's really no
// point in providing translations for this hardcore mess. :)
//
class BaseExcept : public virtual Ps2Generic
{
public:
cpuRegisters cpuState; cpuRegisters cpuState;
public: public:
virtual ~BaseExcept() throw()=0;
u32 GetPc() const { return cpuState.pc; } u32 GetPc() const { return cpuState.pc; }
bool IsDelaySlot() const { return !!cpuState.IsDelaySlot; } bool IsDelaySlot() const { return !!cpuState.IsDelaySlot; }
protected: wxString& Message() { return m_message; }
wxString FormatMessage() const
{
return wxsFormat(L"(EE pc:%8.8X) ", cpuRegs.pc) + m_message;
}
protected:
void Init( const wxString& msg ) void Init( const wxString& msg )
{ {
m_message = L"(EE) " + msg; m_message = msg;;
cpuState = cpuRegs; cpuState = cpuRegs;
} }
void Init( const char*msg ) void Init( const char* msg )
{ {
m_message = fromUTF8( msg ); m_message = fromUTF8( msg );
cpuState = cpuRegs; cpuState = cpuRegs;
} }
}; };
////////////////////////////////////////////////////////////////////////////////// namespace R5900Exception
// {
class BaseAddressError : public BaseExcept // --------------------------------------------------------------------------------------
// BaseAddressError
// --------------------------------------------------------------------------------------
class BaseAddressError : public BaseR5900Exception
{ {
DEFINE_EXCEPTION_COPYTORS(BaseAddressError, BaseR5900Exception)
public: public:
bool OnWrite; bool OnWrite;
u32 Address; u32 Address;
public:
virtual ~BaseAddressError() throw() {}
protected: protected:
void Init( u32 ps2addr, bool onWrite, const wxString& msg ) void Init( u32 ps2addr, bool onWrite, const wxString& msg )
{ {
BaseExcept::Init( wxsFormat( msg+L", addr=0x%x [%s]", ps2addr, onWrite ? L"store" : L"load" ) ); _parent::Init( wxsFormat( msg+L", addr=0x%x [%s]", ps2addr, onWrite ? L"store" : L"load" ) );
OnWrite = onWrite; OnWrite = onWrite;
Address = ps2addr; Address = ps2addr;
} }
@ -76,54 +81,46 @@ namespace R5900Exception
class AddressError : public BaseAddressError class AddressError : public BaseAddressError
{ {
public: public:
virtual ~AddressError() throw() {}
AddressError( u32 ps2addr, bool onWrite ) AddressError( u32 ps2addr, bool onWrite )
{ {
BaseAddressError::Init( ps2addr, onWrite, L"Address error" ); BaseAddressError::Init( ps2addr, onWrite, L"Address error" );
} }
}; };
//////////////////////////////////////////////////////////////////////////////////
//
class TLBMiss : public BaseAddressError class TLBMiss : public BaseAddressError
{ {
public: DEFINE_EXCEPTION_COPYTORS(TLBMiss, BaseAddressError)
virtual ~TLBMiss() throw() {}
public:
TLBMiss( u32 ps2addr, bool onWrite ) TLBMiss( u32 ps2addr, bool onWrite )
{ {
BaseAddressError::Init( ps2addr, onWrite, L"TLB Miss" ); BaseAddressError::Init( ps2addr, onWrite, L"TLB Miss" );
} }
}; };
//////////////////////////////////////////////////////////////////////////////////
//
class BusError : public BaseAddressError class BusError : public BaseAddressError
{ {
public: DEFINE_EXCEPTION_COPYTORS(BusError, BaseAddressError)
virtual ~BusError() throw() {}
public:
BusError( u32 ps2addr, bool onWrite ) BusError( u32 ps2addr, bool onWrite )
{ {
BaseAddressError::Init( ps2addr, onWrite, L"Bus Error" ); BaseAddressError::Init( ps2addr, onWrite, L"Bus Error" );
} }
}; };
////////////////////////////////////////////////////////////////////////////////// class Trap : public BaseR5900Exception
//
class Trap : public BaseExcept
{ {
DEFINE_EXCEPTION_COPYTORS(Trap, BaseR5900Exception)
public: public:
u16 TrapCode; u16 TrapCode;
public: public:
virtual ~Trap() throw() {}
// Generates a trap for immediate-style Trap opcodes // Generates a trap for immediate-style Trap opcodes
Trap() Trap()
{ {
BaseExcept::Init( "Trap" ); _parent::Init( "Trap" );
TrapCode = 0; TrapCode = 0;
} }
@ -131,24 +128,19 @@ namespace R5900Exception
// error code in the opcode // error code in the opcode
explicit Trap( u16 trapcode ) explicit Trap( u16 trapcode )
{ {
BaseExcept::Init( "Trap" ), _parent::Init( "Trap" ),
TrapCode = trapcode; TrapCode = trapcode;
} }
}; };
////////////////////////////////////////////////////////////////////////////////// class DebugBreakpoint : public BaseR5900Exception
//
class DebugBreakpoint : public BaseExcept
{ {
public: DEFINE_EXCEPTION_COPYTORS(DebugBreakpoint, BaseR5900Exception)
virtual ~DebugBreakpoint() throw() {}
public:
explicit DebugBreakpoint() explicit DebugBreakpoint()
{ {
BaseExcept::Init( "Debug Breakpoint" ); _parent::Init( "Debug Breakpoint" );
} }
}; };
} }
#endif

View File

@ -94,11 +94,9 @@ void SaveStateBase::FreezeTag( const char* src )
if( strcmp( m_tagspace, src ) != 0 ) if( strcmp( m_tagspace, src ) != 0 )
{ {
pxFail( "Savestate data corruption detected while reading tag" ); wxString msg( L"Savestate data corruption detected while reading tag: " + fromUTF8(src) );
throw Exception::SaveStateLoadError( pxFail( msg );
// Untranslated diagnostic msg (use default msg for translation) throw Exception::SaveStateLoadError().SetDiagMsg(msg);
L"Savestate data corruption detected while reading tag: " + fromUTF8(src)
);
} }
} }
@ -229,10 +227,9 @@ void SaveStateBase::WritebackSectionLength( int seekpos, int sectlen, const wxCh
{ {
if( sectlen != realsectsize ) // if they don't match then we have a problem, jim. if( sectlen != realsectsize ) // if they don't match then we have a problem, jim.
{ {
throw Exception::SaveStateLoadError( wxEmptyString, throw Exception::SaveStateLoadError()
wxsFormat( L"Invalid size encountered on section '%s'.", sectname ), .SetDiagMsg(wxsFormat(L"Invalid size encountered on section '%s'.", sectname ))
_("The savestate data is invalid or corrupted.") .SetUserMsg(_("The savestate data is invalid or corrupted."));
);
} }
} }
} }
@ -258,10 +255,9 @@ bool SaveStateBase::FreezeSection( int seek_section )
if( sectlen != 128 ) if( sectlen != 128 )
{ {
throw Exception::SaveStateLoadError( wxEmptyString, throw Exception::SaveStateLoadError()
L"Invalid size encountered on BiosVersion section.", .SetDiagMsg(L"Invalid size encountered on BiosVersion section.")
_("The savestate data is invalid or corrupted.") .SetUserMsg(_("The savestate data is invalid or corrupted."));
);
} }
if( isSeeking ) if( isSeeking )
@ -281,10 +277,9 @@ bool SaveStateBase::FreezeSection( int seek_section )
Freeze( sectlen ); Freeze( sectlen );
if( sectlen != MainMemorySizeInBytes ) if( sectlen != MainMemorySizeInBytes )
{ {
throw Exception::SaveStateLoadError( wxEmptyString, throw Exception::SaveStateLoadError()
L"Invalid size encountered on MainMemory section.", .SetDiagMsg(L"Invalid size encountered on MainMemory section.")
_("The savestate data is invalid or corrupted.") .SetUserMsg(_("The savestate data is invalid or corrupted."));
);
} }
if( isSeeking ) if( isSeeking )

View File

@ -58,17 +58,20 @@ namespace Exception
// thrown when the savestate being loaded isn't supported. // thrown when the savestate being loaded isn't supported.
// //
class UnsupportedStateVersion : public virtual SaveStateLoadError class UnsupportedStateVersion : public SaveStateLoadError
{ {
DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion, SaveStateLoadError )
DEFINE_EXCEPTION_MESSAGES( UnsupportedStateVersion )
public: public:
u32 Version; // version number of the unsupported state. u32 Version; // version number of the unsupported state.
public: protected:
DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion ) UnsupportedStateVersion() {}
explicit UnsupportedStateVersion( int version, const wxString& objname=wxEmptyString ) public:
explicit UnsupportedStateVersion( int version )
{ {
StreamName = objname;
Version = version; Version = version;
} }
@ -80,18 +83,21 @@ namespace Exception
// CRC returned by the Cdvd driver. // CRC returned by the Cdvd driver.
// [feature not implemented yet] // [feature not implemented yet]
// //
class StateCrcMismatch : public virtual SaveStateLoadError class StateCrcMismatch : public SaveStateLoadError
{ {
DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch, SaveStateLoadError )
DEFINE_EXCEPTION_MESSAGES( StateCrcMismatch )
public: public:
u32 Crc_Savestate; u32 Crc_Savestate;
u32 Crc_Cdvd; u32 Crc_Cdvd;
public: protected:
DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch ) StateCrcMismatch() {}
explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const wxString& objname=wxEmptyString ) public:
StateCrcMismatch( u32 crc_save, u32 crc_cdvd )
{ {
StreamName = objname;
Crc_Savestate = crc_save; Crc_Savestate = crc_save;
Crc_Cdvd = crc_cdvd; Crc_Cdvd = crc_cdvd;
} }

View File

@ -168,6 +168,7 @@ class CpuInitializer
{ {
public: public:
ScopedPtr<CpuType> MyCpu; ScopedPtr<CpuType> MyCpu;
ScopedPtr<BaseException> ExThrown;
CpuInitializer(); CpuInitializer();
virtual ~CpuInitializer() throw(); virtual ~CpuInitializer() throw();
@ -199,14 +200,14 @@ CpuInitializer< CpuType >::CpuInitializer()
catch( Exception::RuntimeError& ex ) catch( Exception::RuntimeError& ex )
{ {
Console.Error( L"CPU provider error:\n\t" + ex.FormatDiagnosticMessage() ); Console.Error( L"CPU provider error:\n\t" + ex.FormatDiagnosticMessage() );
if( MyCpu )
MyCpu = NULL; MyCpu = NULL;
ExThrown = ex.Clone();
} }
catch( std::runtime_error& ex ) catch( std::runtime_error& ex )
{ {
Console.Error( L"CPU provider error (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) ); Console.Error( L"CPU provider error (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) );
if( MyCpu )
MyCpu = NULL; MyCpu = NULL;
ExThrown = new Exception::RuntimeError(ex);
} }
} }
@ -253,9 +254,6 @@ SysCoreAllocations::SysCoreAllocations()
Console.WriteLn( "Initializing PS2 virtual machine..." ); Console.WriteLn( "Initializing PS2 virtual machine..." );
m_RecSuccessEE = false;
m_RecSuccessIOP = false;
try try
{ {
vtlb_Core_Alloc(); vtlb_Core_Alloc();
@ -266,8 +264,7 @@ SysCoreAllocations::SysCoreAllocations()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
catch( Exception::OutOfMemory& ex ) catch( Exception::OutOfMemory& ex )
{ {
wxString newmsg( ex.UserMsg() + L"\n\n" + GetMemoryErrorVM() ); ex.UserMsg() += L"\n\n" + GetMemoryErrorVM();
ex.UserMsg() = newmsg;
CleanupMess(); CleanupMess();
throw; throw;
} }
@ -278,12 +275,12 @@ SysCoreAllocations::SysCoreAllocations()
// re-throw std::bad_alloc as something more friendly. This is needed since // re-throw std::bad_alloc as something more friendly. This is needed since
// much of the code uses new/delete internally, which throw std::bad_alloc on fail. // much of the code uses new/delete internally, which throw std::bad_alloc on fail.
throw Exception::OutOfMemory( throw Exception::OutOfMemory()
.SetDiagMsg(
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n" L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
L"Error Details: " + fromUTF8( ex.what() ), L"Error Details: " + fromUTF8( ex.what() )
)
GetMemoryErrorVM() // translated .SetUserMsg(GetMemoryErrorVM()); // translated
);
} }
Console.WriteLn( "Allocating memory for recompilers..." ); Console.WriteLn( "Allocating memory for recompilers..." );
@ -292,20 +289,20 @@ SysCoreAllocations::SysCoreAllocations()
try { try {
recCpu.Allocate(); recCpu.Allocate();
m_RecSuccessEE = true;
} }
catch( Exception::RuntimeError& ex ) catch( Exception::RuntimeError& ex )
{ {
m_RecExceptionEE = ex.Clone();
Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
recCpu.Shutdown(); recCpu.Shutdown();
} }
try { try {
psxRec.Allocate(); psxRec.Allocate();
m_RecSuccessIOP = true;
} }
catch( Exception::RuntimeError& ex ) catch( Exception::RuntimeError& ex )
{ {
m_RecExceptionIOP = ex.Clone();
Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
psxRec.Shutdown(); psxRec.Shutdown();
} }
@ -320,9 +317,13 @@ SysCoreAllocations::SysCoreAllocations()
bool SysCoreAllocations::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); } bool SysCoreAllocations::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
bool SysCoreAllocations::IsRecAvailable_MicroVU1() const { return CpuProviders->microVU1.IsAvailable(); } bool SysCoreAllocations::IsRecAvailable_MicroVU1() const { return CpuProviders->microVU1.IsAvailable(); }
BaseException* SysCoreAllocations::GetException_MicroVU0() const { return CpuProviders->microVU0.ExThrown; }
BaseException* SysCoreAllocations::GetException_MicroVU1() const { return CpuProviders->microVU1.ExThrown; }
bool SysCoreAllocations::IsRecAvailable_SuperVU0() const { return CpuProviders->superVU0.IsAvailable(); } bool SysCoreAllocations::IsRecAvailable_SuperVU0() const { return CpuProviders->superVU0.IsAvailable(); }
bool SysCoreAllocations::IsRecAvailable_SuperVU1() const { return CpuProviders->superVU1.IsAvailable(); } bool SysCoreAllocations::IsRecAvailable_SuperVU1() const { return CpuProviders->superVU1.IsAvailable(); }
BaseException* SysCoreAllocations::GetException_SuperVU0() const { return CpuProviders->superVU0.ExThrown; }
BaseException* SysCoreAllocations::GetException_SuperVU1() const { return CpuProviders->superVU1.ExThrown; }
void SysCoreAllocations::CleanupMess() throw() void SysCoreAllocations::CleanupMess() throw()

View File

@ -31,8 +31,8 @@ class SysCoreAllocations
protected: protected:
ScopedPtr<CpuInitializerSet> CpuProviders; ScopedPtr<CpuInitializerSet> CpuProviders;
bool m_RecSuccessEE:1; ScopedPtr<BaseException> m_RecExceptionEE;
bool m_RecSuccessIOP:1; ScopedPtr<BaseException> m_RecExceptionIOP;
public: public:
SysCoreAllocations(); SysCoreAllocations();
@ -42,14 +42,21 @@ public:
bool HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const; bool HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const;
bool IsRecAvailable_EE() const { return m_RecSuccessEE; } bool IsRecAvailable_EE() const { return !m_RecExceptionEE; }
bool IsRecAvailable_IOP() const { return m_RecSuccessIOP; } bool IsRecAvailable_IOP() const { return !m_RecExceptionIOP; }
BaseException* GetException_EE() const { return m_RecExceptionEE; }
BaseException* GetException_IOP() const { return m_RecExceptionIOP; }
bool IsRecAvailable_MicroVU0() const; bool IsRecAvailable_MicroVU0() const;
bool IsRecAvailable_MicroVU1() const; bool IsRecAvailable_MicroVU1() const;
BaseException* GetException_MicroVU0() const;
BaseException* GetException_MicroVU1() const;
bool IsRecAvailable_SuperVU0() const; bool IsRecAvailable_SuperVU0() const;
bool IsRecAvailable_SuperVU1() const; bool IsRecAvailable_SuperVU1() const;
BaseException* GetException_SuperVU0() const;
BaseException* GetException_SuperVU1() const;
protected: protected:
void CleanupMess() throw(); void CleanupMess() throw();

View File

@ -81,7 +81,8 @@ void SysThreadBase::OnStart()
// //
void SysThreadBase::Suspend( bool isBlocking ) void SysThreadBase::Suspend( bool isBlocking )
{ {
if( IsSelf() || !IsRunning() ) return; if (!pxAssertDev(!IsSelf(),"Suspend/Resume are not allowed from this thread.")) return;
if (!IsRunning()) return;
// shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued // shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued
// from Resume or OnResumeReady code. // from Resume or OnResumeReady code.
@ -98,7 +99,7 @@ void SysThreadBase::Suspend( bool isBlocking )
case ExecMode_Pausing: case ExecMode_Pausing:
case ExecMode_Paused: case ExecMode_Paused:
if( !isBlocking ) if( !isBlocking )
throw Exception::CancelEvent( "Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." ); throw Exception::CancelEvent( L"Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." );
m_ExecMode = ExecMode_Closing; m_ExecMode = ExecMode_Closing;
m_sem_Resume.Post(); m_sem_Resume.Post();
@ -182,7 +183,7 @@ void SysThreadBase::Resume()
{ {
Start(); Start();
if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) ) if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) )
throw Exception::ThreadCreationError(); throw Exception::ThreadCreationError(this);
if( m_ExecMode == ExecMode_Opened ) return; if( m_ExecMode == ExecMode_Opened ) return;
} }
// fall through... // fall through...

View File

@ -31,9 +31,9 @@ void vuMicroMemAlloc()
m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 ); m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 );
if( m_vuAllMem == NULL ) if( m_vuAllMem == NULL )
throw Exception::OutOfMemory( "vuMicroMemInit > Failed to allocate VUmicro memory." ); throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" );
jASSUME( sizeof( VURegs ) <= 0x800 ); pxAssume( sizeof( VURegs ) <= 0x800 );
u8* curpos = m_vuAllMem; u8* curpos = m_vuAllMem;
VU0.Micro = curpos; curpos += 0x1000; VU0.Micro = curpos; curpos += 0x1000;
@ -55,8 +55,8 @@ void vuMicroMemShutdown()
void vuMicroMemReset() void vuMicroMemReset()
{ {
jASSUME( VU0.Mem != NULL ); pxAssume( VU0.Mem != NULL );
jASSUME( VU1.Mem != NULL ); pxAssume( VU1.Mem != NULL );
memMapVUmicro(); memMapVUmicro();
@ -107,8 +107,8 @@ void SaveStateBase::vuMicroFreeze()
{ {
FreezeTag( "vuMicro" ); FreezeTag( "vuMicro" );
jASSUME( VU0.Mem != NULL ); pxAssume( VU0.Mem != NULL );
jASSUME( VU1.Mem != NULL ); pxAssume( VU1.Mem != NULL );
Freeze(VU0.ACC); Freeze(VU0.ACC);
Freeze(VU0.code); Freeze(VU0.code);

View File

@ -58,7 +58,7 @@ CompressThread_gzip::~CompressThread_gzip() throw()
void CompressThread_gzip::Write( const void* data, size_t size ) void CompressThread_gzip::Write( const void* data, size_t size )
{ {
if( gzwrite( m_gzfp, data, size ) == 0 ) if( gzwrite( m_gzfp, data, size ) == 0 )
throw Exception::BadStream( m_filename, "Write to zip file failed." ); throw Exception::BadStream( m_filename ).SetDiagMsg(L"Write to zip file failed.");
} }
void CompressThread_gzip::ExecuteTaskInThread() void CompressThread_gzip::ExecuteTaskInThread()
@ -104,7 +104,9 @@ void CompressThread_gzip::ExecuteTaskInThread()
m_gzfp = NULL; m_gzfp = NULL;
if( !wxRenameFile( tempfile, m_filename, true ) ) if( !wxRenameFile( tempfile, m_filename, true ) )
throw Exception::BadStream( m_filename, "Failed to move or copy the temporary archive to the destination filename." ); throw Exception::BadStream( m_filename )
.SetDiagMsg(L"Failed to move or copy the temporary archive to the destination filename.")
.SetUserMsg(_("The savestate was not properly saved. The temporary file was created successfully but could not be moved to its final resting place."));
Console.WriteLn( "(gzipThread) Data saved to disk without error." ); Console.WriteLn( "(gzipThread) Data saved to disk without error." );
} }

View File

@ -154,15 +154,14 @@ namespace Exception
// Exception used to perform 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. // procedures. This happens when a user cancels out of startup prompts/wizards.
// //
class StartupAborted : public BaseException class StartupAborted : public CancelEvent
{ {
public: DEFINE_RUNTIME_EXCEPTION( StartupAborted, CancelEvent, "Startup initialization was aborted by the user." )
DEFINE_EXCEPTION_COPYTORS( StartupAborted )
StartupAborted( const wxString& msg_eng=L"Startup initialization was aborted by the user." ) public:
StartupAborted( const wxString& reason )
{ {
// english messages only for this exception. m_message_diag = L"Startup aborted: " + reason;
BaseException::InitBaseEx( msg_eng, msg_eng );
} }
}; };

View File

@ -755,7 +755,7 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
if( overwrite ) if( overwrite )
{ {
if( wxFileExists( iniFilename ) && !wxRemoveFile( iniFilename ) ) if( wxFileExists( iniFilename ) && !wxRemoveFile( iniFilename ) )
throw Exception::AccessDenied( "Failed to overwrite settings; permission to file was denied." ); throw Exception::AccessDenied(iniFilename).SetBothMsgs(wxLt("Failed to overwrite existing settings file; permission was denied."));
} }
// Bind into wxConfigBase to allow wx to use our config internally, and delete whatever // Bind into wxConfigBase to allow wx to use our config internally, and delete whatever

View File

@ -26,6 +26,7 @@
#include "CDVD/CDVD.h" #include "CDVD/CDVD.h"
#include "Elfheader.h" #include "Elfheader.h"
#include "Patch.h" #include "Patch.h"
#include "R5900Exceptions.h"
__aligned16 SysMtgsThread mtgsThread; __aligned16 SysMtgsThread mtgsThread;
__aligned16 AppCoreThread CoreThread; __aligned16 AppCoreThread CoreThread;
@ -108,7 +109,13 @@ static void _Suspend()
void AppCoreThread::Suspend( bool isBlocking ) void AppCoreThread::Suspend( bool isBlocking )
{ {
if( !GetSysExecutorThread().ProcessMethodSelf( _Suspend ) ) if (IsSelf())
{
// this should never fail...
bool result = GetSysExecutorThread().Rpc_TryInvokeAsync( _Suspend );
pxAssert(result);
}
else if (!GetSysExecutorThread().Rpc_TryInvoke( _Suspend ))
_parent::Suspend(true); _parent::Suspend(true);
} }
@ -392,12 +399,44 @@ void AppCoreThread::UploadStateCopy( const VmStateBuffer& copy )
paused_core.AllowResume(); paused_core.AllowResume();
} }
static uint m_except_threshold = 0;
void AppCoreThread::ExecuteTaskInThread() void AppCoreThread::ExecuteTaskInThread()
{ {
PostCoreStatus( CoreThread_Started ); PostCoreStatus( CoreThread_Started );
m_except_threshold = 0;
_parent::ExecuteTaskInThread(); _parent::ExecuteTaskInThread();
} }
void AppCoreThread::DoCpuExecute()
{
try {
_parent::DoCpuExecute();
}
catch (BaseR5900Exception& ex)
{
Console.Error( ex.FormatMessage() );
// [TODO] : Debugger Hook!
if( ++m_except_threshold > 6 )
{
// If too many TLB Misses occur, we're probably going to crash and
// the game is probably running miserably.
m_except_threshold = 0;
//Suspend();
// [TODO] Issue error dialog to the user here...
Console.Error( "Too many execution errors. VM execution has been suspended!" );
// Hack: this keeps the EE thread from running more code while the SysExecutor
// thread catches up and signals it for suspension.
m_ExecMode = ExecMode_Closing;
}
}
}
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// BaseSysExecEvent_ScopedCore / SysExecEvent_CoreThreadClose / SysExecEvent_CoreThreadPause // BaseSysExecEvent_ScopedCore / SysExecEvent_CoreThreadClose / SysExecEvent_CoreThreadPause
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------

View File

@ -142,6 +142,8 @@ public:
virtual void UploadStateCopy( const VmStateBuffer& copy ); virtual void UploadStateCopy( const VmStateBuffer& copy );
protected: protected:
virtual void DoCpuExecute();
virtual void OnResumeReady(); virtual void OnResumeReady();
virtual void OnResumeInThread( bool IsSuspended ); virtual void OnResumeInThread( bool IsSuspended );
virtual void OnSuspendInThread(); virtual void OnSuspendInThread();

View File

@ -48,8 +48,7 @@ protected:
public: public:
AppGameDatabase() {} AppGameDatabase() {}
virtual ~AppGameDatabase() throw() { virtual ~AppGameDatabase() throw() {
// deque deletes its contents automatically. Console.WriteLn( "(GameDB) Unloading..." );
Console.WriteLn( "(GameDB) Destroying..." );
} }
AppGameDatabase& LoadFromFile(const wxString& file = L"GameIndex.dbf", const wxString& key = L"Serial" ); AppGameDatabase& LoadFromFile(const wxString& file = L"GameIndex.dbf", const wxString& key = L"Serial" );

View File

@ -138,7 +138,7 @@ void Pcsx2App::ReadUserModeSettings()
// first time startup, so give the user the choice of user mode: // first time startup, so give the user the choice of user mode:
FirstTimeWizard wiz( NULL ); FirstTimeWizard wiz( NULL );
if( !wiz.RunWizard( wiz.GetUsermodePage() ) ) if( !wiz.RunWizard( wiz.GetUsermodePage() ) )
throw Exception::StartupAborted( L"Startup aborted: User canceled FirstTime Wizard." ); throw Exception::StartupAborted( L"User canceled FirstTime Wizard." );
// Save user's new settings // Save user's new settings
IniSaver saver( *conf_usermode ); IniSaver saver( *conf_usermode );
@ -166,7 +166,7 @@ void Pcsx2App::ReadUserModeSettings()
// If we skip this check, it's very likely that actions like creating Memory Cards will fail. // If we skip this check, it's very likely that actions like creating Memory Cards will fail.
FirstTimeWizard wiz( NULL ); FirstTimeWizard wiz( NULL );
if( !wiz.RunWizard( /*wiz.GetPostUsermodePage()*/ wiz.GetUsermodePage() ) ) if( !wiz.RunWizard( /*wiz.GetPostUsermodePage()*/ wiz.GetUsermodePage() ) )
throw Exception::StartupAborted( L"Startup aborted: User canceled Configuration Wizard." ); throw Exception::StartupAborted( L"User canceled Configuration Wizard." );
// Save user's new settings // Save user's new settings
IniSaver saver( *conf_usermode ); IniSaver saver( *conf_usermode );
@ -193,7 +193,9 @@ void Pcsx2App::DetectCpuAndUserMode()
{ {
// Note: due to memcpy_fast, we need minimum MMX even for interpreters. This will // Note: due to memcpy_fast, we need minimum MMX even for interpreters. This will
// hopefully change later once we have a dynamically recompiled memcpy. // hopefully change later once we have a dynamically recompiled memcpy.
throw Exception::HardwareDeficiency(L"MMX Extensions not available.", _("PCSX2 requires cpu with MMX instruction to run.")); throw Exception::HardwareDeficiency()
.SetDiagMsg(L"Critical Failure: MMX Extensions not available.")
.SetUserMsg(_("MMX extensions are not available. PCSX2 requires cpu with MMX extension support to run."));
} }
ReadUserModeSettings(); ReadUserModeSettings();
@ -260,8 +262,8 @@ void Pcsx2App::AllocateCoreStuffs()
wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)") ); wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)") );
exconf += 12; exconf += 12;
exconf += exconf.Heading( pxE( ".Popup:RecompilerInit", exconf += exconf.Heading( pxE( ".Popup:RecompilerInit:Header",
L"Warning: Some of the configured PS2 recompilers failed to initialize and will not be available for this session:\n" ) L"Warning: Some of the configured PS2 recompilers failed to initialize and have been disabled:" )
); );
wxTextCtrl* scrollableTextArea = new wxTextCtrl( wxTextCtrl* scrollableTextArea = new wxTextCtrl(
@ -269,63 +271,55 @@ void Pcsx2App::AllocateCoreStuffs()
wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP
); );
exconf += scrollableTextArea | pxSizerFlags::StdExpand(); exconf += 6;
exconf += scrollableTextArea | pxExpand.Border(wxALL, 16);
if( !m_CoreAllocs->IsRecAvailable_EE() ) if( BaseException* ex = m_CoreAllocs->GetException_EE() )
{ {
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" ); scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.EnableEE = false; g_Conf->EmuOptions.Recompiler.EnableEE = false;
} }
if( !m_CoreAllocs->IsRecAvailable_IOP() ) if( BaseException* ex = m_CoreAllocs->GetException_IOP() )
{ {
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\n" ); scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.EnableIOP = false; g_Conf->EmuOptions.Recompiler.EnableIOP = false;
} }
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() ) { if( BaseException* ex = m_CoreAllocs->GetException_MicroVU0() )
scrollableTextArea->AppendText( L"* microVU0\n\n" ); {
scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = false; g_Conf->EmuOptions.Recompiler.UseMicroVU0 = false;
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && m_CoreAllocs->IsRecAvailable_SuperVU0(); g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && m_CoreAllocs->IsRecAvailable_SuperVU0();
} }
if( !m_CoreAllocs->IsRecAvailable_MicroVU1() ) if( BaseException* ex = m_CoreAllocs->GetException_MicroVU1() )
{ {
scrollableTextArea->AppendText( L"* microVU1\n\n" ); scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = false; g_Conf->EmuOptions.Recompiler.UseMicroVU1 = false;
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && m_CoreAllocs->IsRecAvailable_SuperVU1(); g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && m_CoreAllocs->IsRecAvailable_SuperVU1();
} }
if( !m_CoreAllocs->IsRecAvailable_SuperVU0() ) if( BaseException* ex = m_CoreAllocs->GetException_SuperVU0() )
{ {
scrollableTextArea->AppendText( L"* SuperVU0\n\n" ); scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = m_CoreAllocs->IsRecAvailable_MicroVU0(); g_Conf->EmuOptions.Recompiler.UseMicroVU0 = m_CoreAllocs->IsRecAvailable_MicroVU0();
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && g_Conf->EmuOptions.Recompiler.UseMicroVU0; g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && g_Conf->EmuOptions.Recompiler.UseMicroVU0;
} }
if( !m_CoreAllocs->IsRecAvailable_SuperVU1() ) if( BaseException* ex = m_CoreAllocs->GetException_SuperVU1() )
{ {
scrollableTextArea->AppendText( L"* SuperVU1\n\n" ); scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = m_CoreAllocs->IsRecAvailable_MicroVU1(); g_Conf->EmuOptions.Recompiler.UseMicroVU1 = m_CoreAllocs->IsRecAvailable_MicroVU1();
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && g_Conf->EmuOptions.Recompiler.UseMicroVU1; g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && g_Conf->EmuOptions.Recompiler.UseMicroVU1;
} }
exconf += new ModalButtonPanel( &exconf, MsgButtons().OK() ) | pxSizerFlags::StdCenter(); exconf += exconf.Heading( pxE(".Popup:RecompilerInit:Footer",
L"Note: Recompilers are not necessary for PCSX2 to run, however they typically improve emulation speed substantially. "
L"You may have to manually re-enable the recompilers listed above, if you resolve the errors." )
);
exconf.ShowModal(); pxIssueConfirmation( exconf, MsgButtons().OK() );
// Failures can be SSE-related OR memory related. Should do per-cpu error reports instead...
/*message += pxE( ".Popup Error:EmuCore:MemoryForRecs",
L"These errors are the result of memory allocation failures (see the program log for details). "
L"Closing out some memory hogging background tasks may resolve this error.\n\n"
L"These recompilers have been disabled and interpreters will be used in their place. "
L"Interpreters can be very slow, so don't get too excited. Press OK to continue or CANCEL to close PCSX2."
);*/
//if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
// return false;
} }
} }

View File

@ -37,33 +37,28 @@ namespace Exception
// //
class CannotApplySettings : public BaseException class CannotApplySettings : public BaseException
{ {
DEFINE_EXCEPTION_COPYTORS( CannotApplySettings, BaseException )
DEFINE_EXCEPTION_MESSAGES( CannotApplySettings )
public: public:
bool IsVerbose; bool IsVerbose;
protected: protected:
BaseApplicableConfigPanel* m_Panel; BaseApplicableConfigPanel* m_Panel;
protected:
CannotApplySettings() { IsVerbose = true; }
public: public:
DEFINE_EXCEPTION_COPYTORS( CannotApplySettings ) explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel )
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel, const char* msg=wxLt("Cannot apply new settings, one of the settings is invalid."), bool isVerbose = true )
{ {
BaseException::InitBaseEx( msg ); SetBothMsgs(wxLt("Cannot apply new settings, one of the settings is invalid."));
m_Panel = thispanel;
IsVerbose = isVerbose;
}
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel, const wxString& msg_eng, const wxString& msg_xlt )
{
BaseException::InitBaseEx( msg_eng, msg_xlt );
m_Panel = thispanel; m_Panel = thispanel;
IsVerbose = true; IsVerbose = true;
} }
BaseApplicableConfigPanel* GetPanel() virtual CannotApplySettings& Quiet() { IsVerbose = false; return *this; }
{ BaseApplicableConfigPanel* GetPanel() { return m_Panel; }
return m_Panel;
}
}; };
} }

View File

@ -93,7 +93,7 @@ CpuUsageProviderMSW::CpuUsageProviderMSW()
throw Exception::RuntimeError( "(CpuUsageProviderMSW) CoInitializeSecurity failed: No good security packages! .. whatever tht means." ); throw Exception::RuntimeError( "(CpuUsageProviderMSW) CoInitializeSecurity failed: No good security packages! .. whatever tht means." );
case E_OUTOFMEMORY: case E_OUTOFMEMORY:
throw Exception::OutOfMemory( "(CpuUsageProviderMSW) Out of Memory error returned during call to CoInitializeSecurity." ); throw Exception::OutOfMemory( L"(CpuUsageProviderMSW) Out of Memory error returned during call to CoInitializeSecurity." );
default: default:
throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) CoInitializeSecurity failed with an unknown error code: %d", hr ), wxEmptyString ); throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) CoInitializeSecurity failed with an unknown error code: %d", hr ), wxEmptyString );
@ -221,7 +221,7 @@ void CpuUsageProviderMSW::UpdateStats()
break; break;
case WBEM_E_OUT_OF_MEMORY: case WBEM_E_OUT_OF_MEMORY:
throw Exception::OutOfMemory( "(CpuUsageProviderMSW) Out of Memory Enumerating WMI Object." ); throw Exception::OutOfMemory( L"(CpuUsageProviderMSW) Out of Memory Enumerating WMI Object." );
default: default:
throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) WMI Object Enumeration failed with an unknown error code: %d", hRes ), wxEmptyString ); throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) WMI Object Enumeration failed with an unknown error code: %d", hRes ), wxEmptyString );

View File

@ -104,14 +104,13 @@ bool FirstTimeWizard::UsermodePage::PrepForApply()
if( path.FileExists() ) if( path.FileExists() )
{ {
// FIXME: There's already a file by the same name.. not sure what we should do here. // FIXME: There's already a file by the same name.. not sure what we should do here.
throw Exception::BadStream( path.ToString(), throw Exception::BadStream( path.ToString() )
L"Targeted documents folder is already occupied by a file.", .SetDiagMsg(L"Targeted documents folder is already occupied by a file.")
pxE( ".Error:DocsFolderFileConflict", .SetUserMsg(pxE( ".Error:DocsFolderFileConflict",
L"PCSX2 cannot create a documents folder in the requested location. " L"PCSX2 cannot create a documents folder in the requested location. "
L"The path name matches an existing file. Delete the file or change the documents location, " L"The path name matches an existing file. Delete the file or change the documents location, "
L"and then try again." L"and then try again."
) ));
);
} }
if( !path.Exists() ) if( !path.Exists() )

View File

@ -308,7 +308,18 @@ void pxEvtHandler::ProcessEvent( SysExecEvent* evt )
} }
} }
bool pxEvtHandler::ProcessMethodSelf( FnType_Void* method ) bool pxEvtHandler::Rpc_TryInvokeAsync( FnType_Void* method )
{
if( wxThread::GetCurrentId() != m_OwnerThreadId )
{
PostEvent( new SysExecEvent_MethodVoid(method) );
return true;
}
return false;
}
bool pxEvtHandler::Rpc_TryInvoke( FnType_Void* method )
{ {
if( wxThread::GetCurrentId() != m_OwnerThreadId ) if( wxThread::GetCurrentId() != m_OwnerThreadId )
{ {

View File

@ -47,7 +47,6 @@ void GSPanel::InitDefaultAccelerators()
m_Accels->Map( AAC( WXK_F8 ).Shift(), "Sys_TakeSnapshot"); m_Accels->Map( AAC( WXK_F8 ).Shift(), "Sys_TakeSnapshot");
m_Accels->Map( AAC( WXK_F8 ).Shift().Cmd(), "Sys_TakeSnapshot"); m_Accels->Map( AAC( WXK_F8 ).Shift().Cmd(), "Sys_TakeSnapshot");
m_Accels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle"); m_Accels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle");
m_Accels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle" );
//m_Accels->Map( AAC( WXK_F10 ), "Sys_LoggingToggle" ); //m_Accels->Map( AAC( WXK_F10 ), "Sys_LoggingToggle" );
m_Accels->Map( AAC( WXK_F11 ), "Sys_FreezeGS" ); m_Accels->Map( AAC( WXK_F11 ), "Sys_FreezeGS" );

View File

@ -121,16 +121,12 @@ void Panels::BiosSelectorPanel::Apply()
int sel = m_ComboBox->GetSelection(); int sel = m_ComboBox->GetSelection();
if( sel == wxNOT_FOUND ) if( sel == wxNOT_FOUND )
{ {
throw Exception::CannotApplySettings( this, throw Exception::CannotApplySettings(this)
// English Log .SetDiagMsg(L"User did not specify a valid BIOS selection.")
L"User did not specify a valid BIOS selection.", .SetUserMsg( pxE( ".Error:BIOS:InvalidSelection",
// Translated
pxE( ".Error:BIOS:InvalidSelection",
L"Please select a valid BIOS. If you are unable to make a valid selection " L"Please select a valid BIOS. If you are unable to make a valid selection "
L"then press cancel to close the Configuration panel." L"then press cancel to close the Configuration panel."
) ) );
);
} }
g_Conf->BaseFilenames.Bios = (*m_BiosList)[(int)m_ComboBox->GetClientData(sel)]; g_Conf->BaseFilenames.Bios = (*m_BiosList)[(int)m_ComboBox->GetClientData(sel)];

View File

@ -142,10 +142,9 @@ void Panels::GSWindowSettingsPanel::Apply()
long xr, yr; long xr, yr;
if( !m_text_WindowWidth->GetValue().ToLong( &xr ) || !m_text_WindowHeight->GetValue().ToLong( &yr ) ) if( !m_text_WindowWidth->GetValue().ToLong( &xr ) || !m_text_WindowHeight->GetValue().ToLong( &yr ) )
throw Exception::CannotApplySettings( this, throw Exception::CannotApplySettings( this )
L"User submitted non-numeric window size parameters!", .SetDiagMsg(L"User submitted non-numeric window size parameters!")
_("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<") .SetUserMsg(_("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<"));
);
appconf.WindowSize.x = xr; appconf.WindowSize.x = xr;
appconf.WindowSize.y = yr; appconf.WindowSize.y = yr;

View File

@ -58,7 +58,7 @@ namespace Exception
class NotEnumerablePlugin : public BadStream class NotEnumerablePlugin : public BadStream
{ {
public: public:
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, wxLt("File is not a PCSX2 plugin") ); DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream, wxLt("File is not a PCSX2 plugin") );
}; };
} }
@ -89,7 +89,7 @@ public:
: m_plugpath( plugpath ) : m_plugpath( plugpath )
{ {
if( !m_plugin.Load( m_plugpath ) ) if( !m_plugin.Load( m_plugpath ) )
throw Exception::BadStream( m_plugpath, "File is not a valid dynamic library." ); throw Exception::BadStream( m_plugpath ).SetBothMsgs("File is not a valid dynamic library.");
wxDoNotLogInThisScope please; wxDoNotLogInThisScope please;
m_GetLibType = (_PS2EgetLibType)m_plugin.GetSymbol( L"PS2EgetLibType" ); m_GetLibType = (_PS2EgetLibType)m_plugin.GetSymbol( L"PS2EgetLibType" );
@ -241,7 +241,8 @@ void ApplyOverValidStateEvent::InvokeEvent()
int result = pxIssueConfirmation( dialog, MsgButtons().OK().Cancel(), L"PluginSelector:ConfirmShutdown" ); int result = pxIssueConfirmation( dialog, MsgButtons().OK().Cancel(), L"PluginSelector:ConfirmShutdown" );
if( result == wxID_CANCEL ) if( result == wxID_CANCEL )
throw Exception::CannotApplySettings( m_owner->GetApplicableConfigPanel(), "Cannot apply settings: canceled by user because plugins changed while the emulation state was active.", false ); throw Exception::CannotApplySettings( m_owner->GetApplicableConfigPanel() ).Quiet()
.SetDiagMsg(L"Cannot apply settings: canceled by user because plugins changed while the emulation state was active.");
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -465,13 +466,9 @@ void Panels::PluginSelectorPanel::Apply()
{ {
wxString plugname( pi->GetShortname() ); wxString plugname( pi->GetShortname() );
throw Exception::CannotApplySettings( this, throw Exception::CannotApplySettings( this )
// English Log .SetDiagMsg(wxsFormat( L"PluginSelectorPanel: Invalid or missing selection for the %s plugin.", plugname.c_str()) )
wxsFormat( L"PluginSelectorPanel: Invalid or missing selection for the %s plugin.", plugname.c_str() ), .SetUserMsg(wxsFormat( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg() );
// Translated
wxsFormat( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg()
);
} }
g_Conf->BaseFilenames.Plugins[pid] = GetFilename((int)m_ComponentBoxes->Get(pid).GetClientData(sel)); g_Conf->BaseFilenames.Plugins[pid] = GetFilename((int)m_ComponentBoxes->Get(pid).GetClientData(sel));
@ -498,7 +495,7 @@ void Panels::PluginSelectorPanel::Apply()
try try
{ {
if( wxID_CANCEL == ApplyPluginsDialog( this ).ShowModal() ) if( wxID_CANCEL == ApplyPluginsDialog( this ).ShowModal() )
throw Exception::CannotApplySettings( this, "User canceled plugin load process.", false ); throw Exception::CannotApplySettings( this ).Quiet().SetDiagMsg(L"User canceled plugin load process.");
} }
catch( Exception::PluginError& ex ) catch( Exception::PluginError& ex )
{ {
@ -506,15 +503,12 @@ void Panels::PluginSelectorPanel::Apply()
wxString plugname( tbl_PluginInfo[ex.PluginId].GetShortname() ); wxString plugname( tbl_PluginInfo[ex.PluginId].GetShortname() );
throw Exception::CannotApplySettings( this, throw Exception::CannotApplySettings( this )
// Diagnostic .SetDiagMsg(ex.FormatDiagnosticMessage())
ex.FormatDiagnosticMessage(), .SetUserMsg(wxsFormat(
_("The selected %s plugin failed to load.\n\nReason: %s\n\n"),
// Translated
wxsFormat( _("The selected %s plugin failed to load.\n\nReason: %s\n\n"),
plugname.c_str(), ex.FormatDisplayMessage().c_str() plugname.c_str(), ex.FormatDisplayMessage().c_str()
) + GetApplyFailedMsg() ) + GetApplyFailedMsg());
);
} }
} }

View File

@ -144,9 +144,12 @@ void Panels::FramelimiterPanel::Apply()
} }
catch( Exception::ParseError& ) catch( Exception::ParseError& )
{ {
throw Exception::CannotApplySettings( this, throw Exception::CannotApplySettings( this )
wxLt("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics.") .SetDiagMsg(wxsFormat(
); L"Error while parsing either NTSC or PAL framerate settings.\n\tNTSC Input = %s\n\tPAL Input = %s",
m_text_BaseNtsc->GetValue(), m_text_BasePal->GetValue()
) )
.SetUserMsg(_("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics."));
} }
appfps.SanityCheck(); appfps.SanityCheck();

View File

@ -40,25 +40,41 @@ static void SaveStateFile_ReadHeader( IStreamReader& thr )
thr.Read( ident ); thr.Read( ident );
if( strcmp(SavestateIdentString, ident) ) if( strcmp(SavestateIdentString, ident) )
throw Exception::SaveStateLoadError( thr.GetStreamName(), throw Exception::SaveStateLoadError( thr.GetStreamName() )
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ), .SetDiagMsg(wxsFormat( L"Unrecognized file signature while loading savestate. [sig = %s]", ident ))
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.") .SetUserMsg(_("This is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2."));
);
u32 savever; u32 savever;
thr.Read( savever ); thr.Read( savever );
if( (savever >> 16) != (g_SaveVersion >> 16) ) // Major version mismatch. Means we can't load this savestate at all. Support for it
throw Exception::SaveStateLoadError( thr.GetStreamName(), // was removed entirely.
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
);
if( savever > g_SaveVersion ) if( savever > g_SaveVersion )
throw Exception::SaveStateLoadError( thr.GetStreamName(), throw Exception::SaveStateLoadError( thr.GetStreamName() )
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ), .SetDiagMsg(wxsFormat( L"Savestate uses an unsupported or unknown savestate version.\n(PCSX2 ver=%d, state ver=%d)", g_SaveVersion, savever ))
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.") .SetUserMsg(_("Cannot load this savestate. The state is from an incompatible edition of PCSX2 that is either newer than this version, or is no longer supported."));
);
// check for a "minor" version incompatibility; which happens if the savestate being loaded is a newer version
// than the emulator recognizes. 99% chance that trying to load it will just corrupt emulation or crash.
if( (savever >> 16) != (g_SaveVersion >> 16) )
throw Exception::SaveStateLoadError( thr.GetStreamName() )
.SetDiagMsg(wxsFormat( L"Savestate uses an unknown (future?!) savestate version.\n(PCSX2 ver=%d, state ver=%d)", g_SaveVersion, savever ))
.SetUserMsg(_("Cannot load this savestate. The state is an unsupported version, likely created by a newer edition of PCSX2."));
};
class gzError : public Exception::BadStream
{
DEFINE_STREAM_EXCEPTION( gzError, BadStream, wxLt("Invalid or corrupted gzip archive") )
};
class gzReadError : public gzError
{
};
class gzWriteError : public gzError
{
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -79,7 +95,7 @@ public:
: m_filename( filename ) : m_filename( filename )
{ {
if( NULL == (m_gzfp = gzopen( m_filename.ToUTF8(), "rb" )) ) if( NULL == (m_gzfp = gzopen( m_filename.ToUTF8(), "rb" )) )
throw Exception::CannotCreateStream( m_filename, "Cannot open file for reading." ); throw Exception::CannotCreateStream( m_filename ).SetDiagMsg(L"Cannot open file for reading.");
#if defined(ZLIB_VERNUM) && (ZLIB_VERNUM >= 0x1240) #if defined(ZLIB_VERNUM) && (ZLIB_VERNUM >= 0x1240)
gzbuffer(m_gzfp, 0x100000); // 1mb buffer for zlib internal operations gzbuffer(m_gzfp, 0x100000); // 1mb buffer for zlib internal operations
@ -97,7 +113,8 @@ public:
{ {
int result = gzread( m_gzfp, dest, size ); int result = gzread( m_gzfp, dest, size );
if( result == -1) if( result == -1)
throw Exception::BadStream( m_filename, "Data read failed: Invalid or corrupted gzip archive." ); //throw Exception::gzError( m_filename );
throw Exception::BadStream( m_filename ).SetBothMsgs(wxLt("Data read failed: Invalid or corrupted gzip archive."));
if( (size_t)result < size ) if( (size_t)result < size )
throw Exception::EndOfStream( m_filename ); throw Exception::EndOfStream( m_filename );
@ -136,7 +153,9 @@ protected:
ScopedCoreThreadPause paused_core; ScopedCoreThreadPause paused_core;
if( !SysHasValidState() ) if( !SysHasValidState() )
throw Exception::RuntimeError( L"Cannot complete state freeze request; the virtual machine state is reset.", _("You'll need to start a new virtual machine before you can save its state.") ); throw Exception::RuntimeError()
.SetDiagMsg(L"SysExecEvent_DownloadState: Cannot freeze/download an invalid VM state!")
.SetUserMsg(L"There is no active virtual machine state to download or save." );
memSavingState(m_dest_buffer).FreezeAll(); memSavingState(m_dest_buffer).FreezeAll();

View File

@ -191,7 +191,8 @@ public:
void ProcessEvent( SysExecEvent* evt ); void ProcessEvent( SysExecEvent* evt );
void ProcessEvent( SysExecEvent& evt ); void ProcessEvent( SysExecEvent& evt );
bool ProcessMethodSelf( FnType_Void* method ); bool Rpc_TryInvokeAsync( FnType_Void* method );
bool Rpc_TryInvoke( FnType_Void* method );
void SetActiveThread(); void SetActiveThread();
protected: protected:
@ -227,9 +228,14 @@ public:
void ProcessEvent( SysExecEvent* evt ); void ProcessEvent( SysExecEvent* evt );
void ProcessEvent( SysExecEvent& evt ); void ProcessEvent( SysExecEvent& evt );
bool ProcessMethodSelf( void (*evt)() ) bool Rpc_TryInvokeAsync( void (*evt)() )
{ {
return m_EvtHandler ? m_EvtHandler->ProcessMethodSelf( evt ) : false; return m_EvtHandler ? m_EvtHandler->Rpc_TryInvokeAsync( evt ) : false;
}
bool Rpc_TryInvoke( void (*evt)() )
{
return m_EvtHandler ? m_EvtHandler->Rpc_TryInvoke( evt ) : false;
} }
protected: protected:

View File

@ -23,8 +23,9 @@
#define DIRENTRY_SIZE 16 #define DIRENTRY_SIZE 16
////////////////////////////////////////////////////////////////////////////////////////// // --------------------------------------------------------------------------------------
// romdir structure (packing required!) // romdir structure (packing required!)
// --------------------------------------------------------------------------------------
// //
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma pack(1) # pragma pack(1)
@ -41,20 +42,16 @@ struct romdir
# pragma pack() # pragma pack()
#endif #endif
//////////////////////////////////////////////////////////////////////////////////////////
u32 BiosVersion; // Used in Memory, Misc, CDVD u32 BiosVersion; // Used in Memory, Misc, CDVD
Exception::BiosLoadFailed::BiosLoadFailed( const wxString& filename, const wxString& msg_diag, const wxString& msg_user ) // --------------------------------------------------------------------------------------
// Exception::BiosLoadFailed (implementations)
// --------------------------------------------------------------------------------------
Exception::BiosLoadFailed::BiosLoadFailed( const wxString& filename )
{ {
wxString diag( msg_user.IsEmpty() ? m_message_diag = L"BIOS has not been configured, or the configuration has been corrupted.";
L"BIOS has not been configured, or the configuration has been corrupted." : msg_user m_message_user = _("The PS2 BIOS could not be loaded. The BIOS has not been configured, or the configuration has been corrupted. Please re-configure.");
);
wxString user( msg_user.IsEmpty() ?
_("The PS2 BIOS has not been configured, or the configuration has been corrupted. Please re-configure.") : msg_user.c_str()
);
BaseException::InitBaseEx( diag, user );
StreamName = filename; StreamName = filename;
} }
@ -156,10 +153,9 @@ void LoadBIOS()
s64 filesize = Path::GetFileSize( Bios ); s64 filesize = Path::GetFileSize( Bios );
if( filesize <= 0 ) if( filesize <= 0 )
{ {
throw Exception::BiosLoadFailed( Bios, throw Exception::BiosLoadFailed( Bios )
L"Configured BIOS file does not exist.", .SetDiagMsg(L"Configured BIOS file does not exist.")
_("The configured BIOS file does not exist. Please re-configure.") .SetUserMsg(_("The configured BIOS file does not exist. Please re-configure."));
);
} }
wxFile fp( Bios ); wxFile fp( Bios );
@ -168,10 +164,9 @@ void LoadBIOS()
BiosVersion = GetBiosVersion(); BiosVersion = GetBiosVersion();
if( BiosVersion == -1 ) if( BiosVersion == -1 )
{ {
throw Exception::BiosLoadFailed( Bios, throw Exception::BiosLoadFailed( Bios )
L"Configured BIOS file is not a valid PS2 BIOS.", .SetDiagMsg(L"Configured BIOS file is not a valid PS2 BIOS.")
_("The configured BIOS file is not a valid PS2 BIOS. Please re-configure.") .SetUserMsg(_("The configured BIOS file is not a valid PS2 BIOS. Please re-configure."));
);
} }
Console.WriteLn("Bios Version %d.%d", BiosVersion >> 8, BiosVersion & 0xff); Console.WriteLn("Bios Version %d.%d", BiosVersion >> 8, BiosVersion & 0xff);

View File

@ -19,12 +19,12 @@ namespace Exception
{ {
class BiosLoadFailed : public FileNotFound class BiosLoadFailed : public FileNotFound
{ {
public: DEFINE_EXCEPTION_COPYTORS( BiosLoadFailed, FileNotFound )
DEFINE_EXCEPTION_COPYTORS( BiosLoadFailed ) DEFINE_EXCEPTION_MESSAGES( BiosLoadFailed )
DEFINE_STREAM_EXCEPTION_ACCESSORS( BiosLoadFailed )
explicit BiosLoadFailed( const wxString& filename, public:
const wxString& msg_diag=wxEmptyString, BiosLoadFailed( const wxString& streamName );
const wxString& msg_user=wxEmptyString );
}; };
} }

View File

@ -42,7 +42,7 @@ using namespace vtlb_private;
#ifdef PCSX2_DEVBUILD #ifdef PCSX2_DEVBUILD
#define verify(x) {if (!(x)) { (*(u8*)0)=3; }} #define verify(x) {if (!(x)) { (*(u8*)0)=3; }}
#else #else
#define verify jASSUME #define verify pxAssume
#endif #endif
namespace vtlb_private namespace vtlb_private
@ -221,32 +221,35 @@ void __fastcall vtlb_memWrite128(u32 mem, const mem128_t *value)
MemOp_w1<128,mem128_t>(mem,value); MemOp_w1<128,mem128_t>(mem,value);
} }
///////////////////////////////////////////////////////////////////////// // ===========================================================================================
// Error / TLB Miss Handlers // Error / TLB Miss Handlers
// ===========================================================================================
// Important: Throwing exceptions isn't reliable *yet* because memory ops don't flush
// the PC prior to invoking the indirect handlers. That feature will likely be added to
// debug and dev builds soon, and later on to release builds as well.
// //
static const char* _getModeStr( u32 mode )
{
return (mode==0) ? "read" : "write";
}
// Generates a tlbMiss Exception // Generates a tlbMiss Exception
// Note: Don't throw exceptions yet, they cause a crash when otherwise
// there would be a (slight) chance the game continues (rama).
static __forceinline void vtlb_Miss(u32 addr,u32 mode) static __forceinline void vtlb_Miss(u32 addr,u32 mode)
{ {
Console.Error( "vtlb miss : addr 0x%X, mode %d [%s]", addr, mode, _getModeStr(mode) ); if( IsDevBuild )
//verify(false); Cpu->ThrowException( R5900Exception::TLBMiss( addr, !!mode ) );
//throw R5900Exception::TLBMiss( addr, !!mode ); else
Console.Error( R5900Exception::TLBMiss( addr, !!mode ).FormatMessage() );
} }
// Just dies a horrible death for now. // BusError exception: more serious than a TLB miss. If properly emulated the PS2 kernel
// Eventually should generate a BusError exception. // itself would invoke a diagnostic/assertion screen that displays the cpu state at the
// time of the exception.
static __forceinline void vtlb_BusError(u32 addr,u32 mode) static __forceinline void vtlb_BusError(u32 addr,u32 mode)
{ {
Console.Error( "vtlb bus error : addr 0x%X, mode %d\n", addr, _getModeStr(mode) ); // Throwing exceptions isn't reliable *yet* because memory ops don't flush
//verify(false); // the PC prior to invoking the indirect handlers.
throw R5900Exception::BusError( addr, !!mode );
if( IsDevBuild )
Cpu->ThrowException( R5900Exception::BusError( addr, !!mode ) );
else
Console.Error( R5900Exception::TLBMiss( addr, !!mode ).FormatMessage() );
} }
///// Virtual Mapping Errors (TLB Miss) ///// Virtual Mapping Errors (TLB Miss)
@ -307,8 +310,9 @@ void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data) { Console.Er
void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console.Error("vtlbDefaultPhyWrite128: 0x%X",addr); verify(false); } void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console.Error("vtlbDefaultPhyWrite128: 0x%X",addr); verify(false); }
////////////////////////////////////////////////////////////////////////////////////////// // ===========================================================================================
// VTLB Public API -- Init/Term/RegisterHandler stuff // VTLB Public API -- Init/Term/RegisterHandler stuff
// ===========================================================================================
// //
// Assigns or re-assigns the callbacks for a VTLB memory handler. The handler defines specific behavior // Assigns or re-assigns the callbacks for a VTLB memory handler. The handler defines specific behavior
@ -582,7 +586,7 @@ void vtlb_Core_Alloc()
// Win32 just needs this, since malloc always maps below 2GB. // Win32 just needs this, since malloc always maps below 2GB.
vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 ); vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 );
if( vtlbdata.alloc_base == NULL ) if( vtlbdata.alloc_base == NULL )
throw Exception::OutOfMemory( "Fatal Error: could not allocate 42Meg buffer for PS2's mappable system ram." ); throw Exception::OutOfMemory( L"PS2 mappable system ram (42 megs)" );
#endif #endif
} }

View File

@ -26,30 +26,28 @@ void StreamException_ThrowFromErrno( const wxString& streamname, errno_t errcode
{ {
case EINVAL: case EINVAL:
pxFailDev( L"Invalid argument" ); pxFailDev( L"Invalid argument" );
throw Exception::Stream( streamname, "Invalid argument" ); throw Exception::Stream( streamname ).SetDiagMsg(L"Invalid argument" );
case EACCES: // Access denied! case EACCES: // Access denied!
throw Exception::AccessDenied( streamname ); throw Exception::AccessDenied( streamname );
case EMFILE: // Too many open files! case EMFILE: // Too many open files!
throw Exception::CannotCreateStream( streamname, "Too many open files" ); // File handle allocation failure throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"Too many open files"); // File handle allocation failure
case EEXIST: case EEXIST:
throw Exception::CannotCreateStream( streamname, "File already exists" ); throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"File already exists");
case ENOENT: // File not found! case ENOENT: // File not found!
throw Exception::FileNotFound( streamname ); throw Exception::FileNotFound( streamname );
case EPIPE: case EPIPE:
throw Exception::BadStream( streamname, "Broken pipe" ); throw Exception::BadStream( streamname ).SetDiagMsg(L"Broken pipe");
case EBADF: case EBADF:
throw Exception::BadStream( streamname, "Bad file number" ); throw Exception::BadStream( streamname ).SetDiagMsg(L"Bad file number");
default: default:
throw Exception::Stream( streamname, throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General file/stream error [errno: %d]", errcode ));
wxsFormat( L"General file/stream error [errno: %d]", errcode )
);
} }
} }
@ -70,22 +68,20 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
throw Exception::FileNotFound( streamname ); throw Exception::FileNotFound( streamname );
case ERROR_TOO_MANY_OPEN_FILES: case ERROR_TOO_MANY_OPEN_FILES:
throw Exception::CannotCreateStream( streamname, "Too many open files" ); throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"Too many open files");
case ERROR_ACCESS_DENIED: case ERROR_ACCESS_DENIED:
throw Exception::AccessDenied( streamname ); throw Exception::AccessDenied( streamname );
case ERROR_INVALID_HANDLE: case ERROR_INVALID_HANDLE:
throw Exception::BadStream( streamname, "Stream object or handle is invalid" ); throw Exception::BadStream( streamname ).SetDiagMsg(L"Stream object or handle is invalid");
case ERROR_SHARING_VIOLATION: case ERROR_SHARING_VIOLATION:
throw Exception::AccessDenied( streamname, "Sharing violation" ); throw Exception::AccessDenied( streamname ).SetDiagMsg(L"Sharing violation");
default: default:
{ {
throw Exception::Stream( streamname, throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error ));
wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error )
);
} }
} }
} }

View File

@ -19,35 +19,6 @@
#include "App.h" #include "App.h"
#include "ConsoleLogger.h" #include "ConsoleLogger.h"
Exception::WinApiError::WinApiError( const char* msg )
{
ErrorId = GetLastError();
BaseException::InitBaseEx( msg );
}
wxString Exception::WinApiError::GetMsgFromWindows() const
{
if (!ErrorId)
return wxString();
const DWORD BUF_LEN = 2048;
TCHAR t_Msg[BUF_LEN];
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg );
return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId );
}
wxString Exception::WinApiError::FormatDisplayMessage() const
{
return m_message_user + L"\n\n" + GetMsgFromWindows();
}
wxString Exception::WinApiError::FormatDiagnosticMessage() const
{
return m_message_diag + L"\n\t" + GetMsgFromWindows();
}
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Win32 Console Pipes // Win32 Console Pipes
// As a courtesy and convenience, we redirect stdout/stderr to the console and logfile. // As a courtesy and convenience, we redirect stdout/stderr to the console and logfile.
@ -102,7 +73,7 @@ protected:
continue; continue;
} }
throw Exception::WinApiError( "ReadFile from pipe failed." ); throw Exception::WinApiError().SetDiagMsg(L"ReadFile from pipe failed.");
} }
if( u32_Read <= 3 ) if( u32_Read <= 3 )
@ -120,7 +91,7 @@ protected:
{ {
Yield(); Yield();
if( !PeekNamedPipe(m_outpipe, 0, 0, 0, &u32_avail, 0) ) if( !PeekNamedPipe(m_outpipe, 0, 0, 0, &u32_avail, 0) )
throw Exception::WinApiError( "Error peeking Pipe." ); throw Exception::WinApiError().SetDiagMsg(L"Error peeking Pipe.");
if( u32_avail == 0 ) break; if( u32_avail == 0 ) break;
@ -190,10 +161,10 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
try try
{ {
if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) ) if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) )
throw Exception::WinApiError( "CreatePipe failed." ); throw Exception::WinApiError().SetDiagMsg(L"CreatePipe failed.");
if( 0 == SetStdHandle( m_stdhandle, m_writepipe ) ) if( 0 == SetStdHandle( m_stdhandle, m_writepipe ) )
throw Exception::WinApiError( "SetStdHandle failed." ); throw Exception::WinApiError().SetDiagMsg(L"SetStdHandle failed.");
// Note: Don't use GetStdHandle to "confirm" the handle. // Note: Don't use GetStdHandle to "confirm" the handle.
// //
@ -224,7 +195,7 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
// the constructor, so re-pack a new exception: // the constructor, so re-pack a new exception:
Cleanup(); Cleanup();
throw Exception::RuntimeError( ex.FormatDiagnosticMessage(), ex.FormatDisplayMessage() ); throw Exception::RuntimeError().SetDiagMsg( ex.FormatDiagnosticMessage() ).SetUserMsg( ex.FormatDisplayMessage() );
} }
catch( BaseException& ex ) catch( BaseException& ex )
{ {

View File

@ -772,7 +772,7 @@ static void recAlloc()
recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" ); recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" );
if( recMem == NULL ) if( recMem == NULL )
throw Exception::OutOfMemory( "R3000a Init > failed to allocate memory for the recompiler." ); throw Exception::OutOfMemory( L"R3000A recompiled code cache" );
// Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory. // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory.
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
@ -782,7 +782,7 @@ static void recAlloc()
m_recBlockAlloc = (u8*)_aligned_malloc( m_recBlockAllocSize, 4096 ); m_recBlockAlloc = (u8*)_aligned_malloc( m_recBlockAllocSize, 4096 );
if( m_recBlockAlloc == NULL ) if( m_recBlockAlloc == NULL )
throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for baseblock lookup tables." ); throw Exception::OutOfMemory( L"R3000A BASEBLOCK lookup tables" );
u8* curpos = m_recBlockAlloc; u8* curpos = m_recBlockAlloc;
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK); recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK);
@ -796,7 +796,7 @@ static void recAlloc()
} }
if( s_pInstCache == NULL ) if( s_pInstCache == NULL )
throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for pInstCache." ); throw Exception::OutOfMemory( L"R3000 InstCache." );
ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE ); ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE );
_DynGen_Dispatchers(); _DynGen_Dispatchers();

View File

@ -17,6 +17,8 @@
#include "Common.h" #include "Common.h"
#include "Memory.h" #include "Memory.h"
#include "R5900Exceptions.h"
#include "R5900OpcodeTables.h" #include "R5900OpcodeTables.h"
#include "iR5900.h" #include "iR5900.h"
@ -61,6 +63,8 @@ bool g_cpuFlushedPC, g_recompilingDelaySlot, g_maySignalException;
#define X86 #define X86
static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units
static ScopedPtr<BaseR5900Exception> m_vmException;
static u8 *recMem = NULL; // the recompiled blocks will be here static u8 *recMem = NULL; // the recompiled blocks will be here
static u32* recConstBuf = NULL; // 64-bit pseudo-immediates static u32* recConstBuf = NULL; // 64-bit pseudo-immediates
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
@ -534,10 +538,9 @@ static const uint m_recBlockAllocSize =
static void recThrowHardwareDeficiency( const wxChar* extFail ) static void recThrowHardwareDeficiency( const wxChar* extFail )
{ {
throw Exception::HardwareDeficiency( throw Exception::HardwareDeficiency()
wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail), .SetDiagMsg(wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail))
wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ) .SetUserMsg(wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
);
} }
static void recAlloc() static void recAlloc()
@ -569,7 +572,7 @@ static void recAlloc()
} }
if( recMem == NULL ) if( recMem == NULL )
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating recompiled code buffer." ); throw Exception::OutOfMemory( L"R5900-32 recompiled code cache" );
// Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory. // Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory.
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
@ -579,7 +582,7 @@ static void recAlloc()
m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 ); m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 );
if( m_recBlockAlloc == NULL ) if( m_recBlockAlloc == NULL )
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating BASEBLOCK tables." ); throw Exception::OutOfMemory( L"R5900-32 BASEBLOCK tables" );
u8* curpos = m_recBlockAlloc; u8* curpos = m_recBlockAlloc;
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK); recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
@ -595,7 +598,7 @@ static void recAlloc()
} }
if( s_pInstCache == NULL ) if( s_pInstCache == NULL )
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating InstCache." ); throw Exception::OutOfMemory( L"R5900-32 InstCache" );
// No errors.. Proceed with initialization: // No errors.. Proceed with initialization:
@ -722,12 +725,14 @@ static void recExitExecution()
static void recCheckExecutionState() static void recCheckExecutionState()
{ {
if( eeRecIsReset || GetCoreThread().HasPendingStateChangeRequest() ) if( eeRecIsReset || m_vmException || GetCoreThread().HasPendingStateChangeRequest() )
{ {
recExitExecution(); recExitExecution();
} }
} }
static bool m_recExecutingCode = false;
static void recExecute() static void recExecute()
{ {
// Implementation Notes: // Implementation Notes:
@ -735,7 +740,9 @@ static void recExecute()
#if PCSX2_SEH #if PCSX2_SEH
eeRecIsReset = false; eeRecIsReset = false;
m_vmException = NULL;
g_EEFreezeRegs = true; g_EEFreezeRegs = true;
ScopedBool executing(m_recExecutingCode);
try { try {
EnterRecompiledCode(); EnterRecompiledCode();
@ -766,6 +773,8 @@ static void recExecute()
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate ); pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
} }
#endif #endif
if(m_vmException) m_vmException->Rethrow();
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
@ -1813,6 +1822,18 @@ StartRecomp:
s_pCurBlockEx = NULL; s_pCurBlockEx = NULL;
} }
// The only *safe* way to throw exceptions from the context of recompiled code.
// The exception is cached and the recompiler is exited safely using either an
// SEH unwind (MSW) or setjmp/longjmp (GCC).
void recThrowException( const BaseR5900Exception& ex )
{
if (!m_recExecutingCode) ex.Rethrow();
m_vmException = ex.Clone();
recExitExecution();
}
R5900cpu recCpu = R5900cpu recCpu =
{ {
recAlloc, recAlloc,
@ -1823,5 +1844,6 @@ R5900cpu recCpu =
recExecute, recExecute,
recCheckExecutionState, recCheckExecutionState,
recThrowException,
recClear, recClear,
}; };

View File

@ -17,6 +17,7 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "Common.h" #include "Common.h"
#include <deque>
#include "microVU.h" #include "microVU.h"
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -64,10 +65,9 @@ const __aligned(32) mVU_Globals mVUglob = {
//------------------------------------------------------------------ //------------------------------------------------------------------
_f void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) { _f void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) {
throw Exception::HardwareDeficiency( throw Exception::HardwareDeficiency()
wxsFormat( L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail), .SetDiagMsg(wxsFormat(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail))
wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ) .SetUserMsg(wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
);
} }
// Only run this once per VU! ;) // Only run this once per VU! ;)
@ -96,7 +96,7 @@ _f void mVUinit(VURegs* vuRegsPtr, int vuIndex) {
} }
mVU->dispCache = SysMmapEx(NULL, mVUdispCacheSize, 0, (mVU->index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher")); mVU->dispCache = SysMmapEx(NULL, mVUdispCacheSize, 0, (mVU->index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher"));
if (!mVU->dispCache) throw Exception::OutOfMemory("microVU Error: Failed to allocate dispatcher memory!"); if (!mVU->dispCache) throw Exception::OutOfMemory( mVU->index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" );
memset(mVU->dispCache, 0xcc, mVUdispCacheSize); memset(mVU->dispCache, 0xcc, mVUdispCacheSize);
// Setup Entrance/Exit Points // Setup Entrance/Exit Points
@ -165,12 +165,8 @@ void mVUresizeCache(mV, u32 size) {
if (size > (u32)mVUcacheMaxSize) { if (mVU->cacheSize==mVUcacheMaxSize) return; size = mVUcacheMaxSize; } if (size > (u32)mVUcacheMaxSize) { if (mVU->cacheSize==mVUcacheMaxSize) return; size = mVUcacheMaxSize; }
if (mVU->cache) Console.WriteLn(Color_Green, "microVU%d: Attempting to resize Cache [%dmb]", mVU->index, size/_1mb); if (mVU->cache) Console.WriteLn(Color_Green, "microVU%d: Attempting to resize Cache [%dmb]", mVU->index, size/_1mb);
// Give SysMmapEx a NULL and let the OS pick the memory for us: mVU can work with any u8* cache = SysMmapEx(NULL, size, 0, (mVU->index ? "Micro VU1 RecCache" : "Micro VU0 RecCache"));
// address the operating system gives us, and unlike the EE/IOP there's not much convenience if(!cache && !mVU->cache) throw Exception::OutOfMemory( wxsFormat( L"Micro VU%d recompiled code cache", mVU->index) );
// to debugging if the address is known anyway due to mVU's complex memory layouts (caching).
u8* cache = SysMmapEx(NULL, size, 0, (mVU->index ? "Micro VU1" : "Micro VU0"));
if(!cache && !mVU->cache) throw Exception::OutOfMemory("microVU Error: Failed to allocate recompiler memory!");
if(!cache) { Console.Error("microVU%d Error - Cache Resize Failed...", mVU->index); return; } if(!cache) { Console.Error("microVU%d Error - Cache Resize Failed...", mVU->index); return; }
if (mVU->cache) { if (mVU->cache) {
HostSys::Munmap(mVU->cache, mVU->cacheSize); HostSys::Munmap(mVU->cache, mVU->cacheSize);
@ -272,7 +268,7 @@ _mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
microProgramQuick& quick = mVU->prog.quick[startPC/8]; microProgramQuick& quick = mVU->prog.quick[startPC/8];
microProgramList& list = mVU->prog.prog [startPC/8]; microProgramList& list = mVU->prog.prog [startPC/8];
if(!quick.prog) { // If null, we need to search for new program if(!quick.prog) { // If null, we need to search for new program
deque<microProgram*>::iterator it = list.list->begin(); deque<microProgram*>::iterator it( list.list->begin() );
for ( ; it != list.list->end(); it++) { for ( ; it != list.list->end(); it++) {
if (mVUcmpProg<vuIndex>(*it[0], 0)) { if (mVUcmpProg<vuIndex>(*it[0], 0)) {
quick.block = it[0]->block[startPC/8]; quick.block = it[0]->block[startPC/8];
@ -282,7 +278,13 @@ _mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
return mVUentryGet(mVU, quick.block, startPC, pState); return mVUentryGet(mVU, quick.block, startPC, pState);
} }
} }
// If cleared and program not found, make a new program instance // If cleared and program not found, make a new program instance
// Exception note: It's bad news if the recompiler throws any exceptions, so we have a clause to
// assert if an exception occurs. The rec should be pretty much exception safe, except for
// critical errors that would result in a crash regardless.
try {
mVU->prog.cleared = 0; mVU->prog.cleared = 0;
mVU->prog.isSame = 1; mVU->prog.isSame = 1;
mVU->prog.cur = mVUcreateProg<vuIndex>(startPC/8); mVU->prog.cur = mVUcreateProg<vuIndex>(startPC/8);
@ -290,7 +292,16 @@ _mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
quick.block = mVU->prog.cur->block[startPC/8]; quick.block = mVU->prog.cur->block[startPC/8];
quick.prog = mVU->prog.cur; quick.prog = mVU->prog.cur;
list.list->push_front(mVU->prog.cur); list.list->push_front(mVU->prog.cur);
return entryPoint; return entryPoint;
} catch( BaseException& ex ) {
pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + ex.FormatDiagnosticMessage(), mVU->index) );
} catch( std::exception& ex ) {
pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + Exception::RuntimeError(ex).FormatDiagnosticMessage(), mVU->index) );
}
return NULL;
} }
// If list.quick, then we've already found and recompiled the program ;) // If list.quick, then we've already found and recompiled the program ;)
mVU->prog.isSame = -1; mVU->prog.isSame = -1;

View File

@ -33,7 +33,7 @@ protected:
void alloc(int size) { void alloc(int size) {
mData = SysMmapEx(NULL, size, 0, "nVif_BlockBuffer"); mData = SysMmapEx(NULL, size, 0, "nVif_BlockBuffer");
if (!mData) throw Exception::OutOfMemory("nVif Error: Failed to allocate recompiler memory!"); if (!mData) throw Exception::OutOfMemory(L"nVif recompiled code buffer (nVif_BlockBuffer)");
clear(); clear();
} }
void dealloc(u8* &dPtr, int size) { void dealloc(u8* &dPtr, int size) {

View File

@ -83,8 +83,7 @@ public:
if( bucket.Chain = (T*)_aligned_realloc( bucket.Chain, sizeof(T)*(bucket.Size+1), 16), bucket.Chain==NULL ) { if( bucket.Chain = (T*)_aligned_realloc( bucket.Chain, sizeof(T)*(bucket.Size+1), 16), bucket.Chain==NULL ) {
throw Exception::OutOfMemory( throw Exception::OutOfMemory(
wxsFormat(L"Out of memory re-allocating hash bucket (bucket size=%d)", bucket.Size+1), wxsFormat(L"HashBucket Chain (bucket size=%d)", bucket.Size+1)
wxEmptyString
); );
} }
memcpy_const(&bucket.Chain[bucket.Size++], &dataPtr, sizeof(T)); memcpy_const(&bucket.Chain[bucket.Size++], &dataPtr, sizeof(T));

View File

@ -2008,6 +2008,8 @@ void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr)
size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff); size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff);
pDest = &Path1Buffer[Path1WritePos*16]; pDest = &Path1Buffer[Path1WritePos*16];
pxAssumeMsg((Path1WritePos+size < sizeof(Path1Buffer)), "XGKick Buffer Overflow detected on Path1Buffer!"); pxAssumeMsg((Path1WritePos+size < sizeof(Path1Buffer)), "XGKick Buffer Overflow detected on Path1Buffer!");
//DevCon.Warning("Storing size %x PATH 1", size); //DevCon.Warning("Storing size %x PATH 1", size);

View File

@ -360,13 +360,13 @@ static void SuperVUAlloc(int vuindex)
if (s_recVUMem == NULL) if (s_recVUMem == NULL)
{ {
throw Exception::VirtualMemoryMapConflict( throw Exception::VirtualMemoryMapConflict()
// untranslated diagnostic msg, use exception's default for translation .SetDiagMsg(wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." ))
wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." ), .SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc",
L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory "
// Translated message L"ranges required, and will not be available for use. This is not a critical error, since "
_("Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory ranges required.") L"the sVU rec is obsolete, and you should use microVU instead anyway. :)"
); ));
} }
ProfilerRegisterSource("sVU Rec", s_recVUMem, VU_EXESIZE); ProfilerRegisterSource("sVU Rec", s_recVUMem, VU_EXESIZE);
@ -453,7 +453,7 @@ void SuperVUReset(int vuindex)
if (s_recVUMem == NULL) if (s_recVUMem == NULL)
return; return;
//jASSUME( s_recVUMem != NULL ); //pxAssume( s_recVUMem != NULL );
if (vuindex < 0) if (vuindex < 0)
{ {
@ -470,7 +470,6 @@ void SuperVUReset(int vuindex)
else else
{ {
DbgCon.WriteLn("SuperVU [VU%d]: Resetting the recs and junk", vuindex); DbgCon.WriteLn("SuperVU [VU%d]: Resetting the recs and junk", vuindex);
list<VuFunctionHeader*>::iterator it;
if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8)); if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8));
if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8)); if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8));