Savestates work! Not much else does yet (settings, etc), but at least this monkey's off my back. I can work on tying up more loose ends now. :)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1975 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-10-07 19:20:11 +00:00
parent a2a495e842
commit eda5d1d834
49 changed files with 986 additions and 533 deletions

View File

@ -429,6 +429,10 @@
RelativePath="..\..\include\intrin_x86.h"
>
</File>
<File
RelativePath="..\..\include\Utilities\Listeners.h"
>
</File>
<File
RelativePath="..\..\include\Utilities\lnx_memzero.h"
>

View File

@ -191,7 +191,7 @@ typedef struct _PS2E_SessionInfo
// Sony's assigned serial number, valid only for CD/CDVD games (ASCII-Z string).
// Ex: SLUS-2932 (if the running app is not a sony-registered game, the serial
// will be a zero length string).
const char Serial[16];
char Serial[16];
} PS2E_SessionInfo;

View File

@ -45,7 +45,7 @@
#if defined(PCSX2_DEBUG)
# define pxAssertMsg(cond, msg) ( (!!(cond)) || \
(pxOnAssert(__TFILE__, __LINE__, __WXFUNCTION__, _T(#cond), msg), !!(cond)) )
(pxOnAssert(__TFILE__, __LINE__, __WXFUNCTION__, _T(#cond), msg), likely(cond)) )
# define pxAssertDev(cond,msg) pxAssertMsg(cond, msg)
@ -57,26 +57,28 @@
// Devel builds use __assume for standard assertions and call pxOnAssertDevel
// for AssertDev brand assertions (which typically throws a LogicError exception).
# define pxAssertMsg(cond, msg) (!!(cond))
# define pxAssertMsg(cond, msg) (__assume(cond), likely(cond))
# define pxAssertDev(cond, msg) ( (!!(cond)) || \
(pxOnAssert(__TFILE__, __LINE__, __WXFUNCTION__, _T(#cond), msg), !!(cond)) )
(pxOnAssert(__TFILE__, __LINE__, __WXFUNCTION__, _T(#cond), msg), likely(cond)) )
# define pxFail(msg) __assume(false)
# define pxFail(msg) (__assume(false), false)
# define pxFailDev(msg ) pxAssertDev(false, msg)
#else
// Release Builds just use __assume as an optimization, and always return 'true'
// indicating the assertion check succeeded (no actual check is performed).
// Release Builds just use __assume as an optimization, and return the conditional
// as a result (if .
# define pxAssertMsg(cond, msg) (__assume(cond), true)
# define pxAssertDev(cond, msg) (__assume(cond), true)
# define pxFail(msg) (__assume(false), true)
# define pxFailDev(msg) (__assume(false), true)
# define pxAssertMsg(cond, msg) (__assume(cond), likely(cond))
# define pxAssertDev(cond, msg) (__assume(cond), likely(cond))
# define pxFail(msg) (__assume(false), false)
# define pxFailDev(msg) (__assume(false), false)
#endif
__cold
#define pxAssert(cond) pxAssertMsg(cond, (wxChar*)NULL)
extern void pxOnAssert( const wxChar* file, int line, const char* func, const wxChar* cond, const wxChar* msg);

View File

@ -16,6 +16,7 @@
#pragma once
#include "Dependencies.h"
#include "StringHelpers.h"
// --------------------------------------------------------------------------------------
// DESTRUCTOR_CATCHALL - safe destructor helper
@ -133,7 +134,7 @@ namespace Exception
//
#define DEFINE_EXCEPTION_COPYTORS( classname ) \
virtual ~classname() throw() {} \
virtual void Rethrow() const { throw classname( *this ); } \
virtual void Rethrow() const { throw *this; } \
virtual BaseException* Clone() const { return new classname( *this ); }
#define DEFINE_RUNTIME_EXCEPTION( classname, defmsg ) \
@ -149,11 +150,13 @@ namespace Exception
explicit classname( const wxString& msg_eng ) { BaseException::InitBaseEx( msg_eng, wxEmptyString ); }
// ---------------------------------------------------------------------------------------
// Generalized Exceptions: RuntimeError / LogicError / ObjectIsNull
// RuntimeError / LogicError - Generalized Exceptions
// ---------------------------------------------------------------------------------------
class RuntimeError : public virtual BaseException
{
public:
bool IsSilent;
public:
DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
};
@ -166,7 +169,38 @@ namespace Exception
DEFINE_LOGIC_EXCEPTION( LogicError, wxLt("An unhandled logic error has occurred.") )
};
class ObjectIsNull : public virtual RuntimeError
// --------------------------------------------------------------------------------------
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion
// --------------------------------------------------------------------------------------
// Typically the PCSX2 interface issues popup dialogs for runtime errors. This exception
// instead issues a "silent" cancelation that is handled by the app gracefully (generates
// log, and resumes messages queue processing).
//
// 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.
class CancelEvent : public virtual RuntimeError
{
public:
DEFINE_EXCEPTION_COPYTORS( CancelEvent )
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;
// overridden message formatters only use the diagnostic version...
}
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
// --------------------------------------------------------------------------------------
class ObjectIsNull : public virtual CancelEvent
{
public:
wxString ObjectName;
@ -175,17 +209,16 @@ namespace Exception
explicit ObjectIsNull( const char* objname="unspecified" )
{
m_message_diag = wxString::FromUTF8( objname );
m_message_diag = fromUTF8( objname );
// overridden message formatters only use the diagnostic version...
}
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
// ---------------------------------------------------------------------------------------
// OutOfMemory / InvalidOperation / InvalidArgument / IndexBoundsFault / ParseError
// OutOfMemory / InvalidOperation / InvalidArgument / IndexBoundsFault / ParseError
// ---------------------------------------------------------------------------------------
class OutOfMemory : public virtual RuntimeError
@ -282,17 +315,17 @@ namespace Exception
explicit classname( const char* objname, const char* msg=defmsg ) \
{ \
BaseException::InitBaseEx( msg ); \
StreamName = wxString::FromUTF8( objname ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const char* objname, const wxString& msg_eng, const wxString& msg_xlt ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_xlt ); \
StreamName = wxString::FromUTF8( objname ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const char* objname, const wxString& msg_eng ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_eng ); \
StreamName = wxString::FromUTF8( objname ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const wxString& objname, const wxString& msg_eng ) \
{ \

View File

@ -0,0 +1,204 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <wx/event.h>
template< typename EvtType >
struct EventListener
{
typedef void FuncType( void* object, const EvtType& evt );
void* object;
FuncType* OnEvent;
EventListener( FuncType* fnptr )
{
object = NULL;
OnEvent = fnptr;
}
EventListener( void* objhandle, FuncType* fnptr )
{
object = objhandle;
OnEvent = fnptr;
}
bool operator ==( const EventListener& right ) const
{
return (object == right.object) && (OnEvent == right.OnEvent);
}
bool operator !=( const EventListener& right ) const
{
return this->operator ==(right);
}
};
template< typename EvtType >
class EventSource
{
public:
typedef typename EventListener<EvtType> ListenerType;
typedef typename std::list< ListenerType > ListenerList;
typedef typename ListenerList::const_iterator Handle;
protected:
ListenerList m_listeners;
public:
virtual ~EventSource() throw() {}
virtual void Remove( const ListenerType& listener )
{
m_listeners.remove( listener );
}
virtual void Remove( const Handle& listenerHandle )
{
m_listeners.erase( listenerHandle );
}
virtual Handle AddFast( const ListenerType& listener )
{
m_listeners.push_front( listener );
return m_listeners.begin();
}
// Checks for duplicates before adding the event.
virtual inline void Add( const ListenerType& listener );
virtual inline void RemoveObject( const void* object );
Handle Add( void* objhandle, typename ListenerType::FuncType* fnptr )
{
return Add( Handle( objhandle, fnptr ) );
}
void Remove( void* objhandle, typename ListenerType::FuncType* fnptr )
{
Remove( Handle( objhandle, fnptr ) );
}
void Dispatch( const wxCommandEvent& evt ) const
{
Handle iter = m_listeners.begin();
while( iter != m_listeners.end() )
{
try
{
iter->OnEvent( iter->object, evt );
}
catch( Exception::RuntimeError& ex )
{
Console::Error( L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage() );
}
catch( BaseException& ex )
{
}
}
}
};
// --------------------------------------------------------------------------------------
// EventListenerBinding
// --------------------------------------------------------------------------------------
// Encapsulated event listener binding, provides the "benefits" of object unwinding.
//
template< typename EvtType = wxCommandEvent >
class EventListenerBinding
{
public:
typedef typename EventSource<EvtType>::ListenerType ListenerHandle;
typedef typename EventSource<EvtType>::Handle ConstIterator;
protected:
EventSource<EvtType>& m_source;
const ListenerHandle m_listener;
ConstIterator m_iter;
bool m_attached;
public:
EventListenerBinding( EventSource<EvtType>& source, const ListenerHandle& listener, bool autoAttach=true ) :
m_source( source )
, m_listener( listener )
, m_attached( false )
{
// If you want to assert on null pointers, you'll need to do the check yourself. There's
// too many cases where silently ignoring null pointers is the desired behavior.
//if( !pxAssertDev( listener.OnEvent != NULL, "NULL listener callback function." ) ) return;
if( autoAttach ) Attach();
}
virtual ~EventListenerBinding() throw()
{
Detach();
}
void Detach()
{
if( !m_attached ) return;
m_source.Remove( m_iter );
m_attached = false;
}
void Attach()
{
if( m_attached || (m_listener.OnEvent == NULL) ) return;
m_iter = m_source.AddFast( m_listener );
m_attached = true;
}
};
typedef EventSource<wxCommandEvent> CmdEvt_Source;
typedef EventListener<wxCommandEvent> CmdEvt_Listener;
typedef EventListenerBinding<wxCommandEvent> CmdEvt_ListenerBinding;
// Checks for duplicates before adding the event.
template< typename EvtType >
void EventSource<EvtType>::Add( const ListenerType& listener )
{
if( !pxAssertDev( listener.OnEvent != NULL, "NULL listener callback function." ) ) return;
Handle iter = m_listeners.begin();
while( iter != m_listeners.end() )
{
if( *iter == listener ) return;
++iter;
}
AddFast( listener );
}
// removes all listeners which reference the given object. Use for assuring object deletion.
template< typename EvtType >
void EventSource<EvtType>::RemoveObject( const void* object )
{
class PredicatesAreTheThingsOfNightmares
{
protected:
const void* const m_object_match;
public:
PredicatesAreTheThingsOfNightmares( const void* objmatch ) : m_object_match( objmatch ) { }
bool operator()( const ListenerType& src )
{
return src.object == m_object_match;
}
};
m_listeners.remove_if( PredicatesAreTheThingsOfNightmares( object ) );
}

View File

@ -15,6 +15,10 @@
#pragma once
#ifdef __WXMSW__
# include <wx/msw/wrapwin.h>
#else
//////////////////////////////////////////////////////////////////////////////////////////
// Windows Redtape! No windows.h should be included without it!
//
@ -40,3 +44,4 @@
#undef max
#endif
#endif

View File

@ -15,25 +15,14 @@
#pragma once
#include <semaphore.h>
#include <errno.h> // EBUSY
#include <pthread.h>
#include <semaphore.h>
#include "Pcsx2Defs.h"
#include "ScopedPtr.h"
namespace Exception
{
//////////////////////////////////////////////////////////////////////////////////////////
// Thread termination exception, used to quickly terminate threads from anywhere in the
// thread's call stack. This exception is handled by the PCSX2 PersistentThread class. Threads
// not derived from that class will not handle this exception.
//
class ThreadTermination
{
};
}
#undef Yield // release th burden of windows.h global namespace spam.
class wxTimeSpan;
namespace Threading
@ -57,6 +46,38 @@ namespace Threading
};
#endif
// --------------------------------------------------------------------------------------
// NonblockingMutex
// --------------------------------------------------------------------------------------
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
// trylock(), but without any of the extra overhead needed to set up a structure capable
// of blocking waits. It basically optimizes to a single InterlockedExchange.
//
// Simple use: if TryLock() returns false, the Bool is already interlocked by another thread.
// If TryLock() returns true, you've locked the object and are *responsible* for unlocking
// it later.
//
class NonblockingMutex
{
protected:
volatile long val;
public:
NonblockingMutex() : val( false ) {}
virtual ~NonblockingMutex() throw() {};
bool TryLock() throw()
{
return !_InterlockedExchange( &val, true );
}
bool IsLocked()
{ return !!val; }
void Release()
{ val = false; }
};
struct Semaphore
{
sem_t sema;
@ -166,7 +187,7 @@ namespace Threading
pthread_t m_thread;
Semaphore m_sem_event; // general wait event that's needed by most threads.
Semaphore m_sem_finished; // used for canceling and closing threads in a deadlock-safe manner
MutexLock m_lock_start; // used to lock the Start() code from starting simutaneous threads accidentally.
MutexLock m_lock_start; // used to lock the Start() code from starting simultaneous threads accidentally.
volatile long m_detached; // a boolean value which indicates if the m_thread handle is valid
volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
@ -190,27 +211,49 @@ namespace Threading
bool IsSelf() const;
wxString GetName() const;
void _ThreadCleanup();
protected:
// Extending classes should always implement your own OnStart(), which is called by
// Start() once necessary locks have been obtained. Do not override Start() directly
// unless you're really sure that's what you need to do. ;)
virtual void OnStart()=0;
virtual void OnThreadCleanup()=0;
void DoSetThreadName( const wxString& name );
void DoSetThreadName( __unused const char* name );
void _internal_execute();
// Used to dispatch the thread callback function.
// (handles some thread cleanup on Win32, and is basically a typecast
// on linux).
static void* _internal_callback( void* func );
// Implemented by derived class to handle threading actions!
virtual void ExecuteTask()=0;
// Inserts a thread cancellation point. If the thread has received a cancel request, this
// function will throw an SEH exception designed to exit the thread (so make sure to use C++
// object encapsulation for anything that could leak resources, to ensure object unwinding
// and cleanup, or use the DoThreadCleanup() override to perform resource cleanup).
void TestCancel();
// Yields this thread to other threads and checks for cancellation. A sleeping thread should
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
// or better yet, disable cancellation of the thread completely with DisableCancellation().
//
// Parameters:
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
// depending on operating system/platform). If ms is 0 or unspecified, then a single
// timeslice is yielded to other contending threads. If no threads are contending for
// time when ms==0, then no yield is done, but cancellation is still tested.
void Yield( int ms = 0 )
{
pxAssert( IsSelf() );
Threading::Sleep( ms );
TestCancel();
}
// ----------------------------------------------------------------------------
// Section of methods for internal use only.
void _DoSetThreadName( const wxString& name );
void _DoSetThreadName( __unused const char* name );
void _internal_execute();
void _try_virtual_invoke( void (PersistentThread::*method)() );
void _ThreadCleanup();
static void* _internal_callback( void* func );
static void _pt_callback_cleanup( void* handle );
};
//////////////////////////////////////////////////////////////////////////////////////////

View File

@ -15,6 +15,10 @@
#pragma once
#ifdef _MSC_VER
# pragma warning(disable:4063) // case '1' is not a valid value for switch()
#endif
// These functions are meant for memset operations of constant length only.
// For dynamic length clears, use the C-compiler provided memset instead.

View File

@ -227,14 +227,14 @@ void IConsoleWriter::_Write( const char* fmt, va_list args ) const
{
std::string m_format_buffer;
vssprintf( m_format_buffer, fmt, args );
Write( wxString::FromUTF8( m_format_buffer.c_str() ) );
Write( fromUTF8( m_format_buffer.c_str() ) );
}
void IConsoleWriter::_WriteLn( const char* fmt, va_list args ) const
{
std::string m_format_buffer;
vssprintf( m_format_buffer, fmt, args );
WriteLn( wxString::FromUTF8( m_format_buffer.c_str() ) );
WriteLn( fromUTF8( m_format_buffer.c_str() ) );
}
void IConsoleWriter::_WriteLn( ConsoleColors color, const char* fmt, va_list args ) const

View File

@ -116,11 +116,23 @@ wxString Exception::BaseException::FormatDiagnosticMessage() const
return m_message_diag + L"\n\n" + m_stacktrace;
}
// ------------------------------------------------------------------------
wxString Exception::CancelEvent::FormatDiagnosticMessage() const
{
// FIXME: This should probably just log a single line from the stacktrace.. ?
return L"Action canceled: " + m_message_diag;
}
wxString Exception::CancelEvent::FormatDisplayMessage() const
{
return L"Action canceled: " + m_message_diag;
}
// ------------------------------------------------------------------------
wxString Exception::ObjectIsNull::FormatDiagnosticMessage() const
{
return wxsFormat(
L"An attempted reference to the %s has failed; the frame does not exist or it's handle is null.",
L"reference to '%s' failed : handle is null.",
m_message_diag.c_str()
) + m_stacktrace;
}
@ -128,7 +140,7 @@ wxString Exception::ObjectIsNull::FormatDiagnosticMessage() const
wxString Exception::ObjectIsNull::FormatDisplayMessage() const
{
return wxsFormat(
L"An attempted reference to the %s has failed; the frame does not exist or it's handle is null.",
L"reference to '%s' failed : handle is null.",
m_message_diag.c_str()
);
}

View File

@ -15,24 +15,30 @@
#include "PrecompiledHeader.h"
#include "Threading.h"
#include "wxBaseTools.h"
#include <wx/datetime.h>
#include <wx/thread.h>
#ifdef _WIN32
# include <wx/msw/wrapwin.h> // for thread renaming features
#endif
#include <wx/app.h>
#ifdef __LINUX__
# include <signal.h> // for pthread_kill, which is in pthread.h on w32-pthreads
#endif
#include "Threading.h"
#include "wxBaseTools.h"
#include <wx/datetime.h>
#include <wx/thread.h>
using namespace Threading;
namespace Threading
{
static const wxTimeSpan ts_msec_250( 0, 0, 0, 250 );
static void _pt_callback_cleanup( void* handle )
void PersistentThread::_pt_callback_cleanup( void* handle )
{
((PersistentThread*)handle)->_ThreadCleanup();
}
@ -59,11 +65,11 @@ namespace Threading
{
try
{
wxString logfix = L"Thread Destructor for " + m_name;
Console.WriteLn( L"Thread Log: Executing destructor for " + m_name );
if( m_running )
{
Console.WriteLn( logfix + L": Waiting for running thread to end.");
Console.WriteLn( L"\tWaiting for running thread to end...");
#if wxUSE_GUI
m_sem_finished.WaitGui();
#else
@ -73,9 +79,7 @@ namespace Threading
// it gets destroyed, otherwise th mutex handle would become invalid.
ScopedLock locker( m_lock_start );
}
else
Console.WriteLn( logfix + L": thread not running.");
Sleep( 1 );
Threading::Sleep( 1 );
Detach();
}
DESTRUCTOR_CATCHALL
@ -189,47 +193,22 @@ namespace Threading
m_except->Rethrow();
}
// invoked internally when canceling or exiting the thread. Extending classes should implement
// OnThreadCleanup() to extend clenup functionality.
void PersistentThread::_ThreadCleanup()
void PersistentThread::TestCancel()
{
pxAssertMsg( IsSelf(), "Thread affinity error." ); // only allowed from our own thread, thanks.
// Typically thread cleanup needs to lock against thread startup, since both
// will perform some measure of variable inits or resets, depending on how the
// derrived class is implemented.
ScopedLock startlock( m_lock_start );
OnThreadCleanup();
m_running = false;
m_sem_finished.Post();
pxAssert( IsSelf() );
pthread_testcancel();
}
wxString PersistentThread::GetName() const
// Executes the virtual member method
void PersistentThread::_try_virtual_invoke( void (PersistentThread::*method)() )
{
return m_name;
}
void PersistentThread::_internal_execute()
{
m_running = true;
DoSetThreadName( m_name );
try {
ExecuteTask();
}
catch( std::logic_error& ex )
{
throw Exception::LogicError( wxsFormat( L"(thread: %s) STL Logic Error: %s\n\t%s",
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
);
}
catch( Exception::LogicError& ex )
{
m_except->DiagMsg() = wxsFormat( L"(thread:%s) ", GetName().c_str() ) + m_except->DiagMsg();
ex.Rethrow();
(this->*method)();
}
// ----------------------------------------------------------------------------
// Neat repackaging for STL Runtime errors...
//
catch( std::runtime_error& ex )
{
m_except = new Exception::RuntimeError(
@ -244,16 +223,79 @@ namespace Threading
)
);
}
// ----------------------------------------------------------------------------
catch( Exception::RuntimeError& ex )
{
m_except = ex.Clone();
m_except->DiagMsg() = wxsFormat( L"(thread:%s) ", GetName().c_str() ) + m_except->DiagMsg();
}
// ----------------------------------------------------------------------------
// Should we let logic errors propagate, or swallow them and let the thread manager
// handle them? Hmm..
/*catch( std::logic_error& ex )
{
throw Exception::LogicError( wxsFormat( L"(thread: %s) STL Logic Error: %s\n\t%s",
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
);
}
catch( Exception::LogicError& ex )
{
m_except = ex.Clone();
m_except->DiagMsg() = wxsFormat( L"(thread:%s) ", GetName().c_str() ) + m_except->DiagMsg();
}*/
// ----------------------------------------------------------------------------
// BaseException / std::exception -- same deal. Allow propagation or no?
//
/*catch( std::exception& ex )
{
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL exception: %s\n\t%s",
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
);
}
catch( Exception::BaseException& ex )
{
m_except = ex.Clone();
m_except->DiagMsg() = wxsFormat( L"(thread:%s) ", GetName().c_str() ) + m_except->DiagMsg();
}*/
}
// invoked internally when canceling or exiting the thread. Extending classes should implement
// OnThreadCleanup() to extend cleanup functionality.
void PersistentThread::_ThreadCleanup()
{
pxAssertMsg( IsSelf(), "Thread affinity error." ); // only allowed from our own thread, thanks.
// Typically thread cleanup needs to lock against thread startup, since both
// will perform some measure of variable inits or resets, depending on how the
// derived class is implemented.
ScopedLock startlock( m_lock_start );
_try_virtual_invoke( &PersistentThread::OnThreadCleanup );
m_running = false;
m_sem_finished.Post();
}
wxString PersistentThread::GetName() const
{
return m_name;
}
void PersistentThread::_internal_execute()
{
m_running = true;
_DoSetThreadName( m_name );
_try_virtual_invoke( &PersistentThread::ExecuteTask );
}
void PersistentThread::OnStart() {}
void PersistentThread::OnThreadCleanup() {}
// passed into pthread_create, and is used to dispatch the thread's object oriented
// callback function
void* PersistentThread::_internal_callback( void* itsme )
{
jASSUME( itsme != NULL );
@ -265,12 +307,12 @@ namespace Threading
return NULL;
}
void PersistentThread::DoSetThreadName( const wxString& name )
void PersistentThread::_DoSetThreadName( const wxString& name )
{
DoSetThreadName( toUTF8(name) );
_DoSetThreadName( toUTF8(name) );
}
void PersistentThread::DoSetThreadName( __unused const char* name )
void PersistentThread::_DoSetThreadName( __unused const char* name )
{
pxAssertMsg( IsSelf(), "Thread affinity error." ); // only allowed from our own thread, thanks.

View File

@ -18,7 +18,6 @@
#include "x86emitter/tools.h"
#include "Threading.h"
#ifdef _WIN32
#include "implement.h" // win32 pthreads implementations.
#endif

View File

@ -15,11 +15,13 @@
#include "PrecompiledHeader.h"
#include "internal.h"
#include "tools.h"
#include "Utilities/RedtapeWindows.h"
#include "Utilities/Threading.h"
#include "internal.h"
#include "tools.h"
using namespace x86Emitter;
__aligned16 x86CPU_INFO x86caps;

View File

@ -5,7 +5,7 @@
Name="PcsxBaseProperties"
OutputDirectory="$(SolutionDir)\bin\$(PcsxSubsection)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
DeleteExtensionsOnClean="*.bsc;*.idb;*.sbr;*.res;*.pch;*.pdb;*.obj;*.ilk;*.tlb;*.tli;*.tlh;*.tmp;*.rsp;*.pgc;*.pgd;*.meta;$(TargetPath)"
DeleteExtensionsOnClean="*.bsc;*.idb;*.sbr;*.res;*.pch;*.pdb;*.obj;*.tlb;*.tli;*.tlh;*.tmp;*.rsp;*.pgc;*.pgd;*.meta;$(TargetPath)"
>
<Tool
Name="VCCLCompilerTool"
@ -18,6 +18,7 @@
WarningLevel="3"
DebugInformationFormat="3"
CompileAs="0"
DisableSpecificWarnings="4063;4100"
/>
<Tool
Name="VCLinkerTool"

View File

@ -16,6 +16,7 @@
WarningLevel="3"
DebugInformationFormat="3"
CompileAs="0"
DisableSpecificWarnings="4063;4100"
/>
<Tool
Name="VCLinkerTool"

View File

@ -19,7 +19,7 @@
#define ENABLE_TIMESTAMPS
#ifdef _WIN32
#include <windows.h>
# include <wx/msw/wrapwin.h>
#endif
#include <ctype.h>

View File

@ -17,7 +17,8 @@
#include "IsoFileTools.h"
#ifdef _WIN32
#include <windows.h>
# include <wx/msw/wrapwin.h>
void *_openfile(const char *filename, int flags)
{

View File

@ -102,7 +102,6 @@ protected:
int m_CopyCommandTally;
int m_CopyDataTally;
volatile bool m_RingBufferIsBusy;
volatile bool m_LoadState;
// Counts the number of vsync frames queued in the MTGS ringbuffer. This is used to
// throttle the number of frames allowed to be rendered ahead of time for games that
@ -153,7 +152,8 @@ public:
protected:
void OpenPlugin();
void OnSuspendInThread();
void OnResumeInThread();
void OnPauseInThread() {}
void OnResumeInThread( bool IsSuspended );
void OnResumeReady();

View File

@ -206,7 +206,7 @@ struct GIFregisters
u32 padding[3];
tGIF_MODE mode;
u32 padding1[3];
tGIF_STAT stat;
tGIF_STAT stat;
u32 padding2[7];
tGIF_TAG0 tag0;
@ -218,7 +218,7 @@ struct GIFregisters
u32 tag3;
u32 padding6[3];
tGIF_CNT cnt;
tGIF_CNT cnt;
u32 padding7[3];
tGIF_P3CNT p3cnt;
u32 padding8[3];

View File

@ -54,7 +54,6 @@ public:
extern StartupParams g_Startup;
extern void States_Load( const wxString& file );
extern void States_Save( const wxString& file );
extern bool States_isSlotUsed(int num);

View File

@ -99,7 +99,6 @@ mtgsThreadObject::mtgsThreadObject() :
, m_CopyCommandTally( 0 )
, m_CopyDataTally( 0 )
, m_RingBufferIsBusy( false )
, m_LoadState( false )
, m_QueuedFrames( 0 )
, m_lock_FrameQueueCounter()
, m_packet_size( 0 )
@ -127,7 +126,6 @@ void mtgsThreadObject::OnStart()
m_WritePos = 0;
m_RingBufferIsBusy = false;
m_LoadState = false;
m_QueuedFrames = 0;
m_packet_size = 0;
@ -435,9 +433,9 @@ void mtgsThreadObject::OnSuspendInThread()
_clean_close_gs( NULL );
}
void mtgsThreadObject::OnResumeInThread()
void mtgsThreadObject::OnResumeInThread( bool isSuspended )
{
if( !m_LoadState )
if( isSuspended )
OpenPlugin();
}
@ -812,7 +810,6 @@ void mtgsThreadObject::Freeze( int mode, MTGS_FreezeData& data )
{
AtomicExchange( m_RingPos, m_WritePos );
SendPointerPacket( GS_RINGTYPE_FREEZE, mode, &data );
m_LoadState = true;
SetEvent();
Resume();
}
@ -820,7 +817,6 @@ void mtgsThreadObject::Freeze( int mode, MTGS_FreezeData& data )
SendPointerPacket( GS_RINGTYPE_FREEZE, mode, &data );
mtgsWaitGS();
m_LoadState = false;
}
// Waits for the GS to empty out the entire ring buffer contents.

View File

@ -90,7 +90,7 @@ struct LegacyApi_CommonMethod
// returns the method name as a wxString, converted from UTF8.
wxString GetMethodName( PluginsEnum_t pid ) const
{
return tbl_PluginInfo[pid].GetShortname() + wxString::FromUTF8( MethodName );
return tbl_PluginInfo[pid].GetShortname() + fromUTF8( MethodName );
}
};
@ -107,7 +107,7 @@ struct LegacyApi_ReqMethod
// returns the method name as a wxString, converted from UTF8.
wxString GetMethodName( ) const
{
return wxString::FromUTF8( MethodName );
return fromUTF8( MethodName );
}
};
@ -118,7 +118,7 @@ struct LegacyApi_OptMethod
VoidMethod** Dest; // Target function where the binding is saved.
// returns the method name as a wxString, converted from UTF8.
wxString GetMethodName() const { return wxString::FromUTF8( MethodName ); }
wxString GetMethodName() const { return fromUTF8( MethodName ); }
};

View File

@ -32,10 +32,21 @@ struct PluginInfo
wxString GetShortname() const
{
return wxString::FromUTF8( shortname );
return fromUTF8( shortname );
}
};
#ifdef _MSC_VER
// Disabling C4673: throwing 'Exception::Blah' the following types will not be considered at the catch site
// The warning is bugged, and happens even though we're properly inheriting classes with
// 'virtual' qualifiers. But since the warning is potentially useful elsewhere, I disable
// it only for the scope of these exceptions.
# pragma warning(push)
# pragma warning(disable:4673)
#endif
// --------------------------------------------------------------------------------------
// Plugin-related Exceptions
// --------------------------------------------------------------------------------------
@ -139,9 +150,12 @@ namespace Exception
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
};
#ifdef _MSC_VER
# pragma warning(pop)
#endif
// --------------------------------------------------------------------------------------
// LegacyPluginAPI_Common
// --------------------------------------------------------------------------------------

View File

@ -47,7 +47,7 @@ namespace R5900Exception
void Init( const char*msg )
{
m_message = wxString::FromUTF8( msg );
m_message = fromUTF8( msg );
cpuState = cpuRegs;
}
};

View File

@ -13,57 +13,98 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "App.h"
#include "HostGui.h"
#include "zlib/zlib.h"
static SafeArray<u8> state_buffer;
// Simple lock boolean for the state buffer in use by a thread. This simple solution works because
// we are assured that state save/load actions will only be initiated from the main thread.
static bool state_buffer_lock = false;
// Simple lock boolean for the state buffer being in use by a thread.
static NonblockingMutex state_buffer_lock;
// This boolean is to keep the system from resuming emulation until the current state has completely
// uploaded or downloaded itself. It is only modified from the main thread, and should only be read
// form the main thread.
bool sys_resume_lock = false;
// --------------------------------------------------------------------------------------
// StateThread_Freeze
// --------------------------------------------------------------------------------------
class StateThread_Freeze : public PersistentThread
static FnType_OnThreadComplete* Callback_FreezeFinished = NULL;
enum
{
StateThreadAction_None = 0,
StateThreadAction_Create,
StateThreadAction_Restore,
StateThreadAction_ZipToDisk,
StateThreadAction_UnzipFromDisk,
};
class _BaseStateThread : public PersistentThread
{
typedef PersistentThread _parent;
public:
StateThread_Freeze( const wxString& file )
virtual ~_BaseStateThread() throw()
{
m_name = L"SaveState::Freeze";
AllowFromMainThreadOnly();
if( state_buffer_lock )
throw Exception::RuntimeError( "Cannot save state; a previous save or load action is already in progress." );
Start();
sys_resume_lock = true;
state_buffer_lock.Release(); // just in case;
}
protected:
void OnStart() {}
_BaseStateThread( const char* name, FnType_OnThreadComplete* onFinished )
{
Callback_FreezeFinished = onFinished;
m_name = L"StateThread::" + fromUTF8(name);
}
void OnStart()
{
if( !state_buffer_lock.TryLock() )
throw Exception::CancelEvent( m_name + L"request ignored: state copy buffer is already locked!" );
}
void SendFinishEvent( int type )
{
wxCommandEvent evt( pxEVT_FreezeThreadFinished );
evt.SetClientData( this );
evt.SetInt( type );
wxGetApp().AddPendingEvent( evt );
}
};
// --------------------------------------------------------------------------------------
// StateThread_Freeze
// --------------------------------------------------------------------------------------
class StateThread_Freeze : public _BaseStateThread
{
typedef _BaseStateThread _parent;
public:
StateThread_Freeze( FnType_OnThreadComplete* onFinished ) : _BaseStateThread( "Freeze", onFinished )
{
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.") );
}
protected:
void OnStart()
{
_parent::OnStart();
sys_resume_lock = true;
sCoreThread.Pause();
}
void ExecuteTask()
{
memSavingState( state_buffer ).FreezeAll();
}
void OnThreadCleanup()
{
wxCommandEvent evt( pxEVT_FreezeFinished );
evt.SetClientData( this );
wxGetApp().AddPendingEvent( evt );
SendFinishEvent( StateThreadAction_Create );
_parent::OnThreadCleanup();
}
};
@ -71,37 +112,36 @@ protected:
// --------------------------------------------------------------------------------------
// StateThread_Thaw
// --------------------------------------------------------------------------------------
class StateThread_Thaw : public PersistentThread
class StateThread_Thaw : public _BaseStateThread
{
typedef PersistentThread _parent;
typedef _BaseStateThread _parent;
public:
StateThread_Thaw( const wxString& file )
{
m_name = L"SaveState::Thaw";
AllowFromMainThreadOnly();
if( state_buffer_lock )
throw Exception::RuntimeError( "Cannot sload state; a previous save or load action is already in progress." );
Start();
sys_resume_lock = true;
}
StateThread_Thaw( FnType_OnThreadComplete* onFinished ) : _BaseStateThread( "Thaw", onFinished ) { }
protected:
void OnStart() {}
void OnStart()
{
_parent::OnStart();
if( state_buffer.IsDisposed() )
{
state_buffer_lock.Release();
throw Exception::RuntimeError( "ThawState request made, but no valid state exists!" );
}
sys_resume_lock = true;
sCoreThread.Pause();
}
void ExecuteTask()
{
memSavingState( state_buffer ).FreezeAll();
memLoadingState( state_buffer ).FreezeAll();
}
void OnThreadCleanup()
{
wxCommandEvent evt( pxEVT_FreezeFinished );
evt.SetClientData( this );
wxGetApp().AddPendingEvent( evt );
SendFinishEvent( StateThreadAction_Restore );
_parent::OnThreadCleanup();
}
};
@ -109,57 +149,46 @@ protected:
// --------------------------------------------------------------------------------------
// StateThread_ZipToDisk
// --------------------------------------------------------------------------------------
class StateThread_ZipToDisk : public PersistentThread
class StateThread_ZipToDisk : public _BaseStateThread
{
typedef PersistentThread _parent;
typedef _BaseStateThread _parent;
protected:
gzFile m_gzfp;
const wxString m_filename;
gzFile m_gzfp;
public:
StateThread_ZipToDisk( const wxString& file ) : m_gzfp( NULL )
StateThread_ZipToDisk( FnType_OnThreadComplete* onFinished, const wxString& file ) :
_BaseStateThread( "ZipToDisk", onFinished )
, m_filename( file )
, m_gzfp( NULL )
{
m_name = L"SaveState::ZipToDisk";
AllowFromMainThreadOnly();
if( state_buffer_lock )
throw Exception::RuntimeError( "Cannot save state; a previous save or load action is already in progress." );
m_gzfp = gzopen( file.ToUTF8().data(), "wb" );
if( m_gzfp == NULL )
throw Exception::CreateStream( file, "Cannot create savestate file for writing." );
try{ Start(); }
catch(...)
{
gzclose( m_gzfp ); m_gzfp = NULL;
throw;
}
sys_resume_lock = true;
}
~StateThread_ZipToDisk() throw()
{
sys_resume_lock = false; // just in case;
if( m_gzfp != NULL ) gzclose( m_gzfp );
}
protected:
void OnStart() {}
void OnStart()
{
_parent::OnStart();
m_gzfp = gzopen( toUTF8(m_filename), "wb" );
if( m_gzfp == NULL )
throw Exception::CreateStream( m_filename, "Cannot create savestate file for writing." );
}
void ExecuteTask()
{
Sleep( 2 );
Yield( 2 );
if( gzwrite( (gzFile)m_gzfp, state_buffer.GetPtr(), state_buffer.GetSizeInBytes() ) < state_buffer.GetSizeInBytes() )
throw Exception::BadStream();
}
void OnThreadCleanup()
{
wxCommandEvent evt( pxEVT_FreezeFinished );
evt.SetClientData( this ); // tells message to clean us up.
wxGetApp().AddPendingEvent( evt );
SendFinishEvent( StateThreadAction_ZipToDisk );
_parent::OnThreadCleanup();
}
};
@ -168,43 +197,41 @@ protected:
// --------------------------------------------------------------------------------------
// StateThread_UnzipFromDisk
// --------------------------------------------------------------------------------------
class StateThread_UnzipFromDisk : public PersistentThread
class StateThread_UnzipFromDisk : public _BaseStateThread
{
typedef PersistentThread _parent;
typedef _BaseStateThread _parent;
protected:
gzFile m_gzfp;
const wxString m_filename;
gzFile m_gzfp;
// set true only once the whole file has finished loading. IF the thread is canceled or
// an error occurs, this will remain false.
bool m_finished;
public:
StateThread_UnzipFromDisk( const wxString& file ) : m_gzfp( NULL )
StateThread_UnzipFromDisk( FnType_OnThreadComplete* onFinished, const wxString& file ) :
_BaseStateThread( "UnzipFromDisk", onFinished )
, m_filename( file )
, m_gzfp( NULL )
, m_finished( false )
{
m_name = L"SaveState::UnzipFromDisk";
AllowFromMainThreadOnly();
if( state_buffer_lock )
throw Exception::RuntimeError( "Cannot save state; a previous save or load action is already in progress." );
m_gzfp = gzopen( file.ToUTF8().data(), "wb" );
if( m_gzfp == NULL )
throw Exception::CreateStream( file, "Cannot create savestate file for writing." );
try{ Start(); }
catch(...)
{
gzclose( m_gzfp ); m_gzfp = NULL;
throw;
}
sys_resume_lock = true;
}
~StateThread_UnzipFromDisk() throw()
{
sys_resume_lock = false; // just in case;
if( m_gzfp != NULL ) gzclose( m_gzfp );
}
protected:
void OnStart() {}
void OnStart()
{
_parent::OnStart();
m_gzfp = gzopen( toUTF8(m_filename), "rb" );
if( m_gzfp == NULL )
throw Exception::CreateStream( m_filename, "Cannot open savestate file for reading." );
}
void ExecuteTask()
{
@ -217,70 +244,95 @@ protected:
state_buffer.ExactAlloc( curidx+BlockSize );
gzread( m_gzfp, state_buffer.GetPtr(curidx), BlockSize );
curidx += BlockSize;
TestCancel();
} while( !gzeof(m_gzfp) );
m_finished = true;
}
void OnThreadCleanup()
{
wxCommandEvent evt( pxEVT_ThawFinished );
evt.SetClientData( this ); // tells message to clean us up.
wxGetApp().AddPendingEvent( evt );
SendFinishEvent( StateThreadAction_UnzipFromDisk );
_parent::OnThreadCleanup();
}
};
void Pcsx2App::OnFreezeFinished( wxCommandEvent& evt )
void Pcsx2App::OnFreezeThreadFinished( wxCommandEvent& evt )
{
state_buffer.Dispose();
state_buffer_lock = false;
// clear the OnFreezeFinsihed to NULL now, in case of error.
// (but only actually run it if no errors occur)
FnType_OnThreadComplete* fn_tmp = Callback_FreezeFinished;
Callback_FreezeFinished = NULL;
SysClearExecutionCache();
sCoreThread.Resume();
{
ScopedPtr<PersistentThread> thr( (PersistentThread*)evt.GetClientData() );
if( !pxAssertDev( thr != NULL, "NULL thread handle on freeze finished?" ) ) return;
state_buffer_lock.Release();
sys_resume_lock = false;
thr->RethrowException();
}
delete (PersistentThread*)evt.GetClientData();
if( fn_tmp != NULL ) fn_tmp( evt );
//m_evtsrc_FreezeThreadFinished.Dispatch( evt );
}
void Pcsx2App::OnThawFinished( wxCommandEvent& evt )
void OnFinished_Resume( const wxCommandEvent& evt )
{
PersistentThread* thr = (PersistentThread*)evt.GetClientData();
if( thr == NULL )
if( evt.GetInt() == StateThreadAction_Restore )
{
pxAssert( false );
return;
// Successfully restored state, so remove the copy. Don't remove it sooner
// because the thread may have failed with some exception/error.
state_buffer.Dispose();
SysClearExecutionCache();
}
/*catch( Exception::BadSavedState& ex)
{
// At this point we can return control back to the user, no questions asked.
// StateLoadErrors are only thorwn if the load failed prior to any virtual
// machine memory contents being changed. (usually missing file errors)
Console.Notice( ex.FormatDiagnosticMessage() );
sCoreThread.Resume();
}*/
state_buffer.Dispose();
state_buffer_lock = false;
SysClearExecutionCache();
sCoreThread.Resume();
delete (PersistentThread*)evt.GetClientData();
}
static wxString zip_dest_filename;
void OnFinished_ZipToDisk( const wxCommandEvent& evt )
{
if( !pxAssertDev( evt.GetInt() == StateThreadAction_Create, "Unexpected StateThreadAction value, aborting save." ) ) return;
if( zip_dest_filename.IsEmpty() )
{
Console.Notice( "Cannot save state to disk: empty filename specified." );
return;
}
// Phase 2: Record to disk!!
(new StateThread_ZipToDisk( OnFinished_Resume, zip_dest_filename ))->Start();
}
void OnFinished_Restore( const wxCommandEvent& evt )
{
if( !pxAssertDev( evt.GetInt() == StateThreadAction_UnzipFromDisk, "Unexpected StateThreadAction value, aborting restore." ) ) return;
// Phase 2: Restore over existing VM state!!
(new StateThread_Thaw( OnFinished_Resume ))->Start();
}
// =====================================================================================================
// StateCopy Public Interface
// =====================================================================================================
void StateCopy_SaveToFile( const wxString& file )
{
if( state_buffer_lock ) return;
new StateThread_ZipToDisk( file );
if( state_buffer_lock.IsLocked() ) return;
zip_dest_filename = file;
(new StateThread_Freeze( OnFinished_ZipToDisk ))->Start();
Console.Status( wxsFormat( L"Saving savestate to file: %s", zip_dest_filename.c_str() ) );
}
void StateCopy_LoadFromFile( const wxString& file )
{
if( state_buffer_lock ) return;
sCoreThread.ShortSuspend();
new StateThread_UnzipFromDisk( file );
if( state_buffer_lock.IsLocked() ) return;
sCoreThread.Pause();
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
}
// Saves recovery state info to the given saveslot, or saves the active emulation state
@ -289,8 +341,28 @@ void StateCopy_LoadFromFile( const wxString& file )
// the one in the memory save. :)
void StateCopy_SaveToSlot( uint num )
{
if( state_buffer_lock ) return;
StateCopy_SaveToFile( SaveStateBase::GetFilename( num ) );
zip_dest_filename = SaveStateBase::GetFilename( num );
(new StateThread_Freeze( OnFinished_ZipToDisk ))->Start();
Console.Status( "Saving savestate to slot %d...", num );
Console.Status( wxsFormat(L"\tfilename: %s", zip_dest_filename.c_str()) );
}
void StateCopy_LoadFromSlot( uint slot )
{
if( state_buffer_lock.IsLocked() ) return;
wxString file( SaveStateBase::GetFilename( slot ) );
if( !wxFileExists( file ) )
{
Console.Notice( "Savestate slot %d is empty.", slot );
return;
}
Console.Status( "Loading savestate from slot %d...", slot );
Console.Status( wxsFormat(L"\tfilename: %s", file.c_str()) );
sCoreThread.Pause();
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
}
bool StateCopy_IsValid()
@ -310,46 +382,19 @@ bool StateCopy_HasPartialState()
void StateCopy_FreezeToMem()
{
if( state_buffer_lock ) return;
if( state_buffer_lock.IsLocked() ) return;
(new StateThread_Freeze( OnFinished_Restore ))->Start();
}
void StateCopy_ThawFromMem()
{
if( state_buffer_lock ) return;
if( state_buffer_lock.IsLocked() ) return;
new StateThread_Thaw( OnFinished_Restore );
}
void StateCopy_Clear()
{
if( state_buffer_lock ) return;
if( state_buffer_lock.IsLocked() ) return;
state_buffer.Dispose();
}
// Creates a full recovery of the entire emulation state (CPU and all plugins).
// If a current recovery state is already present, then nothing is done (the
// existing recovery state takes precedence since if it were out-of-date it'd be
// deleted!).
void MakeFull()
{
//if( g_RecoveryState ) return;
//if( !SysHasValidState() ) return;
/*
try
{
g_RecoveryState = new SafeArray<u8>( L"Memory Savestate Recovery" );
memSavingState( *g_RecoveryState ).FreezeAll();
}
catch( Exception::RuntimeError& ex )
{
Msgbox::Alert( wxsFormat( // fixme: needs proper translation
L"PCSX2 encountered an error while trying to backup/suspend the PS2 VirtualMachine state. "
L"You may resume emulation without losing any data, however the machine state will not be "
L"able to recover if you make changes to your PCSX2 configuration.\n\n"
L"Details: %s", ex.FormatDisplayMessage().c_str() )
);
g_RecoveryState = NULL;
}*/
}

View File

@ -136,6 +136,9 @@ static const int MainMemorySizeInBytes =
void SaveStateBase::FreezeMainMemory()
{
if( IsLoading() )
PreLoadPrep();
// First Block - Memory Dumps
// ---------------------------
FreezeMem(PS2MEM_BASE, Ps2MemSize::Base); // 32 MB main memory
@ -149,8 +152,8 @@ void SaveStateBase::FreezeMainMemory()
void SaveStateBase::FreezeRegisters()
{
//if( IsLoading() )
// PreLoadPrep();
if( IsLoading() )
PreLoadPrep();
// Second Block - Various CPU Registers and States
// -----------------------------------------------

View File

@ -202,5 +202,6 @@ extern void StateCopy_ThawFromMem();
extern void StateCopy_SaveToFile( const wxString& file );
extern void StateCopy_LoadFromFile( const wxString& file );
extern void StateCopy_SaveToSlot( uint num );
extern void StateCopy_LoadFromSlot( uint slot );
extern void StateCopy_Clear();

View File

@ -139,7 +139,7 @@ SysCoreAllocations::SysCoreAllocations()
throw Exception::OutOfMemory(
wxsFormat( // Diagnostic (english)
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
L"Error Details: " + wxString::FromUTF8( ex.what() )
L"Error Details: " + fromUTF8( ex.what() )
),
GetMemoryErrorVM() // translated

View File

@ -55,7 +55,6 @@ void SysSuspendableThread::OnStart()
_parent::OnStart();
}
// Pauses the emulation state at the next PS2 vsync, and returns control to the calling
// thread; or does nothing if the core is already suspended. Calling this thread from the
// Core thread will result in deadlock.
@ -66,6 +65,11 @@ void SysSuspendableThread::OnStart()
// is mostly useful for starting certain non-Emu related gui activities (improves gui
// responsiveness).
//
// Exceptions:
// CancelEvent - thrown if the thread is already in a Paused state. Because actions that
// pause emulation typically rely on plugins remaining loaded/active, Suspension must
// cansel itself forcefully or risk crashing whatever other action is in progress.
//
void SysSuspendableThread::Suspend( bool isBlocking )
{
if( IsSelf() || !IsRunning() ) return;
@ -76,11 +80,34 @@ void SysSuspendableThread::Suspend( bool isBlocking )
if( m_ExecMode == ExecMode_Suspended )
return;
if( m_ExecMode == ExecMode_Pausing || m_ExecMode == ExecMode_Paused )
throw Exception::CancelEvent( "Another thread is pausing the VM state." );
if( m_ExecMode == ExecMode_Running )
m_ExecMode = ExecMode_Suspending;
pxAssertDev( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspended..." );
pxAssertDev( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspending..." );
}
m_SuspendEvent.Reset();
m_sem_event.Post();
if( isBlocking ) m_SuspendEvent.WaitGui();
}
void SysSuspendableThread::Pause()
{
if( IsSelf() || !IsRunning() ) return;
{
ScopedLock locker( m_lock_ExecMode );
if( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused) ) return;
if( m_ExecMode == ExecMode_Running )
m_ExecMode = ExecMode_Pausing;
pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
}
m_SuspendEvent.Reset();
m_sem_event.Post();
m_SuspendEvent.WaitGui();
}
@ -111,6 +138,7 @@ void SysSuspendableThread::Resume()
// fall through...
case ExecMode_Suspending:
case ExecMode_Pausing:
// we need to make sure and wait for the emuThread to enter a fully suspended
// state before continuing...
@ -120,8 +148,8 @@ void SysSuspendableThread::Resume()
}
}
pxAssertDev( m_ExecMode == ExecMode_Suspended,
"SysSuspendableThread is not in a suspended/idle state? wtf!" );
pxAssertDev( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused),
"SysSuspendableThread is not in a suspended/paused state? wtf!" );
m_ExecMode = ExecMode_Running;
m_ResumeProtection = true;
@ -148,7 +176,7 @@ void SysSuspendableThread::StateCheck( bool isCancelable )
// Shortcut for the common case, to avoid unnecessary Mutex locks:
if( m_ExecMode == ExecMode_Running )
{
if( isCancelable ) pthread_testcancel();
if( isCancelable ) TestCancel();
return;
}
@ -170,23 +198,41 @@ void SysSuspendableThread::StateCheck( bool isCancelable )
// Yup, need this a second time. Variable state could have changed while we
// were trying to acquire the lock above.
if( isCancelable )
pthread_testcancel();
TestCancel();
break;
// -------------------------------------
case ExecMode_Pausing:
{
OnPauseInThread();
m_ExecMode = ExecMode_Paused;
m_SuspendEvent.Post();
}
// fallthrough...
case ExecMode_Paused:
m_lock_ExecMode.Unlock();
while( m_ExecMode == ExecMode_Paused )
m_ResumeEvent.WaitGui();
OnResumeInThread( false );
break;
// -------------------------------------
case ExecMode_Suspending:
{
OnSuspendInThread();
m_ExecMode = ExecMode_Suspended;
m_SuspendEvent.Post();
}
// fall through...
// fallthrough...
case ExecMode_Suspended:
m_lock_ExecMode.Unlock();
while( m_ExecMode == ExecMode_Suspended )
m_ResumeEvent.WaitGui();
OnResumeInThread();
OnResumeInThread( true );
break;
jNO_DEFAULT;
@ -218,16 +264,6 @@ void SysCoreThread::Start()
_parent::Start();
}
// Suspends the system without closing plugins or updating GUI status.
// Should be used for savestates or other actions which happen very quickly.
void SysCoreThread::ShortSuspend()
{
m_shortSuspend = true;
Suspend();
m_shortSuspend = false;
}
// Resumes the core execution state, or does nothing is the core is already running. If
// settings were changed, resets will be performed as needed and emulation state resumed from
// memory savestates.
@ -348,11 +384,6 @@ void SysCoreThread::CpuExecute()
PCSX2_MEM_PROTECT_END();
}
static void _cet_callback_cleanup( void* handle )
{
((SysCoreThread*)handle)->OnThreadCleanup();
}
void SysCoreThread::ExecuteTask()
{
tls_coreThread = this;
@ -369,9 +400,10 @@ void SysCoreThread::OnSuspendInThread()
m_plugins.Close();
}
void SysCoreThread::OnResumeInThread()
void SysCoreThread::OnResumeInThread( bool isSuspended )
{
m_plugins.Open();
if( isSuspended )
m_plugins.Open();
}

View File

@ -41,7 +41,9 @@ protected:
ExecMode_NoThreadYet,
ExecMode_Running,
ExecMode_Suspending,
ExecMode_Suspended
ExecMode_Suspended,
ExecMode_Pausing,
ExecMode_Paused,
};
volatile ExecutionMode m_ExecMode;
@ -59,6 +61,7 @@ public:
virtual void Suspend( bool isBlocking = true );
virtual void Resume();
virtual void Pause();
virtual void StateCheck( bool isCancelable = true );
virtual void OnThreadCleanup();
@ -78,11 +81,21 @@ protected:
// thread, requesting this thread suspend itself temporarily). After this is called,
// the thread enters a waiting state on the m_ResumeEvent semaphore.
virtual void OnSuspendInThread()=0;
// Extending classes should implement this, but should not call it. The parent class
// handles invocation by the following guidelines: Called *in thread* from StateCheck()
// prior to pausing the thread (ie, when Pause() has been called on a separate thread,
// requesting this thread pause itself temporarily). After this is called, the thread
// enters a waiting state on the m_ResumeEvent semaphore.
virtual void OnPauseInThread()=0;
// Extending classes should implement this, but should not call it. The parent class
// handles invocation by the following guidelines: Called from StateCheck() after the
// thread has been suspended and then subsequently resumed.
virtual void OnResumeInThread()=0;
// Parameter:
// isSuspended - set to TRUE if the thread is returning from a suspended state, or
// FALSE if it's returning from a paused state.
virtual void OnResumeInThread( bool isSuspended )=0;
};
// --------------------------------------------------------------------------------------
@ -107,7 +120,6 @@ public:
virtual void ApplySettings( const Pcsx2Config& src );
virtual void OnThreadCleanup();
virtual void ShortSuspend();
virtual void OnResumeReady();
protected:
@ -116,6 +128,7 @@ protected:
virtual void Start();
virtual void OnSuspendInThread();
virtual void OnResumeInThread();
virtual void OnPauseInThread() {}
virtual void OnResumeInThread( bool IsSuspended );
virtual void ExecuteTask();
};

