mirror of https://github.com/PCSX2/pcsx2.git
* Fixed death-by-recursion caused when a thread threw an exception.
* Fixed some minor bugs when processing idle events. * Plugin Load/Init/Shutdown/Unload are all called from the Main/UI thread again; this is important for plugins that issue popup warning/error messages. DevNotes: * Added ScopedPtrMT, a multithread-safe version of ScopedPtr. * MTGS errors are still not handled as gracefully as they should be; namely the MTGS thread doesn't restart itself (it's on the TODO list). git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2958 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
0918cb42a3
commit
12bdd9dc10
|
@ -537,6 +537,10 @@
|
||||||
RelativePath="..\..\include\Utilities\ScopedPtr.h"
|
RelativePath="..\..\include\Utilities\ScopedPtr.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\include\Utilities\ScopedPtrMT.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\Utilities\StringHelpers.h"
|
RelativePath="..\..\include\Utilities\StringHelpers.h"
|
||||||
>
|
>
|
||||||
|
|
|
@ -170,6 +170,7 @@ namespace Exception
|
||||||
DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
|
DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
|
||||||
|
|
||||||
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 );
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Threading.h"
|
#include "Threading.h"
|
||||||
|
#include "ScopedPtrMT.h"
|
||||||
#include "EventSource.h"
|
#include "EventSource.h"
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
|
@ -130,7 +131,7 @@ namespace Threading
|
||||||
|
|
||||||
// exception handle, set non-NULL if the thread terminated with an exception
|
// exception handle, set non-NULL if the thread terminated with an exception
|
||||||
// Use RethrowException() to re-throw the exception using its original exception type.
|
// Use RethrowException() to re-throw the exception using its original exception type.
|
||||||
ScopedPtr<BaseException> m_except;
|
ScopedPtrMT<BaseException> m_except;
|
||||||
|
|
||||||
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
|
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2010 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
|
#pragma once
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -15,10 +30,12 @@ protected:
|
||||||
public:
|
public:
|
||||||
typedef T element_type;
|
typedef T element_type;
|
||||||
|
|
||||||
wxEXPLICIT ScopedPtr(T * ptr = NULL) : m_ptr(ptr) { }
|
wxEXPLICIT ScopedPtr(T * ptr = NULL)
|
||||||
|
{
|
||||||
|
m_ptr = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
~ScopedPtr() throw()
|
~ScopedPtr() throw() { Delete(); }
|
||||||
{ Delete(); }
|
|
||||||
|
|
||||||
ScopedPtr& Reassign(T * ptr = NULL)
|
ScopedPtr& Reassign(T * ptr = NULL)
|
||||||
{
|
{
|
||||||
|
@ -128,13 +145,14 @@ class ScopedArray
|
||||||
protected:
|
protected:
|
||||||
T* m_array;
|
T* m_array;
|
||||||
uint m_valid_range;
|
uint m_valid_range;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef T element_type;
|
typedef T element_type;
|
||||||
|
|
||||||
wxEXPLICIT ScopedArray(T * ptr = NULL) :
|
wxEXPLICIT ScopedArray(T * ptr = NULL) :
|
||||||
m_array(ptr)
|
|
||||||
, m_valid_range( 0xffffffff )
|
|
||||||
{
|
{
|
||||||
|
m_array = ptr;
|
||||||
|
m_valid_range = 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxEXPLICIT ScopedArray( int size ) :
|
wxEXPLICIT ScopedArray( int size ) :
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2010 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 "Threading.h"
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// ScopedPtrMT
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
class ScopedPtrMT
|
||||||
|
{
|
||||||
|
DeclareNoncopyableObject(ScopedPtrMT);
|
||||||
|
|
||||||
|
typedef T* TPtr;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
volatile TPtr m_ptr;
|
||||||
|
Threading::Mutex m_mtx;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef T element_type;
|
||||||
|
|
||||||
|
wxEXPLICIT ScopedPtrMT(T * ptr = NULL)
|
||||||
|
{
|
||||||
|
m_ptr = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedPtrMT() throw() { _Delete_unlocked(); }
|
||||||
|
|
||||||
|
ScopedPtrMT& Reassign(T * ptr = NULL)
|
||||||
|
{
|
||||||
|
TPtr doh = (TPtr)AtomicExchangePointer( m_ptr, ptr );
|
||||||
|
if ( ptr != doh ) delete doh;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedPtrMT& Delete() throw()
|
||||||
|
{
|
||||||
|
ScopedLock lock( m_mtx );
|
||||||
|
_Delete_unlocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the pointer from scoped management, but does not delete!
|
||||||
|
// (ScopedPtr will be NULL after this method)
|
||||||
|
T *DetachPtr()
|
||||||
|
{
|
||||||
|
ScopedLock lock( m_mtx );
|
||||||
|
|
||||||
|
T *ptr = m_ptr;
|
||||||
|
m_ptr = NULL;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the managed pointer. Can return NULL as a valid result if the ScopedPtrMT
|
||||||
|
// has no object in management.
|
||||||
|
T* GetPtr() const
|
||||||
|
{
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapPtr(ScopedPtrMT& other)
|
||||||
|
{
|
||||||
|
ScopedLock lock( m_mtx );
|
||||||
|
T * const tmp = other.m_ptr;
|
||||||
|
other.m_ptr = m_ptr;
|
||||||
|
m_ptr = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// ScopedPtrMT Operators
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// I've decided to use the ATL's approach to pointer validity tests, opposed to
|
||||||
|
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
|
||||||
|
// allow the T* implicit casting.
|
||||||
|
|
||||||
|
bool operator!() const throw()
|
||||||
|
{
|
||||||
|
return m_ptr == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equality
|
||||||
|
bool operator==(T* pT) const throw()
|
||||||
|
{
|
||||||
|
return m_ptr == pT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inequality
|
||||||
|
bool operator!=(T* pT) const throw()
|
||||||
|
{
|
||||||
|
return !operator==(pT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenient assignment operator. ScopedPtrMT = NULL will issue an automatic deletion
|
||||||
|
// of the managed pointer.
|
||||||
|
ScopedPtrMT& operator=( T* src )
|
||||||
|
{
|
||||||
|
return Reassign( src );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
operator T*() const
|
||||||
|
{
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dereference operator, returns a handle to the managed pointer.
|
||||||
|
// Generates a debug assertion if the object is NULL!
|
||||||
|
T& operator*() const
|
||||||
|
{
|
||||||
|
pxAssert(m_ptr != NULL);
|
||||||
|
return *m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator->() const
|
||||||
|
{
|
||||||
|
pxAssert(m_ptr != NULL);
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _Delete_unlocked() throw()
|
||||||
|
{
|
||||||
|
delete m_ptr;
|
||||||
|
m_ptr = NULL;
|
||||||
|
}
|
||||||
|
};
|
|
@ -156,15 +156,11 @@ namespace Threading
|
||||||
|
|
||||||
extern bool AtomicBitTestAndReset( volatile u32& bitset, u8 bit );
|
extern bool AtomicBitTestAndReset( volatile u32& bitset, u8 bit );
|
||||||
|
|
||||||
extern void* _AtomicExchangePointer( void * volatile * const target, void* const value );
|
extern void* _AtomicExchangePointer( volatile uptr& target, uptr value );
|
||||||
extern void* _AtomicCompareExchangePointer( void * volatile * const target, void* const value, void* const comparand );
|
extern void* _AtomicCompareExchangePointer( volatile uptr& target, uptr value, uptr comparand );
|
||||||
|
|
||||||
#define AtomicExchangePointer( target, value ) \
|
|
||||||
_InterlockedExchangePointer( &target, value )
|
|
||||||
|
|
||||||
#define AtomicCompareExchangePointer( target, value, comparand ) \
|
|
||||||
_InterlockedCompareExchangePointer( &target, value, comparand )
|
|
||||||
|
|
||||||
|
#define AtomicExchangePointer( dest, src ) _AtomicExchangePointer( (uptr&)dest, (uptr)src )
|
||||||
|
#define AtomicCompareExchangePointer( dest, comp, src ) _AtomicExchangePointer( (uptr&)dest, (uptr)comp, (uptr)src )
|
||||||
|
|
||||||
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
||||||
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
|
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
|
||||||
|
|
|
@ -43,6 +43,8 @@ public:
|
||||||
|
|
||||||
typedef void FnType_Void();
|
typedef void FnType_Void();
|
||||||
|
|
||||||
|
typedef std::list<wxEvent*> wxEventList;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// wxAppWithHelpers
|
// wxAppWithHelpers
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -53,9 +55,9 @@ class wxAppWithHelpers : public wxApp
|
||||||
DECLARE_DYNAMIC_CLASS(wxAppWithHelpers)
|
DECLARE_DYNAMIC_CLASS(wxAppWithHelpers)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<wxEvent*> m_IdleEventQueue;
|
wxEventList m_IdleEventQueue;
|
||||||
Threading::Mutex m_IdleEventMutex;
|
Threading::MutexRecursive m_IdleEventMutex;
|
||||||
wxTimer m_IdleEventTimer;
|
wxTimer m_IdleEventTimer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxAppWithHelpers();
|
wxAppWithHelpers();
|
||||||
|
@ -105,7 +107,7 @@ public:
|
||||||
bool ProcessEvent( pxInvokeActionEvent* evt );
|
bool ProcessEvent( pxInvokeActionEvent* evt );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void IdleEventDispatcher( const char* action );
|
void IdleEventDispatcher( const wxChar* action );
|
||||||
|
|
||||||
void OnIdleEvent( wxIdleEvent& evt );
|
void OnIdleEvent( wxIdleEvent& evt );
|
||||||
void OnStartIdleEventTimer( wxEvent& evt );
|
void OnStartIdleEventTimer( wxEvent& evt );
|
||||||
|
|
|
@ -174,8 +174,19 @@ wxString BaseException::FormatDiagnosticMessage() const
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
Exception::RuntimeError::RuntimeError( const std::runtime_error& ex, const wxString& prefix )
|
Exception::RuntimeError::RuntimeError( const std::runtime_error& ex, const wxString& prefix )
|
||||||
{
|
{
|
||||||
const wxString msg( wxsFormat( L"%sSTL Runtime Error: %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()
|
||||||
|
) );
|
||||||
|
|
||||||
|
BaseException::InitBaseEx( msg, msg );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString& prefix )
|
||||||
|
{
|
||||||
|
const wxString msg( wxsFormat( L"STL Exception%s: %s",
|
||||||
|
(prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()),
|
||||||
fromUTF8( ex.what() ).c_str()
|
fromUTF8( ex.what() ).c_str()
|
||||||
) );
|
) );
|
||||||
|
|
||||||
|
|
|
@ -380,8 +380,14 @@ void Threading::PersistentThread::AddListener( EventListener_Thread& evt )
|
||||||
// the thread will have allowed itself to terminate properly.
|
// the thread will have allowed itself to terminate properly.
|
||||||
void Threading::PersistentThread::RethrowException() const
|
void Threading::PersistentThread::RethrowException() const
|
||||||
{
|
{
|
||||||
if( !m_except ) return;
|
// Thread safety note: always detach the m_except pointer. If we checked it for NULL, the
|
||||||
m_except->Rethrow();
|
// pointer might still be invalid after detachment, so might as well just detach and check
|
||||||
|
// after.
|
||||||
|
|
||||||
|
ScopedPtr<BaseException> ptr( const_cast<PersistentThread*>(this)->m_except.DetachPtr() );
|
||||||
|
if( ptr ) ptr->Rethrow();
|
||||||
|
|
||||||
|
//m_except->Rethrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool m_BlockDeletions = false;
|
static bool m_BlockDeletions = false;
|
||||||
|
@ -533,8 +539,9 @@ void Threading::PersistentThread::_try_virtual_invoke( void (PersistentThread::*
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
catch( Exception::RuntimeError& ex )
|
catch( Exception::RuntimeError& ex )
|
||||||
{
|
{
|
||||||
m_except = ex.Clone();
|
BaseException* woot = ex.Clone();
|
||||||
m_except->DiagMsg() = wxsFormat( L"(thread:%s) ", GetName().c_str() ) + m_except->DiagMsg();
|
woot->DiagMsg() += wxsFormat( L"(thread:%s)", GetName().c_str() );
|
||||||
|
m_except = woot;
|
||||||
}
|
}
|
||||||
#ifndef PCSX2_DEVBUILD
|
#ifndef PCSX2_DEVBUILD
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -543,13 +550,13 @@ void Threading::PersistentThread::_try_virtual_invoke( void (PersistentThread::*
|
||||||
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
|
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
|
||||||
/*catch( std::logic_error& ex )
|
/*catch( std::logic_error& ex )
|
||||||
{
|
{
|
||||||
throw BaseException( wxsFormat( L"(thread: %s) STL Logic Error: %s",
|
throw BaseException( wxsFormat( L"STL Logic Error (thread:%s): %s",
|
||||||
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
|
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch( std::exception& ex )
|
catch( std::exception& ex )
|
||||||
{
|
{
|
||||||
throw BaseException( wxsFormat( L"(thread: %s) STL exception: %s",
|
throw BaseException( wxsFormat( L"STL exception (thread:%s): %s",
|
||||||
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
|
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
|
||||||
);
|
);
|
||||||
}*/
|
}*/
|
||||||
|
@ -805,6 +812,24 @@ __forceinline s32 Threading::AtomicDecrement( volatile s32& Target )
|
||||||
return _InterlockedExchangeAdd( (volatile long*)&Target, -1 );
|
return _InterlockedExchangeAdd( (volatile long*)&Target, -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__forceinline void* Threading::_AtomicExchangePointer( volatile uptr& target, uptr value )
|
||||||
|
{
|
||||||
|
#ifdef _M_AMD64 // high-level atomic ops, please leave these 64 bit checks in place.
|
||||||
|
return (void*)_InterlockedExchange64( &(volatile s64&)target, value );
|
||||||
|
#else
|
||||||
|
return (void*)_InterlockedExchange( (volatile long*)&target, value );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void* Threading::_AtomicCompareExchangePointer( volatile uptr& target, uptr value, uptr comparand )
|
||||||
|
{
|
||||||
|
#ifdef _M_AMD64 // high-level atomic ops, please leave these 64 bit checks in place.
|
||||||
|
return (void*)_InterlockedCompareExchange64( &(volatile s64&)target, value );
|
||||||
|
#else
|
||||||
|
return (void*)_InterlockedCompareExchange( &(volatile long&)target, value, comparand );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// BaseThreadError
|
// BaseThreadError
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -420,27 +420,37 @@ void wxAppWithHelpers::OnStartIdleEventTimer( wxEvent& evt )
|
||||||
m_IdleEventTimer.Start( 100, true );
|
m_IdleEventTimer.Start( 100, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::IdleEventDispatcher( const char* action )
|
void wxAppWithHelpers::IdleEventDispatcher( const wxChar* action )
|
||||||
{
|
{
|
||||||
|
// Recursion is possible thanks to modal dialogs being issued from the idle event handler.
|
||||||
|
// (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator
|
||||||
|
// on each pass)
|
||||||
|
|
||||||
|
//static int __guard=0;
|
||||||
|
//RecursionGuard guard(__guard);
|
||||||
|
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
|
||||||
|
|
||||||
|
wxEventList postponed;
|
||||||
|
wxEventList::iterator node;
|
||||||
|
|
||||||
ScopedLock lock( m_IdleEventMutex );
|
ScopedLock lock( m_IdleEventMutex );
|
||||||
|
|
||||||
size_t size = m_IdleEventQueue.size();
|
while( node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end() )
|
||||||
if( size == 0 ) return;
|
|
||||||
|
|
||||||
DbgCon.WriteLn( Color_Gray, "App IdleQueue (%s) -> %u events.", action, size );
|
|
||||||
|
|
||||||
std::vector<wxEvent*> postponed;
|
|
||||||
|
|
||||||
for( size_t i=0; i<size; ++i )
|
|
||||||
{
|
{
|
||||||
if( !Threading::AllowDeletions() && (m_IdleEventQueue[i]->GetEventType() == pxEvt_DeleteThread) )
|
ScopedPtr<wxEvent> deleteMe(*node);
|
||||||
postponed.push_back(m_IdleEventQueue[i]);
|
m_IdleEventQueue.erase( node );
|
||||||
|
|
||||||
|
lock.Release();
|
||||||
|
if( !Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread) )
|
||||||
|
{
|
||||||
|
postponed.push_back(deleteMe.DetachPtr());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lock.Release();
|
DbgCon.WriteLn( Color_Gray, L"(AppIdleQueue:%s) -> Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName() );
|
||||||
ProcessEvent( *m_IdleEventQueue[i] );
|
ProcessEvent( *deleteMe ); // dereference to prevent auto-deletion by ProcessEvent
|
||||||
lock.Acquire();
|
|
||||||
}
|
}
|
||||||
|
lock.Acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_IdleEventQueue = postponed;
|
m_IdleEventQueue = postponed;
|
||||||
|
@ -449,12 +459,12 @@ void wxAppWithHelpers::IdleEventDispatcher( const char* action )
|
||||||
void wxAppWithHelpers::OnIdleEvent( wxIdleEvent& evt )
|
void wxAppWithHelpers::OnIdleEvent( wxIdleEvent& evt )
|
||||||
{
|
{
|
||||||
m_IdleEventTimer.Stop();
|
m_IdleEventTimer.Stop();
|
||||||
IdleEventDispatcher( "Idle" );
|
IdleEventDispatcher( L"Idle" );
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::OnIdleEventTimeout( wxTimerEvent& evt )
|
void wxAppWithHelpers::OnIdleEventTimeout( wxTimerEvent& evt )
|
||||||
{
|
{
|
||||||
IdleEventDispatcher( "Timeout" );
|
IdleEventDispatcher( L"Timeout" );
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppWithHelpers::Ping()
|
void wxAppWithHelpers::Ping()
|
||||||
|
|
|
@ -523,8 +523,11 @@ void SysMtgsThread::WaitGS()
|
||||||
if( volatize(m_RingPos) != m_WritePos )
|
if( volatize(m_RingPos) != m_WritePos )
|
||||||
{
|
{
|
||||||
SetEvent();
|
SetEvent();
|
||||||
|
RethrowException();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
m_lock_RingBufferBusy.Wait();
|
m_lock_RingBufferBusy.Wait();
|
||||||
|
RethrowException();
|
||||||
} while( volatize(m_RingPos) != m_WritePos );
|
} while( volatize(m_RingPos) != m_WritePos );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -867,19 +867,17 @@ void PluginManager::Load( PluginsEnum_t pid, const wxString& srcfile )
|
||||||
{
|
{
|
||||||
ScopedLock lock( m_mtx_PluginStatus );
|
ScopedLock lock( m_mtx_PluginStatus );
|
||||||
pxAssume( (uint)pid < PluginId_Count );
|
pxAssume( (uint)pid < PluginId_Count );
|
||||||
Console.WriteLn( L"Binding %s\t: %s ", tbl_PluginInfo[pid].GetShortname().c_str(), srcfile.c_str() );
|
Console.Indent().WriteLn( L"Binding %s\t: %s ", tbl_PluginInfo[pid].GetShortname().c_str(), srcfile.c_str() );
|
||||||
m_info[pid] = new PluginStatus_t( pid, srcfile );
|
m_info[pid] = new PluginStatus_t( pid, srcfile );
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginManager::Load( const wxString (&folders)[PluginId_Count] )
|
void PluginManager::Load( const wxString (&folders)[PluginId_Count] )
|
||||||
{
|
{
|
||||||
ScopedLock lock( m_mtx_PluginStatus );
|
|
||||||
|
|
||||||
if( !NeedsLoad() ) return;
|
if( !NeedsLoad() ) return;
|
||||||
|
|
||||||
wxDoNotLogInThisScope please;
|
wxDoNotLogInThisScope please;
|
||||||
|
|
||||||
Console.WriteLn( Color_StrongBlue, "Loading plugins..." );
|
Console.WriteLn( Color_StrongBlue, "\nLoading plugins..." );
|
||||||
|
|
||||||
ConsoleIndentScope indent;
|
ConsoleIndentScope indent;
|
||||||
const PluginInfo* pi = tbl_PluginInfo; do
|
const PluginInfo* pi = tbl_PluginInfo; do
|
||||||
|
@ -939,8 +937,6 @@ void PluginManager::Unload(PluginsEnum_t pid)
|
||||||
|
|
||||||
void PluginManager::Unload()
|
void PluginManager::Unload()
|
||||||
{
|
{
|
||||||
ScopedLock lock( m_mtx_PluginStatus );
|
|
||||||
|
|
||||||
if( NeedsShutdown() )
|
if( NeedsShutdown() )
|
||||||
Console.Warning( "(SysCorePlugins) Warning: Unloading plugins prior to shutdown!" );
|
Console.Warning( "(SysCorePlugins) Warning: Unloading plugins prior to shutdown!" );
|
||||||
|
|
||||||
|
@ -954,7 +950,6 @@ void PluginManager::Unload()
|
||||||
Unload( tbl_PluginInfo[i].id );
|
Unload( tbl_PluginInfo[i].id );
|
||||||
|
|
||||||
DbgCon.WriteLn( Color_StrongBlue, "Plugins unloaded successfully." );
|
DbgCon.WriteLn( Color_StrongBlue, "Plugins unloaded successfully." );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exceptions:
|
// Exceptions:
|
||||||
|
@ -1167,6 +1162,29 @@ void PluginManager::Close()
|
||||||
DbgCon.WriteLn( Color_StrongBlue, "Plugins closed successfully." );
|
DbgCon.WriteLn( Color_StrongBlue, "Plugins closed successfully." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PluginManager::Init( PluginsEnum_t pid )
|
||||||
|
{
|
||||||
|
ScopedLock lock( m_mtx_PluginStatus );
|
||||||
|
|
||||||
|
if( !m_info[pid] || m_info[pid]->IsInitialized ) return;
|
||||||
|
|
||||||
|
Console.Indent().WriteLn( "Init %s", tbl_PluginInfo[pid].shortname );
|
||||||
|
if( NULL != m_info[pid]->CommonBindings.Init() )
|
||||||
|
throw Exception::PluginInitError( pid );
|
||||||
|
|
||||||
|
m_info[pid]->IsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginManager::Shutdown( PluginsEnum_t pid )
|
||||||
|
{
|
||||||
|
ScopedLock lock( m_mtx_PluginStatus );
|
||||||
|
|
||||||
|
if( !m_info[pid] || !m_info[pid]->IsInitialized ) return;
|
||||||
|
DevCon.Indent().WriteLn( "Shutdown %s", tbl_PluginInfo[pid].shortname );
|
||||||
|
m_info[pid]->IsInitialized = false;
|
||||||
|
m_info[pid]->CommonBindings.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
// Initializes all plugins. Plugin initialization should be done once for every new emulation
|
// Initializes all plugins. Plugin initialization should be done once for every new emulation
|
||||||
// session. During a session emulation can be paused/resumed using Open/Close, and should be
|
// session. During a session emulation can be paused/resumed using Open/Close, and should be
|
||||||
// terminated using Shutdown().
|
// terminated using Shutdown().
|
||||||
|
@ -1177,26 +1195,11 @@ void PluginManager::Close()
|
||||||
//
|
//
|
||||||
void PluginManager::Init()
|
void PluginManager::Init()
|
||||||
{
|
{
|
||||||
ScopedLock lock( m_mtx_PluginStatus );
|
|
||||||
|
|
||||||
if( !NeedsInit() ) return;
|
if( !NeedsInit() ) return;
|
||||||
|
|
||||||
bool printlog = false;
|
Console.WriteLn( Color_StrongBlue, "\nInitializing plugins..." );
|
||||||
const PluginInfo* pi = tbl_PluginInfo; do
|
const PluginInfo* pi = tbl_PluginInfo; do {
|
||||||
{
|
Init( pi->id );
|
||||||
const PluginsEnum_t pid = pi->id;
|
|
||||||
|
|
||||||
if( !m_info[pid] || m_info[pid]->IsInitialized ) continue;
|
|
||||||
if( !printlog )
|
|
||||||
{
|
|
||||||
Console.WriteLn( Color_StrongBlue, "Initializing plugins..." );
|
|
||||||
printlog = true;
|
|
||||||
}
|
|
||||||
Console.Indent().WriteLn( "Init %s", tbl_PluginInfo[pid].shortname );
|
|
||||||
if( 0 != m_info[pid]->CommonBindings.Init() )
|
|
||||||
throw Exception::PluginInitError( pid );
|
|
||||||
|
|
||||||
m_info[pid]->IsInitialized = true;
|
|
||||||
} while( ++pi, pi->shortname != NULL );
|
} while( ++pi, pi->shortname != NULL );
|
||||||
|
|
||||||
if( SysPlugins.Mcd == NULL )
|
if( SysPlugins.Mcd == NULL )
|
||||||
|
@ -1209,10 +1212,10 @@ void PluginManager::Init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( printlog )
|
Console.WriteLn( Color_StrongBlue, "Plugins initialized successfully.\n" );
|
||||||
Console.WriteLn( Color_StrongBlue, "Plugins initialized successfully.\n" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Shuts down all plugins. Plugins are closed first, if necessary.
|
// Shuts down all plugins. Plugins are closed first, if necessary.
|
||||||
//
|
//
|
||||||
// In a purist emulation sense, Init() and Shutdown() should only ever need be called for when
|
// In a purist emulation sense, Init() and Shutdown() should only ever need be called for when
|
||||||
|
@ -1221,7 +1224,6 @@ void PluginManager::Init()
|
||||||
//
|
//
|
||||||
void PluginManager::Shutdown()
|
void PluginManager::Shutdown()
|
||||||
{
|
{
|
||||||
ScopedLock lock( m_mtx_PluginStatus );
|
|
||||||
if( !NeedsShutdown() ) return;
|
if( !NeedsShutdown() ) return;
|
||||||
|
|
||||||
pxAssumeDev( !NeedsClose(), "Cannot shut down plugins prior to Close()" );
|
pxAssumeDev( !NeedsClose(), "Cannot shut down plugins prior to Close()" );
|
||||||
|
@ -1235,11 +1237,7 @@ void PluginManager::Shutdown()
|
||||||
|
|
||||||
for( int i=PluginId_Count-1; i>=0; --i )
|
for( int i=PluginId_Count-1; i>=0; --i )
|
||||||
{
|
{
|
||||||
const PluginsEnum_t pid = tbl_PluginInfo[i].id;
|
Shutdown( tbl_PluginInfo[i].id );
|
||||||
if( !m_info[pid] || !m_info[pid]->IsInitialized ) continue;
|
|
||||||
DevCon.Indent().WriteLn( "Shutdown %s", tbl_PluginInfo[pid].shortname );
|
|
||||||
m_info[pid]->IsInitialized = false;
|
|
||||||
m_info[pid]->CommonBindings.Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// More memorycard hacks!!
|
// More memorycard hacks!!
|
||||||
|
@ -1448,6 +1446,8 @@ bool PluginManager::NeedsUnload() const
|
||||||
|
|
||||||
bool PluginManager::NeedsInit() const
|
bool PluginManager::NeedsInit() const
|
||||||
{
|
{
|
||||||
|
ScopedLock lock( m_mtx_PluginStatus );
|
||||||
|
|
||||||
const PluginInfo* pi = tbl_PluginInfo; do {
|
const PluginInfo* pi = tbl_PluginInfo; do {
|
||||||
if( !IsInitialized(pi->id) ) return true;
|
if( !IsInitialized(pi->id) ) return true;
|
||||||
} while( ++pi, pi->shortname != NULL );
|
} while( ++pi, pi->shortname != NULL );
|
||||||
|
@ -1457,6 +1457,8 @@ bool PluginManager::NeedsInit() const
|
||||||
|
|
||||||
bool PluginManager::NeedsShutdown() const
|
bool PluginManager::NeedsShutdown() const
|
||||||
{
|
{
|
||||||
|
ScopedLock lock( m_mtx_PluginStatus );
|
||||||
|
|
||||||
const PluginInfo* pi = tbl_PluginInfo; do {
|
const PluginInfo* pi = tbl_PluginInfo; do {
|
||||||
if( IsInitialized(pi->id) ) return true;
|
if( IsInitialized(pi->id) ) return true;
|
||||||
} while( ++pi, pi->shortname != NULL );
|
} while( ++pi, pi->shortname != NULL );
|
||||||
|
|
|
@ -275,10 +275,10 @@ public:
|
||||||
PluginManager();
|
PluginManager();
|
||||||
virtual ~PluginManager() throw();
|
virtual ~PluginManager() throw();
|
||||||
|
|
||||||
void Load( PluginsEnum_t pid, const wxString& srcfile );
|
virtual void Load( PluginsEnum_t pid, const wxString& srcfile );
|
||||||
void Load( const wxString (&folders)[PluginId_Count] );
|
virtual void Load( const wxString (&folders)[PluginId_Count] );
|
||||||
void Unload();
|
virtual void Unload();
|
||||||
void Unload( PluginsEnum_t pid );
|
virtual void Unload( PluginsEnum_t pid );
|
||||||
|
|
||||||
bool AreLoaded() const;
|
bool AreLoaded() const;
|
||||||
bool AreAnyLoaded() const;
|
bool AreAnyLoaded() const;
|
||||||
|
@ -287,6 +287,8 @@ public:
|
||||||
Threading::Mutex& GetMutex() { return m_mtx_PluginStatus; }
|
Threading::Mutex& GetMutex() { return m_mtx_PluginStatus; }
|
||||||
|
|
||||||
virtual void Init();
|
virtual void Init();
|
||||||
|
virtual void Init( PluginsEnum_t pid );
|
||||||
|
virtual void Shutdown( PluginsEnum_t pid );
|
||||||
virtual void Shutdown();
|
virtual void Shutdown();
|
||||||
virtual void Open();
|
virtual void Open();
|
||||||
virtual void Open( PluginsEnum_t pid );
|
virtual void Open( PluginsEnum_t pid );
|
||||||
|
|
|
@ -98,46 +98,8 @@ static void ConvertPluginFilenames( wxString (&passins)[PluginId_Count] )
|
||||||
} while( ++pi, pi->shortname != NULL );
|
} while( ++pi, pi->shortname != NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// AppPluginManager
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
AppPluginManager::AppPluginManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AppPluginManager::~AppPluginManager() throw()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppPluginManager::Load( const wxString (&folders)[PluginId_Count] )
|
|
||||||
{
|
|
||||||
if( !pxAssert(!AreLoaded()) ) return;
|
|
||||||
|
|
||||||
SetSettingsFolder( GetSettingsFolder().ToString() );
|
|
||||||
_parent::Load( folders );
|
|
||||||
PostPluginStatus( CorePlugins_Loaded );
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppPluginManager::Unload()
|
|
||||||
{
|
|
||||||
_parent::Unload();
|
|
||||||
PostPluginStatus( CorePlugins_Unloaded );
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppPluginManager::Init()
|
|
||||||
{
|
|
||||||
SetSettingsFolder( GetSettingsFolder().ToString() );
|
|
||||||
_parent::Init();
|
|
||||||
PostPluginStatus( CorePlugins_Init );
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppPluginManager::Shutdown()
|
|
||||||
{
|
|
||||||
_parent::Shutdown();
|
|
||||||
PostPluginStatus( CorePlugins_Shutdown );
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (AppPluginManager::*FnPtr_AppPluginManager)();
|
typedef void (AppPluginManager::*FnPtr_AppPluginManager)();
|
||||||
|
typedef void (AppPluginManager::*FnPtr_AppPluginPid)( PluginsEnum_t pid );
|
||||||
|
|
||||||
class SysExecEvent_AppPluginManager : public SysExecEvent
|
class SysExecEvent_AppPluginManager : public SysExecEvent
|
||||||
{
|
{
|
||||||
|
@ -160,6 +122,162 @@ protected:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LoadSinglePluginEvent : public pxInvokeActionEvent
|
||||||
|
{
|
||||||
|
typedef pxInvokeActionEvent _parent;
|
||||||
|
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(LoadSinglePluginEvent)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
wxString m_filename;
|
||||||
|
PluginsEnum_t m_pid;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~LoadSinglePluginEvent() throw() { }
|
||||||
|
virtual LoadSinglePluginEvent *Clone() const { return new LoadSinglePluginEvent(*this); }
|
||||||
|
|
||||||
|
LoadSinglePluginEvent( PluginsEnum_t pid = PluginId_GS, const wxString& filename=wxEmptyString )
|
||||||
|
: m_filename( filename )
|
||||||
|
{
|
||||||
|
m_pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InvokeEvent()
|
||||||
|
{
|
||||||
|
GetCorePlugins().Load( m_pid, m_filename );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinglePluginMethodEvent : public pxInvokeActionEvent
|
||||||
|
{
|
||||||
|
typedef pxInvokeActionEvent _parent;
|
||||||
|
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(SinglePluginMethodEvent)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PluginsEnum_t m_pid;
|
||||||
|
FnPtr_AppPluginPid m_method;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~SinglePluginMethodEvent() throw() { }
|
||||||
|
virtual SinglePluginMethodEvent *Clone() const { return new SinglePluginMethodEvent(*this); }
|
||||||
|
|
||||||
|
SinglePluginMethodEvent( FnPtr_AppPluginPid method=NULL, PluginsEnum_t pid = PluginId_GS )
|
||||||
|
{
|
||||||
|
m_pid = pid;
|
||||||
|
m_method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InvokeEvent()
|
||||||
|
{
|
||||||
|
//GetCorePlugins().Unload( m_pid );
|
||||||
|
if( m_method ) (CorePlugins.*m_method)( m_pid );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_DYNAMIC_CLASS( LoadSinglePluginEvent, pxInvokeActionEvent );
|
||||||
|
IMPLEMENT_DYNAMIC_CLASS( SinglePluginMethodEvent, pxInvokeActionEvent );
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// AppPluginManager
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Thread Affinity Notes:
|
||||||
|
// It's important to ensure that Load/Unload/Init/Shutdown are all called from the
|
||||||
|
// MAIN/UI Thread only. Those APIs are allowed to issue modal popups, and as such
|
||||||
|
// are only safe when invoked form the UI thread. Under windows the popups themselves
|
||||||
|
// will typically work from any thread, but some common control activities will fail
|
||||||
|
// (such as opening the browser windows). On Linux it's probably just highly unsafe, period.
|
||||||
|
//
|
||||||
|
// My implementation is to execute the main Load/Init/Shutdown/Unload procedure on the
|
||||||
|
// SysExecutor, and then dispatch each individual plugin to the main thread. This keeps
|
||||||
|
// the main thread from being completely busy while plugins are loaded and initialized.
|
||||||
|
// (responsiveness is bliss!!) -- air
|
||||||
|
//
|
||||||
|
AppPluginManager::AppPluginManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AppPluginManager::~AppPluginManager() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPluginManager::Load( PluginsEnum_t pid, const wxString& srcfile )
|
||||||
|
{
|
||||||
|
if( !wxThread::IsMain() )
|
||||||
|
{
|
||||||
|
wxGetApp().ProcessAction( LoadSinglePluginEvent( pid, srcfile ) );
|
||||||
|
Sleep( 5 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent::Load( pid, srcfile );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPluginManager::Unload( PluginsEnum_t pid )
|
||||||
|
{
|
||||||
|
if( !wxThread::IsMain() )
|
||||||
|
{
|
||||||
|
wxGetApp().ProcessAction( SinglePluginMethodEvent( &AppPluginManager::Unload, pid ) );
|
||||||
|
Sleep( 5 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent::Unload( pid );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPluginManager::Load( const wxString (&folders)[PluginId_Count] )
|
||||||
|
{
|
||||||
|
if( !pxAssert(!AreLoaded()) ) return;
|
||||||
|
|
||||||
|
SetSettingsFolder( GetSettingsFolder().ToString() );
|
||||||
|
_parent::Load( folders );
|
||||||
|
PostPluginStatus( CorePlugins_Loaded );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPluginManager::Unload()
|
||||||
|
{
|
||||||
|
_parent::Unload();
|
||||||
|
PostPluginStatus( CorePlugins_Unloaded );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPluginManager::Init( PluginsEnum_t pid )
|
||||||
|
{
|
||||||
|
if( !wxThread::IsMain() )
|
||||||
|
{
|
||||||
|
wxGetApp().ProcessAction( SinglePluginMethodEvent( &AppPluginManager::Init, pid ) );
|
||||||
|
Sleep( 5 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent::Init( pid );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPluginManager::Shutdown( PluginsEnum_t pid )
|
||||||
|
{
|
||||||
|
if( !wxThread::IsMain() )
|
||||||
|
{
|
||||||
|
wxGetApp().ProcessAction( SinglePluginMethodEvent( &AppPluginManager::Shutdown, pid ) );
|
||||||
|
Sleep( 5 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent::Shutdown( pid );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPluginManager::Init()
|
||||||
|
{
|
||||||
|
SetSettingsFolder( GetSettingsFolder().ToString() );
|
||||||
|
_parent::Init();
|
||||||
|
PostPluginStatus( CorePlugins_Init );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPluginManager::Shutdown()
|
||||||
|
{
|
||||||
|
_parent::Shutdown();
|
||||||
|
PostPluginStatus( CorePlugins_Shutdown );
|
||||||
|
}
|
||||||
|
|
||||||
void AppPluginManager::Close()
|
void AppPluginManager::Close()
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFrom_CoreThread();
|
AffinityAssert_AllowFrom_CoreThread();
|
||||||
|
@ -413,8 +531,8 @@ SaveSinglePluginHelper::~SaveSinglePluginHelper() throw()
|
||||||
Console.WriteLn( Color_Green, L"Recovering single plugin: " + tbl_PluginInfo[m_pid].GetShortname() );
|
Console.WriteLn( Color_Green, L"Recovering single plugin: " + tbl_PluginInfo[m_pid].GetShortname() );
|
||||||
memLoadingState load( m_plugstore );
|
memLoadingState load( m_plugstore );
|
||||||
//if( m_plugstore.IsDisposed() ) load.SeekToSection( m_pid );
|
//if( m_plugstore.IsDisposed() ) load.SeekToSection( m_pid );
|
||||||
|
GetCorePlugins().Open( m_pid );
|
||||||
GetCorePlugins().Freeze( m_pid, load );
|
GetCorePlugins().Freeze( m_pid, load );
|
||||||
GetCorePlugins().Close( m_pid );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s_DisableGsWindow = false;
|
s_DisableGsWindow = false;
|
||||||
|
@ -422,14 +540,18 @@ SaveSinglePluginHelper::~SaveSinglePluginHelper() throw()
|
||||||
catch( BaseException& ex )
|
catch( BaseException& ex )
|
||||||
{
|
{
|
||||||
allowResume = false;
|
allowResume = false;
|
||||||
Console.Error( "Unhandled BaseException in %s (ignored!):", __pxFUNCTION__ );
|
wxGetApp().PostEvent( pxExceptionEvent( ex ) );
|
||||||
Console.Error( ex.FormatDiagnosticMessage() );
|
|
||||||
|
//Console.Error( "Unhandled BaseException in %s (ignored!):", __pxFUNCTION__ );
|
||||||
|
//Console.Error( ex.FormatDiagnosticMessage() );
|
||||||
}
|
}
|
||||||
catch( std::exception& ex )
|
catch( std::exception& ex )
|
||||||
{
|
{
|
||||||
allowResume = false;
|
allowResume = false;
|
||||||
Console.Error( "Unhandled std::exception in %s (ignored!):", __pxFUNCTION__ );
|
wxGetApp().PostEvent( pxExceptionEvent(new Exception::RuntimeError( ex, L"SaveSinglePlugin" )) );
|
||||||
Console.Error( ex.what() );
|
|
||||||
|
//Console.Error( "Unhandled std::exception in %s (ignored!):", __pxFUNCTION__ );
|
||||||
|
//Console.Error( ex.what() );
|
||||||
}
|
}
|
||||||
|
|
||||||
s_DisableGsWindow = false;
|
s_DisableGsWindow = false;
|
||||||
|
|
|
@ -35,9 +35,13 @@ public:
|
||||||
virtual ~AppPluginManager() throw();
|
virtual ~AppPluginManager() throw();
|
||||||
|
|
||||||
void Load( const wxString (&folders)[PluginId_Count] );
|
void Load( const wxString (&folders)[PluginId_Count] );
|
||||||
|
void Load( PluginsEnum_t pid, const wxString& srcfile );
|
||||||
|
void Unload( PluginsEnum_t pid );
|
||||||
void Unload();
|
void Unload();
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
|
void Init( PluginsEnum_t pid );
|
||||||
|
void Shutdown( PluginsEnum_t pid );
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void Close();
|
void Close();
|
||||||
void Open();
|
void Open();
|
||||||
|
|
|
@ -488,7 +488,7 @@ void Pcsx2App::CleanupRestartable()
|
||||||
|
|
||||||
//PingDispatcher( "Cleanup" );
|
//PingDispatcher( "Cleanup" );
|
||||||
//DeletionDispatcher();
|
//DeletionDispatcher();
|
||||||
IdleEventDispatcher( "Cleanup" );
|
IdleEventDispatcher( L"Cleanup" );
|
||||||
|
|
||||||
if( g_Conf )
|
if( g_Conf )
|
||||||
AppSaveSettings();
|
AppSaveSettings();
|
||||||
|
|
Loading…
Reference in New Issue