mirror of
https://github.com/libretro/pcsx2.git
synced 2024-12-21 09:18:18 +00:00
Minor fixes for interlocking against the threaded plugin loader (running a game too quickly could cause crashes)
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1843 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
e5da378d9a
commit
2b3d596d86
@ -36,6 +36,7 @@ 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_LoadPluginsComplete, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -365,6 +366,7 @@ protected:
|
||||
void HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent& event) const;
|
||||
|
||||
void OnReloadPlugins( wxCommandEvent& evt );
|
||||
void OnLoadPluginsComplete( wxCommandEvent& evt );
|
||||
void OnSemaphorePing( wxCommandEvent& evt );
|
||||
void OnOpenModalDialog( wxCommandEvent& evt );
|
||||
void OnMessageBox( pxMessageBoxEvent& evt );
|
||||
|
@ -27,13 +27,14 @@
|
||||
|
||||
#include <wx/cmdline.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/evtloop.h>
|
||||
#include <wx/intl.h>
|
||||
|
||||
IMPLEMENT_APP(Pcsx2App)
|
||||
|
||||
DEFINE_EVENT_TYPE( pxEVT_SemaphorePing );
|
||||
DEFINE_EVENT_TYPE( pxEVT_OpenModalDialog );
|
||||
DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
|
||||
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
|
||||
|
||||
bool UseAdminMode = false;
|
||||
wxDirName SettingsFolder;
|
||||
@ -427,6 +428,7 @@ bool Pcsx2App::OnInit()
|
||||
Connect( pxEVT_SemaphorePing, wxCommandEventHandler( Pcsx2App::OnSemaphorePing ) );
|
||||
Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
||||
Connect( pxEVT_ReloadPlugins, wxCommandEventHandler( Pcsx2App::OnReloadPlugins ) );
|
||||
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
|
||||
|
||||
Connect( pxID_Window_GS, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
|
||||
|
||||
@ -630,12 +632,13 @@ void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt )
|
||||
Msgbox::OnEvent( evt );
|
||||
}
|
||||
|
||||
#include <wx/intl.h>
|
||||
|
||||
void Pcsx2App::CleanupMess()
|
||||
{
|
||||
m_CorePlugins->Close();
|
||||
m_CorePlugins->Shutdown();
|
||||
if( m_CorePlugins )
|
||||
{
|
||||
m_CorePlugins->Close();
|
||||
m_CorePlugins->Shutdown();
|
||||
}
|
||||
|
||||
// Notice: deleting the plugin manager (unloading plugins) here causes Lilypad to crash,
|
||||
// likely due to some pending message in the queue that references lilypad procs.
|
||||
@ -768,7 +771,7 @@ void Pcsx2App::LoadSettings()
|
||||
IniLoader loader( *conf );
|
||||
g_Conf->LoadSave( loader );
|
||||
|
||||
if( m_MainFrame != NULL )
|
||||
if( m_MainFrame != NULL && m_MainFrame->m_RecentIsoList )
|
||||
m_MainFrame->m_RecentIsoList->Load( *conf );
|
||||
}
|
||||
|
||||
@ -780,6 +783,6 @@ void Pcsx2App::SaveSettings()
|
||||
IniSaver saver( *conf );
|
||||
g_Conf->LoadSave( saver );
|
||||
|
||||
if( m_MainFrame != NULL )
|
||||
if( m_MainFrame != NULL && m_MainFrame->m_RecentIsoList )
|
||||
m_MainFrame->m_RecentIsoList->Save( *conf );
|
||||
}
|
||||
|
@ -432,11 +432,8 @@ MainEmuFrame::~MainEmuFrame() throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
if( m_RecentIsoList != NULL )
|
||||
{
|
||||
if( m_RecentIsoList )
|
||||
m_RecentIsoList->Save( *wxConfigBase::Get( false ) );
|
||||
safe_delete( m_RecentIsoList );
|
||||
}
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
@ -450,10 +447,10 @@ void MainEmuFrame::ApplySettings()
|
||||
wxConfigBase* cfg = wxConfigBase::Get( false );
|
||||
wxASSERT( cfg != NULL );
|
||||
|
||||
if( m_RecentIsoList != NULL )
|
||||
if( m_RecentIsoList )
|
||||
m_RecentIsoList->Save( *cfg );
|
||||
safe_delete( m_RecentIsoList );
|
||||
m_RecentIsoList = new wxFileHistory( g_Conf->RecentFileCount );
|
||||
m_RecentIsoList.reset();
|
||||
m_RecentIsoList.reset( new wxFileHistory( g_Conf->RecentFileCount ) );
|
||||
m_RecentIsoList->Load( *cfg );
|
||||
|
||||
UpdateIsoSrcFile();
|
||||
|
@ -37,7 +37,7 @@ class MainEmuFrame : public wxFrame
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
wxFileHistory* m_RecentIsoList;
|
||||
wxScopedPtr<wxFileHistory> m_RecentIsoList;
|
||||
wxStatusBar& m_statusbar;
|
||||
wxStaticBitmap m_background;
|
||||
|
||||
|
@ -25,6 +25,90 @@
|
||||
#include "HostGui.h"
|
||||
#include "AppConfig.h"
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// LoadPluginsTask
|
||||
// --------------------------------------------------------------------------------------
|
||||
// On completion the thread sends a pxEVT_LoadPluginsComplete message, which contains a
|
||||
// handle to this thread object. If the load is successful, the Result var is set to
|
||||
// non-NULL. If NULL, an error occurred and the thread loads the exception into either
|
||||
// Ex_PluginError or Ex_RuntimeError.
|
||||
//
|
||||
class LoadPluginsTask : public Threading::PersistentThread
|
||||
{
|
||||
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 )
|
||||
{
|
||||
for(int i=0; i<PluginId_Count; ++i )
|
||||
m_folders[i] = folders[i];
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
virtual ~LoadPluginsTask() throw();
|
||||
|
||||
protected:
|
||||
int ExecuteTask();
|
||||
};
|
||||
|
||||
static wxScopedPtr<LoadPluginsTask> _loadTask;
|
||||
|
||||
LoadPluginsTask::~LoadPluginsTask() throw()
|
||||
{
|
||||
_loadTask.release();
|
||||
PersistentThread::Cancel();
|
||||
_loadTask.reset();
|
||||
}
|
||||
|
||||
int LoadPluginsTask::ExecuteTask()
|
||||
{
|
||||
wxGetApp().Ping();
|
||||
Sleep(3);
|
||||
|
||||
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 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
|
||||
{
|
||||
wxScopedPtr<wxArrayString> placebo;
|
||||
@ -45,69 +129,29 @@ int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
|
||||
wxDir::GetAllFiles( searchpath.ToString(), realdest, wxsFormat( pattern, wxDynamicLibrary::GetDllExt()), wxDIR_FILES ) : 0;
|
||||
}
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt )
|
||||
{
|
||||
ReloadPlugins();
|
||||
}
|
||||
|
||||
void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt )
|
||||
{
|
||||
// scoped ptr ensures the thread object is cleaned up even on exception:
|
||||
wxScopedPtr<LoadPluginsTask> killTask( (LoadPluginsTask*)evt.GetClientData() );
|
||||
m_CorePlugins.reset( 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()
|
||||
{
|
||||
class LoadPluginsTask : public Threading::BaseTaskThread
|
||||
{
|
||||
public:
|
||||
PluginManager* Result;
|
||||
Exception::PluginError* Ex_PluginError;
|
||||
Exception::RuntimeError* Ex_RuntimeError;
|
||||
|
||||
protected:
|
||||
const wxString (&m_folders)[PluginId_Count];
|
||||
|
||||
public:
|
||||
LoadPluginsTask( const wxString (&folders)[PluginId_Count] ) :
|
||||
Result( NULL )
|
||||
, Ex_PluginError( NULL )
|
||||
, Ex_RuntimeError( NULL )
|
||||
, m_folders( folders )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~LoadPluginsTask() throw()
|
||||
{
|
||||
BaseTaskThread::Cancel();
|
||||
}
|
||||
|
||||
protected:
|
||||
void Task()
|
||||
{
|
||||
wxGetApp().Ping();
|
||||
Sleep(3);
|
||||
|
||||
try
|
||||
{
|
||||
//throw Exception::PluginError( PluginId_PAD, "This one is for testing the error handler!" );
|
||||
Result = PluginManager_Create( m_folders );
|
||||
}
|
||||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
Result = NULL;
|
||||
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.
|
||||
Result = NULL;
|
||||
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!
|
||||
}
|
||||
};
|
||||
if( _loadTask ) return;
|
||||
|
||||
m_CoreThread.reset();
|
||||
m_CorePlugins.reset();
|
||||
@ -123,20 +167,8 @@ void Pcsx2App::ReloadPlugins()
|
||||
passins[pi->id] = g_Conf->FullpathTo( pi->id );
|
||||
}
|
||||
|
||||
LoadPluginsTask task( passins );
|
||||
task.Start();
|
||||
task.PostTask();
|
||||
task.WaitForResult();
|
||||
|
||||
if( task.Result == NULL )
|
||||
{
|
||||
if( task.Ex_PluginError != NULL )
|
||||
throw *task.Ex_PluginError;
|
||||
if( task.Ex_RuntimeError != NULL )
|
||||
throw *task.Ex_RuntimeError; // Re-Throws generic threaded errors
|
||||
}
|
||||
|
||||
m_CorePlugins.reset( task.Result );
|
||||
_loadTask.reset( new LoadPluginsTask( passins ) );
|
||||
// ... and when it finishes it posts up a OnLoadPluginsComplete(). Bye. :)
|
||||
}
|
||||
|
||||
// Posts a message to the App to reload plugins. Plugins are loaded via a background thread
|
||||
@ -158,6 +190,11 @@ void LoadPluginsImmediate()
|
||||
|
||||
wxASSERT( !guard.IsReentrant() );
|
||||
wxGetApp().ReloadPlugins();
|
||||
while( _loadTask )
|
||||
{
|
||||
Sleep( 10 );
|
||||
wxGetApp().ProcessPendingEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void UnloadPlugins()
|
||||
|
Loading…
Reference in New Issue
Block a user