View File

@ -27,12 +27,6 @@
VUmicroCpu CpuVU0; // contains a working copy of the VU0 cpu functions/API
VUmicroCpu CpuVU1; // contains a working copy of the VU1 cpu functions/API
static void DummyExecuteVU1Block(void)
{
VU0.VI[ REG_VPU_STAT ].UL &= ~0x100;
VU1.vifRegs->stat.VEW = 0; // also reset the bit (grandia 3 works)
}
void vuMicroCpuReset()
{
CpuVU0 = CHECK_VU0REC ? recVU0 : intVU0;

View File

@ -21,6 +21,8 @@
#include <wx/docview.h>
#include <wx/apptrait.h>
#include "Utilities/Listeners.h"
class IniInterface;
class MainEmuFrame;
class GSFrame;
@ -35,6 +37,9 @@ class AppCoreThread;
#include "System.h"
#include "System/SysThreads.h"
typedef void FnType_OnThreadComplete(const wxCommandEvent& evt);
#define AllowFromMainThreadOnly() \
pxAssertMsg( wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only." )
@ -42,10 +47,10 @@ BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE( pxEVT_SemaphorePing, -1 )
DECLARE_EVENT_TYPE( pxEVT_OpenModalDialog, -1 )
DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 )
DECLARE_EVENT_TYPE( pxEVT_SysExecute, -1 )
DECLARE_EVENT_TYPE( pxEVT_LoadPluginsComplete, -1 )
DECLARE_EVENT_TYPE( pxEVT_AppCoreThread_Terminated, -1 )
DECLARE_EVENT_TYPE( pxEVT_FreezeFinished, -1 )
DECLARE_EVENT_TYPE( pxEVT_ThawFinished, -1 )
DECLARE_EVENT_TYPE( pxEVT_AppCoreThreadFinished, -1 )
DECLARE_EVENT_TYPE( pxEVT_FreezeThreadFinished, -1 )
END_DECLARE_EVENT_TYPES()
// This is used when the GS plugin is handling its own window. Messages from the PAD
@ -335,8 +340,6 @@ public:
Pcsx2App();
virtual ~Pcsx2App();
void ReloadPlugins();
void PostPadKey( wxKeyEvent& evt );
void PostMenuAction( MenuIdentifiers menu_id ) const;
int ThreadedModalDialog( DialogIdentifiers dialogId );
@ -392,6 +395,18 @@ public:
void DisableDiskLogging() const;
void OnProgramLogClosed();
// ----------------------------------------------------------------------------
// Event Sources!
// ----------------------------------------------------------------------------
protected:
CmdEvt_Source m_evtsrc_CorePluginStatus;
CmdEvt_Source m_evtsrc_CoreThreadStatus;
public:
CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; }
CmdEvt_Source& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; }
protected:
void InitDefaultGlobalAccelerators();
void BuildCommandHash();
@ -402,18 +417,18 @@ protected:
void HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent& event) const;
void OnSysExecute( wxCommandEvent& evt );
void OnReloadPlugins( wxCommandEvent& evt );
void OnLoadPluginsComplete( wxCommandEvent& evt );
void OnSemaphorePing( wxCommandEvent& evt );
void OnOpenModalDialog( wxCommandEvent& evt );
void OnCoreThreadTerminated( wxCommandEvent& evt );
void OnFreezeFinished( wxCommandEvent& evt );
void OnThawFinished( wxCommandEvent& evt );
void OnFreezeThreadFinished( wxCommandEvent& evt );
void OnMessageBox( pxMessageBoxEvent& evt );
void OnEmuKeyDown( wxKeyEvent& evt );
// ----------------------------------------------------------------------------
// Override wx default exception handling behavior
// ----------------------------------------------------------------------------
@ -496,7 +511,7 @@ DECLARE_APP(Pcsx2App)
extern bool sys_resume_lock;
extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest );
extern void LoadPluginsPassive();
extern void LoadPluginsPassive( FnType_OnThreadComplete* onComplete );
extern void LoadPluginsImmediate();
extern void UnloadPlugins();

View File

@ -72,7 +72,7 @@ void AppCoreThread::OnResumeReady()
// the new (lack of) thread status, so this posts a message to the App to do so.
void AppCoreThread::OnThreadCleanup()
{
wxCommandEvent evt( pxEVT_AppCoreThread_Terminated );
wxCommandEvent evt( pxEVT_AppCoreThreadFinished );
wxGetApp().AddPendingEvent( evt );
_parent::OnThreadCleanup();
}

View File

@ -220,12 +220,12 @@ bool Pcsx2App::OnInit()
Connect( pxEVT_SemaphorePing, wxCommandEventHandler( Pcsx2App::OnSemaphorePing ) );
Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
Connect( pxEVT_ReloadPlugins, wxCommandEventHandler( Pcsx2App::OnReloadPlugins ) );
Connect( pxEVT_SysExecute, wxCommandEventHandler( Pcsx2App::OnSysExecute ) );
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
Connect( pxEVT_FreezeFinished, wxCommandEventHandler( Pcsx2App::OnCoreThreadTerminated ) );
Connect( pxEVT_FreezeFinished, wxCommandEventHandler( Pcsx2App::OnFreezeFinished ) );
Connect( pxEVT_ThawFinished, wxCommandEventHandler( Pcsx2App::OnThawFinished ) );
Connect( pxEVT_AppCoreThreadFinished, wxCommandEventHandler( Pcsx2App::OnCoreThreadTerminated ) );
Connect( pxEVT_FreezeThreadFinished, wxCommandEventHandler( Pcsx2App::OnFreezeThreadFinished ) );
Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
@ -310,7 +310,7 @@ bool Pcsx2App::OnInit()
return false;
}
LoadPluginsPassive();
LoadPluginsPassive( NULL );
}
// ----------------------------------------------------------------------------
catch( Exception::StartupAborted& ex )

View File

@ -30,10 +30,10 @@ IMPLEMENT_APP(Pcsx2App)
DEFINE_EVENT_TYPE( pxEVT_SemaphorePing );
DEFINE_EVENT_TYPE( pxEVT_OpenModalDialog );
DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
DEFINE_EVENT_TYPE( pxEVT_SysExecute );
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
DEFINE_EVENT_TYPE( pxEVT_AppCoreThread_Terminated );
DEFINE_EVENT_TYPE( pxEVT_FreezeFinished );
DEFINE_EVENT_TYPE( pxEVT_ThawFinished );
DEFINE_EVENT_TYPE( pxEVT_AppCoreThreadFinished );
DEFINE_EVENT_TYPE( pxEVT_FreezeThreadFinished );
bool UseAdminMode = false;
wxDirName SettingsFolder;
@ -211,6 +211,18 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
(handler->*func)(event);
}
// ----------------------------------------------------------------------------
catch( Exception::CancelEvent& ex )
{
Console.Notice( ex.FormatDiagnosticMessage() );
}
// ----------------------------------------------------------------------------
catch( Exception::BadSavedState& ex)
{
// Saved state load failed.
Console.Notice( ex.FormatDiagnosticMessage() );
sCoreThread.Resume();
}
// ----------------------------------------------------------------------------
catch( Exception::PluginError& ex )
{
Console.Error( ex.FormatDiagnosticMessage() );
@ -376,32 +388,53 @@ void Pcsx2App::OnMainFrameClosed()
m_MainFrame = NULL;
}
// --------------------------------------------------------------------------------------
// Sys/Core API and Shortcuts (for wxGetApp())
// --------------------------------------------------------------------------------------
static int _sysexec_cdvdsrc_type = -1;
static void OnSysExecuteAfterPlugins( const wxCommandEvent& loadevt )
{
if( !wxGetApp().m_CorePlugins ) return;
wxCommandEvent execevt( pxEVT_SysExecute );
execevt.SetInt( _sysexec_cdvdsrc_type );
wxGetApp().AddPendingEvent( execevt );
}
// Executes the emulator using a saved/existing virtual machine state and currently
// configured CDVD source device.
void Pcsx2App::SysExecute()
{
if( sys_resume_lock )
if( !m_CorePlugins )
{
Console.WriteLn( "SysExecute: State is locked, ignoring Execute request!" );
LoadPluginsPassive( OnSysExecuteAfterPlugins );
return;
}
SysReset();
LoadPluginsImmediate();
m_CoreThread = new AppCoreThread( *m_CorePlugins );
m_CoreThread->Resume();
wxCommandEvent evt( pxEVT_SysExecute );
evt.SetInt( -1 );
AddPendingEvent( evt );
}
// Executes the specified cdvd source and optional elf file. This command performs a
// full closure of any existing VM state and starts a fresh VM with the requested
// sources.
void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc )
{
if( !m_CorePlugins )
{
LoadPluginsPassive( OnSysExecuteAfterPlugins );
return;
}
wxCommandEvent evt( pxEVT_SysExecute );
evt.SetInt( (int)cdvdsrc );
AddPendingEvent( evt );
}
void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
{
if( sys_resume_lock )
{
@ -409,10 +442,13 @@ void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc )
return;
}
SysReset();
LoadPluginsImmediate();
// if something unloaded plugins since this messages was queued then it's best to ignore
// it, because apparently too much stuff is going on and the emulation states are wonky.
if( !m_CorePlugins ) return;
if( evt.GetInt() != -1 ) SysReset();
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
CDVDsys_ChangeSource( cdvdsrc );
if( evt.GetInt() != -1 ) CDVDsys_ChangeSource( (CDVD_SourceType)evt.GetInt() );
m_CoreThread = new AppCoreThread( *m_CorePlugins );
m_CoreThread->Resume();

View File

@ -109,7 +109,7 @@ void ConsoleTestThread::ExecuteTask()
// worst case scenario (without being entirely unrealistic).
Console.WriteLn( wxsFormat( L"This is a threaded logging test. Something bad could happen... %d", ++numtrack ) );
Console.Status( wxsFormat( L"Testing high stress loads %s", L"(multi-color)" ) );
Sleep( 0 );
Yield( 0 );
}
}

View File

@ -51,7 +51,7 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
m_bitmap_dualshock( this, wxID_ANY, wxBitmap( EmbeddedImage<res_Dualshock>().Get() ),
wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN )
{
static const wxString LabelAuthors = wxString::FromUTF8(
static const wxString LabelAuthors = fromUTF8(
"Developers"
"\n\n"
"v0.9.6+: Arcum42, Refraction,"
@ -69,7 +69,7 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
"Webmasters: CKemu, Falcon4ever"
);
static const wxString LabelGreets = wxString::FromUTF8(
static const wxString LabelGreets = fromUTF8(
"Contributors"
"\n\n"
"Hiryu and Sjeep (libcdvd / iso filesystem), nneeve (fpu and vu)"

View File

@ -44,7 +44,7 @@ static const int IdealWidth = 500;
template< typename T >
void Dialogs::ConfigurationDialog::AddPage( const char* label, int iconid )
{
const wxString labelstr( wxString::FromUTF8( label ) );
const wxString labelstr( fromUTF8( label ) );
const int curidx = m_labels.Add( labelstr );
g_ApplyState.SetCurrentPage( curidx );
m_listbook.AddPage( new T( m_listbook, IdealWidth ), wxGetTranslation( labelstr ),

View File

@ -263,7 +263,7 @@ void AcceleratorDictionary::Map( const KeyAcceleratorCode& acode, const char *se
Console.Notice( wxsFormat(
L"Kbd Accelerator '%s' is mapped multiple times.\n"
L"\t'Command %s' is being replaced by '%s'",
acode.ToString().c_str(), wxString::FromUTF8( result->Id ).c_str(), searchfor )
acode.ToString().c_str(), fromUTF8( result->Id ).c_str(), searchfor )
);
}
@ -272,7 +272,7 @@ void AcceleratorDictionary::Map( const KeyAcceleratorCode& acode, const char *se
if( result == NULL )
{
Console.Notice( wxsFormat( L"Kbd Accelerator '%s' is mapped to unknown command '%s'",
acode.ToString().c_str(), wxString::FromUTF8( searchfor ).c_str() )
acode.ToString().c_str(), fromUTF8( searchfor ).c_str() )
);
}
else

View File

@ -310,7 +310,7 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
{
// Odd versions: beta / development editions, which feature revision number and compile date.
wintitle.Printf( _("PCSX2 %d.%d.%d.%d%s (svn) %s"), PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo,
SVN_REV, SVN_MODS ? L"m" : wxEmptyString, wxString::FromUTF8(__DATE__).c_str() );
SVN_REV, SVN_MODS ? L"m" : wxEmptyString, fromUTF8(__DATE__).c_str() );
}
else
{

View File

@ -559,13 +559,13 @@ void Panels::PluginSelectorPanel::EnumThread::ExecuteTask()
DevCon.Status( "Plugin Enumeration Thread started..." );
wxGetApp().Ping(); // gives the gui thread some time to refresh
Sleep( 3 );
Yield( 3 );
for( int curidx=0; curidx < m_master.FileCount(); ++curidx )
{
DoNextPlugin( curidx );
if( (curidx & 3) == 3 ) wxGetApp().Ping(); // gives the gui thread some time to refresh
pthread_testcancel();
TestCancel();
//Sleep(150); // uncomment this to slow down the selector, for debugging threading.
}

View File

@ -27,6 +27,8 @@
using namespace Threading;
static FnType_OnThreadComplete* Callback_PluginsLoadComplete = NULL;
// --------------------------------------------------------------------------------------
// LoadPluginsTask
// --------------------------------------------------------------------------------------
@ -37,76 +39,52 @@ using namespace Threading;
//
class LoadPluginsTask : public PersistentThread
{
typedef PersistentThread _parent;
public:
Exception::PluginError* Ex_PluginError;
Exception::RuntimeError* Ex_RuntimeError;
PluginManager* Result;
protected:
wxString m_folders[PluginId_Count];
public:
LoadPluginsTask( const wxString (&folders)[PluginId_Count] ) :
Ex_PluginError( NULL )
, Ex_RuntimeError( NULL )
, Result( NULL )
LoadPluginsTask( const wxString (&folders)[PluginId_Count] ) : Result( NULL )
{
for(int i=0; i<PluginId_Count; ++i )
m_folders[i] = folders[i];
Start();
}
virtual ~LoadPluginsTask() throw();
protected:
void OnStart() {}
void OnThreadCleanup() {}
void OnThreadCleanup();
void ExecuteTask();
};
static ScopedPtr<LoadPluginsTask> _loadTask;
LoadPluginsTask::~LoadPluginsTask() throw()
{
if( _loadTask )
_loadTask.DetachPtr(); // avoids recursive deletion
PersistentThread::Cancel();
_loadTask = NULL;
}
void LoadPluginsTask::ExecuteTask()
{
wxGetApp().Ping();
Sleep(3);
Yield(3);
// This is for testing of the error handler... uncomment for fun?
//throw Exception::PluginError( PluginId_PAD, "This one is for testing the error handler!" );
Result = PluginManager_Create( m_folders );
}
void LoadPluginsTask::OnThreadCleanup()
{
wxCommandEvent evt( pxEVT_LoadPluginsComplete );
evt.SetClientData( this );
try
{
// This is for testing of the error handler... uncomment for fun?
//throw Exception::PluginError( PluginId_PAD, "This one is for testing the error handler!" );
Result = PluginManager_Create( m_folders );
}
catch( Exception::PluginError& ex )
{
Ex_PluginError = new Exception::PluginError( ex );
}
catch( Exception::RuntimeError& innerEx )
{
// Runtime errors are typically recoverable, so handle them here
// and prep them for re-throw on the main thread.
Ex_RuntimeError = new Exception::RuntimeError(
L"A runtime error occurred on the LoadPlugins thread.\n" + innerEx.FormatDiagnosticMessage(),
innerEx.FormatDisplayMessage()
);
}
// anything else leave unhandled so that the debugger catches it!
wxGetApp().AddPendingEvent( evt );
_parent::OnThreadCleanup();
}
/////////////////////////////////////////////////////////////////////////////////////////
@ -132,30 +110,23 @@ int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
wxDir::GetAllFiles( searchpath.ToString(), realdest, wxsFormat( pattern, wxDynamicLibrary::GetDllExt()), wxDIR_FILES ) : 0;
}
void ConvertPluginFilenames( wxString (&passins)[PluginId_Count] )
{
const PluginInfo* pi = tbl_PluginInfo; do
{
passins[pi->id] = OverrideOptions.Filenames[pi->id].GetFullPath();
if( passins[pi->id].IsEmpty() || !wxFileExists( passins[pi->id] ) )
passins[pi->id] = g_Conf->FullpathTo( pi->id );
} while( ++pi, pi->shortname != NULL );
}
// boolean lock modified from the main thread only...
static bool plugin_load_lock = false;
void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt )
{
ReloadPlugins();
}
void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt )
{
// scoped ptr ensures the thread object is cleaned up even on exception:
ScopedPtr<LoadPluginsTask> killTask( (LoadPluginsTask*)evt.GetClientData() );
m_CorePlugins = killTask->Result;
if( !m_CorePlugins )
{
if( killTask->Ex_PluginError != NULL )
throw *killTask->Ex_PluginError;
if( killTask->Ex_RuntimeError != NULL )
throw *killTask->Ex_RuntimeError; // Re-Throws generic threaded errors
}
}
void Pcsx2App::ReloadPlugins()
{
if( _loadTask ) return;
if( plugin_load_lock ) return;
m_CoreThread = NULL;
m_CorePlugins = NULL;
@ -169,42 +140,79 @@ void Pcsx2App::ReloadPlugins()
passins[pi->id] = g_Conf->FullpathTo( pi->id );
} while( ++pi, pi->shortname != NULL );
_loadTask.Delete() = new LoadPluginsTask( passins );
(new LoadPluginsTask( passins ))->Start();
// ... and when it finishes it posts up a OnLoadPluginsComplete(). Bye. :)
plugin_load_lock = true;
}
// Note: If the ClientData paremeter of wxCommandEvt is NULL, this message simply dispatches
// the plugged in listeners.
void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt )
{
plugin_load_lock = false;
FnType_OnThreadComplete* fn_tmp = Callback_PluginsLoadComplete;
if( evt.GetClientData() != NULL )
{
if( !pxAssertDev( !m_CorePlugins, "LoadPlugins thread just finished, but CorePlugins state != NULL (odd!)." ) )
m_CorePlugins = NULL;
// scoped ptr ensures the thread object is cleaned up even on exception:
ScopedPtr<LoadPluginsTask> killTask( (LoadPluginsTask*)evt.GetClientData() );
killTask->RethrowException();
m_CorePlugins = killTask->Result;
}
if( fn_tmp != NULL ) fn_tmp( evt );
//m_evtsrc_PluginLoadFinished.Dispatch( evt );
}
// Posts a message to the App to reload plugins. Plugins are loaded via a background thread
// which is started on a pending event, so don't expect them to be ready "right now."
// If plugins are already loaded then no action is performed.
void LoadPluginsPassive()
// If plugins are already loaded, onComplete is invoked, and the function returns with no
// other actions performed.
void LoadPluginsPassive( FnType_OnThreadComplete* onComplete )
{
if( g_plugins ) return;
// Plugins already loaded?
if( wxGetApp().m_CorePlugins )
{
if( onComplete ) onComplete( wxCommandEvent( pxEVT_LoadPluginsComplete ) );
return;
}
if( onComplete )
Callback_PluginsLoadComplete = onComplete;
wxCommandEvent evt( pxEVT_ReloadPlugins );
wxGetApp().AddPendingEvent( evt );
}
// Blocks until plugins have been successfully loaded, or throws an exception if
// the user cancels the loading procedure after error. If plugins are already loaded
// then no action is performed.
// Performs a blocking load of plugins. If the emulation thread is active, it is shut down
// automatically to prevent race conditions (it depends on plugins).
//
// Exceptions regarding plugin failures will propagate out of this function, so be prepared
// to handle them.
//
// Note that this is not recommended for most situations, but coding improper passive loads
// is probably worse, so if in doubt use this and air will fix it up for you later. :)
//
void LoadPluginsImmediate()
{
AllowFromMainThreadOnly();
if( g_plugins ) return;
if( g_plugins != NULL ) return;
static int _reentrant = 0;
RecursionGuard guard( _reentrant );
wxGetApp().m_CoreThread = NULL;
wxString passins[PluginId_Count];
ConvertPluginFilenames( passins );
wxGetApp().m_CorePlugins = PluginManager_Create( passins );
pxAssertMsg( !guard.IsReentrant(), "Recrsive calls to this function are prohibited." );
wxGetApp().ReloadPlugins();
while( _loadTask )
{
Sleep( 10 );
wxGetApp().ProcessPendingEvents();
}
}
void UnloadPlugins()
{
wxGetApp().m_CoreThread = NULL;
wxGetApp().m_CorePlugins = NULL;
}

View File

@ -23,59 +23,10 @@
StartupParams g_Startup;
// returns true if the new state was loaded, or false if nothing happened.
void States_Load( const wxString& file )
{
sCoreThread.ShortSuspend();
try
{
StateCopy_LoadFromFile( file );
//SysLoadState( file );
//SysStatus( wxsFormat( _("Loaded State %s"), wxFileName( file ).GetFullName().c_str() ) );
}
catch( Exception::BaseException& )
{
// VM state is probably ruined. We'll need to recover from the in-memory backup.
//StateRecovery::Recover();
}
sApp.SysExecute();
}
// Save state save-to-file (or slot) helpers.
void States_Save( const wxString& file )
{
if( !SysHasValidState() )
{
Msgbox::Alert( _("You need to start emulation first before you can save it's state.") );
return;
}
try
{
Console.Status( wxsFormat( L"Saving savestate to file: %s", file.c_str() ) );
StateCopy_SaveToFile( file );
SysStatus( wxsFormat( _("State saved to file: %s"), wxFileName( file ).GetFullName().c_str() ) );
}
catch( Exception::BaseException& ex )
{
// TODO: Implement a "pause the action and issue a popup" thing here.
// *OR* some kind of GS overlay... [for now we use the console]
// Translation Tip: "Your emulation state has not been saved!"
/*Msgbox::Alert(
wxsFormat( _("Error saving state to file: %s"), file.c_str() ) +
L"\n\n" + _("Error details:") + ex.DisplayMessage()
);*/
Console.Error( wxsFormat(
L"An error occurred while trying to save to file %s\n", file.c_str() ) +
L"Your emulation state has not been saved!\n"
L"\nError: " + ex.FormatDiagnosticMessage()
);
}
StateCopy_SaveToFile( file );
}
// --------------------------------------------------------------------------------------
@ -95,22 +46,12 @@ bool States_isSlotUsed(int num)
void States_FreezeCurrentSlot()
{
Console.Status( "Saving savestate to slot %d...", StatesC );
States_Save( SaveStateBase::GetFilename( StatesC ) );
StateCopy_SaveToSlot( StatesC );
}
void States_DefrostCurrentSlot()
{
wxString file( SaveStateBase::GetFilename( StatesC ) );
if( !wxFileExists( file ) )
{
Console.Notice( "Savestate slot %d is empty.", StatesC );
return;
}
Console.Status( "Loading savestate from slot %d...", StatesC );
States_Load( file );
StateCopy_LoadFromSlot( StatesC );
//SysStatus( wxsFormat( _("Loaded State (slot %d)"), StatesC ) );
}

View File

@ -1804,6 +1804,10 @@
RelativePath="..\..\gui\IniInterface.cpp"
>
</File>
<File
RelativePath="..\..\..\common\include\Utilities\Listeners.h"
>
</File>
<File
RelativePath="..\..\gui\MainFrame.cpp"
>

View File

@ -142,6 +142,9 @@ static __forceinline bool ReadPipe(HANDLE h_Pipe, ConsoleColors color )
return true;
}
// --------------------------------------------------------------------------------------
// WinPipeThread
// --------------------------------------------------------------------------------------
class WinPipeThread : public PersistentThread
{
typedef PersistentThread _parent;
@ -173,8 +176,7 @@ protected:
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
while( true )
{
Sleep( 100 );
pthread_testcancel();
Yield( 100 );
ReadPipe( m_outpipe, m_color );
}
}
@ -189,6 +191,9 @@ protected:
void OnThreadCleanup() { }
};
// --------------------------------------------------------------------------------------
// WinPipeRedirection
// --------------------------------------------------------------------------------------
class WinPipeRedirection : public PipeRedirectionBase
{
DeclareNoncopyableObject( WinPipeRedirection );
@ -221,7 +226,8 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream ) :
DWORD stdhandle = ( stdstream == stderr ) ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE;
CreatePipe( m_pipe, m_file );
SetStdHandle( stdhandle, m_file );
if( 0 == SetStdHandle( stdhandle, m_file ) )
throw Exception::Win32Error( "SetStdHandle failed." );
// In some cases GetStdHandle can fail, even when the one we just assigned above is valid.
HANDLE newhandle = GetStdHandle(stdhandle);
@ -231,11 +237,11 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream ) :
if( newhandle == NULL )
throw Exception::RuntimeError( "GetStdHandle returned NULL." ); // not a Win32error (no error code)
m_crtFile = _open_osfhandle( (intptr_t)newhandle, _O_TEXT );
m_crtFile = _open_osfhandle( (intptr_t)newhandle, _O_TEXT );
if( m_crtFile == -1 )
throw Exception::RuntimeError( "_open_osfhandle returned -1." );
m_fp = _fdopen( m_crtFile, "w" );
m_fp = _fdopen( m_crtFile, "w" );
if( m_fp == NULL )
throw Exception::RuntimeError( "_fdopen returned NULL." );
@ -269,10 +275,22 @@ void WinPipeRedirection::Cleanup() throw()
{
fclose( m_fp );
m_fp = NULL;
m_crtFile = -1; // crtFile is closed implicitly when closing m_fp
m_file = INVALID_HANDLE_VALUE; // m_file is closed implicitly when closing crtFile
}
if( m_crtFile != -1 )
{
_close( m_crtFile );
m_crtFile = -1; // m_file is closed implicitly when closing crtFile
}
// crtFile is closed implicitly when closing m_fp
// m_file is closed implicitly when closing crtFile
if( m_file != INVALID_HANDLE_VALUE )
{
CloseHandle( m_pipe );
m_file = INVALID_HANDLE_VALUE;
}
if( m_pipe != INVALID_HANDLE_VALUE )
{

View File

@ -30,7 +30,6 @@ int mVUdebugNow = 0;
#ifdef DEBUG_COMPARE
#include <windows.h>
static int runAmount = 0;
void VUtestPause() {
@ -70,8 +69,9 @@ void VUtestPause() {
SysPrintf("VU Mem CRC = 0x%08x\n", j);
SysPrintf("EndPC = 0x%04x\n", VU1.VI[REG_TPC].UL);
// ... wtf?? --air
for (int i = 0; i < 10000000; i++) {
Sleep(1000);
Threading::Sleep(1000);
}
}
#else
@ -84,9 +84,6 @@ extern u32 vudump;
#ifdef DEBUG_COMPARE2
#ifndef DEBUG_COMPARE
#include <windows.h>
#endif
__aligned16 u8 backVUregs[sizeof(VURegs)];
__aligned16 u8 cmpVUregs [sizeof(VURegs)];

View File

@ -238,20 +238,6 @@ static __forceinline s32 __fastcall GetNextDataBuffered( V_Core& thiscore, uint
g_counter_cache_misses++;
}
s16* sbuffer = cacheLine.Sampledata;
//if( vc.LoopFlags & XAFLAG_LOOP )
// vc.Prev1 = vc.Prev2 = 0;
// saturated decoder
//XA_decode_block( sbuffer, memptr, vc.Prev1, vc.Prev2 );
// [Air]: Testing use of a new unsaturated decoder. (benchmark needed)
// Chances are the saturation isn't needed, but for a very few exception games.
// This is definitely faster than the above version, but is it by enough to
// merit possible lower compatibility? Especially now that games that make
// heavy use of the SPU2 via music or sfx will mostly use the cache anyway.
XA_decode_block_unsaturated( vc.SBuffer, memptr, vc.Prev1, vc.Prev2 );
}

View File

@ -63,8 +63,6 @@ StereoOut32 V_Core::ReadInput_HiFi()
AdmaInProgress = 0;
if(InputDataLeft >= 0x200)
{
u8 k = (InputDataLeft >= InputDataProgress);
#ifdef PCM24_S1_INTERLEAVE
AutoDMAReadBuffer(1);
#else

View File

@ -837,7 +837,7 @@ static void __fastcall RegWrite_Core( u16 value )
{
bool irqe = thiscore.IRQEnable;
int bit0 = thiscore.AttrBit0;
int bit4 = thiscore.AttrBit4;
//int bit4 = thiscore.AttrBit4;
if( ((value>>15)&1) && (!thiscore.CoreEnabled) && (thiscore.InitDelay==0) ) // on init/reset
{