mirror of https://github.com/PCSX2/pcsx2.git
Re-implemented Ping() into wxApp, this time using Idle events (for once I found a use for them!). This because the YieldToMain logic wasn't ever going to work right since wxWidgets lacks a way to poll the event loop for pending events. End result: More responsive GUI dialogs and junk. ;)
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2376 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
f071faa642
commit
500c1dbfeb
|
@ -33,8 +33,12 @@ namespace Threading
|
|||
{
|
||||
class PersistentThread;
|
||||
|
||||
PersistentThread* pxGetCurrentThread();
|
||||
wxString pxGetCurrentThreadName();
|
||||
extern PersistentThread* pxGetCurrentThread();
|
||||
extern wxString pxGetCurrentThreadName();
|
||||
|
||||
// Yields the current thread and provides cancelation points if the thread is managed by
|
||||
// PersistentThread. Unmanaged threads use standard Sleep.
|
||||
extern void pxYield( int ms );
|
||||
}
|
||||
|
||||
namespace Exception
|
||||
|
@ -127,10 +131,6 @@ namespace Exception
|
|||
#endif
|
||||
}
|
||||
|
||||
// Yields this thread against the main thread *if* the main thread's message pump has pending
|
||||
// messages. If the main thread is idle then no yield is performed.
|
||||
extern void pxYieldToMain();
|
||||
|
||||
namespace Threading
|
||||
{
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -348,6 +348,8 @@ namespace Threading
|
|||
{
|
||||
DeclareNoncopyableObject(PersistentThread);
|
||||
|
||||
friend void pxYield( int ms );
|
||||
|
||||
protected:
|
||||
wxString m_name; // diagnostic name for our thread.
|
||||
|
||||
|
@ -402,7 +404,6 @@ namespace Threading
|
|||
virtual void ExecuteTaskInThread()=0;
|
||||
|
||||
void TestCancel() const;
|
||||
void YieldToMain() const;
|
||||
|
||||
// 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()
|
||||
|
|
|
@ -51,17 +51,4 @@ __forceinline void Threading::DisableHiresScheduler()
|
|||
{
|
||||
}
|
||||
|
||||
void pxYieldToMain()
|
||||
{
|
||||
// Linux/GTK+ Implementation Notes:
|
||||
// I have no idea if wxEventLoop::Pending() is thread safe or not, nor do I have
|
||||
// any idea how to properly obtain the message queue status of GTK+. So let's
|
||||
// just play dumb (and slow) and sleep for a couple milliseconds regardless, until
|
||||
// a better fix is found. --air
|
||||
|
||||
// (FIXME : Find a more correct implementation for this?)
|
||||
|
||||
Threading::Sleep( 2 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -92,6 +92,14 @@ wxString Threading::pxGetCurrentThreadName()
|
|||
return L"Unknown";
|
||||
}
|
||||
|
||||
void Threading::pxYield( int ms )
|
||||
{
|
||||
if( PersistentThread* thr = pxGetCurrentThread() )
|
||||
thr->Yield( ms );
|
||||
else
|
||||
Sleep( ms );
|
||||
}
|
||||
|
||||
// (intended for internal use only)
|
||||
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
|
||||
// handled via normal yielding methods.
|
||||
|
@ -465,12 +473,6 @@ void Threading::PersistentThread::TestCancel() const
|
|||
pthread_testcancel();
|
||||
}
|
||||
|
||||
void Threading::PersistentThread::YieldToMain() const
|
||||
{
|
||||
pxYieldToMain();
|
||||
TestCancel();
|
||||
}
|
||||
|
||||
// Executes the virtual member method
|
||||
void Threading::PersistentThread::_try_virtual_invoke( void (PersistentThread::*method)() )
|
||||
{
|
||||
|
|
|
@ -52,26 +52,5 @@ __forceinline void Threading::DisableHiresScheduler()
|
|||
timeEndPeriod( 1 );
|
||||
}
|
||||
|
||||
void pxYieldToMain()
|
||||
{
|
||||
// Windows Implementation Note:
|
||||
// wxWidgets has a wxEventLoop::Pending() function, however it uses PeekMessage internally
|
||||
// which is a multithreaded NO-NO. So instead we must use GetQueueStatus. This is ok
|
||||
// anyway since I get extra fancy and scale the sleep duration based on the type of messages
|
||||
// in the queue. User input (key and mouse button) cue longer worker thread yields since
|
||||
// maintaining a responsive gui is typically a high priority.
|
||||
|
||||
DWORD result = GetQueueStatus( QS_ALLEVENTS );
|
||||
uint hiword = HIWORD( result );
|
||||
|
||||
if( hiword == 0 ) return;
|
||||
|
||||
int sleepdur = 1;
|
||||
if( (hiword & (QS_MOUSEBUTTON | QS_KEY)) != 0 )
|
||||
sleepdur += 3;
|
||||
|
||||
Sleep( sleepdur );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -733,6 +733,9 @@ PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] )
|
|||
wxsFormat( L"Plugin Test failure, return code: %d", testres ),
|
||||
_( "The plugin reports that your hardware or software/drivers are not supported." )
|
||||
);
|
||||
|
||||
pxYield( 2 );
|
||||
|
||||
} while( ++pi, pi->shortname != NULL );
|
||||
|
||||
CDVDapi_Plugin.newDiskCB( cdvdNewDiskCB );
|
||||
|
|
|
@ -39,6 +39,7 @@ BEGIN_DECLARE_EVENT_TYPES()
|
|||
DECLARE_EVENT_TYPE( pxEVT_LoadPluginsComplete, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_CoreThreadStatus, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_FreezeThreadFinished, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_Ping, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
// This is used when the GS plugin is handling its own window. Messages from the PAD
|
||||
|
@ -327,8 +328,7 @@ public:
|
|||
class Pcsx2App : public wxApp
|
||||
{
|
||||
// ----------------------------------------------------------------------------
|
||||
// Event Sources!
|
||||
// ----------------------------------------------------------------------------
|
||||
// Event Sources!
|
||||
// These need to be at the top of the App class, because a lot of other things depend
|
||||
// on them and they are, themselves, fairly self-contained.
|
||||
|
||||
|
@ -345,7 +345,8 @@ public:
|
|||
EventSource<AppEventType>& Source_AppStatus() { return m_evtsrc_AppStatus; }
|
||||
EventSource<PluginEventType>& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; }
|
||||
EventSource<IniInterface>& Source_SettingsLoadSave() { return m_evtsrc_SettingsLoadSave; }
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
CommandDictionary GlobalCommands;
|
||||
AcceleratorDictionary GlobalAccels;
|
||||
|
@ -353,7 +354,6 @@ public:
|
|||
protected:
|
||||
ScopedPtr<PipeRedirectionBase> m_StdoutRedirHandle;
|
||||
ScopedPtr<PipeRedirectionBase> m_StderrRedirHandle;
|
||||
|
||||
ScopedPtr<pxAppResources> m_Resources;
|
||||
|
||||
public:
|
||||
|
@ -363,14 +363,18 @@ public:
|
|||
protected:
|
||||
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
||||
// of these objects internally.
|
||||
MainEmuFrame* m_MainFrame;
|
||||
GSFrame* m_gsFrame;
|
||||
ConsoleLogFrame* m_ProgramLogBox;
|
||||
MainEmuFrame* m_MainFrame;
|
||||
GSFrame* m_gsFrame;
|
||||
ConsoleLogFrame* m_ProgramLogBox;
|
||||
|
||||
std::vector<Semaphore*> m_PingWhenIdle;
|
||||
|
||||
public:
|
||||
Pcsx2App();
|
||||
virtual ~Pcsx2App();
|
||||
|
||||
void Ping();
|
||||
|
||||
void PostPadKey( wxKeyEvent& evt );
|
||||
void PostMenuAction( MenuIdentifiers menu_id ) const;
|
||||
int IssueModalDialog( const wxString& dlgName );
|
||||
|
@ -441,7 +445,8 @@ protected:
|
|||
bool TryOpenConfigCwd();
|
||||
void CleanupMess();
|
||||
void OpenWizardConsole();
|
||||
|
||||
void PingDispatch( const char* action );
|
||||
|
||||
void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event) const;
|
||||
void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event);
|
||||
|
||||
|
@ -456,6 +461,9 @@ protected:
|
|||
void OnMessageBox( pxMessageBoxEvent& evt );
|
||||
void OnEmuKeyDown( wxKeyEvent& evt );
|
||||
|
||||
void OnIdleEvent( wxIdleEvent& evt );
|
||||
void OnPingEvent( pxPingEvent& evt );
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Override wx default exception handling behavior
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -30,6 +30,7 @@ class GSFrame;
|
|||
class ConsoleLogFrame;
|
||||
class PipeRedirectionBase;
|
||||
class AppCoreThread;
|
||||
class pxPingEvent;
|
||||
|
||||
enum AppEventType
|
||||
{
|
||||
|
|
|
@ -261,6 +261,7 @@ bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser )
|
|||
}
|
||||
|
||||
typedef void (wxEvtHandler::*pxMessageBoxEventFunction)(pxMessageBoxEvent&);
|
||||
typedef void (wxEvtHandler::*pxPingEventFunction)(pxPingEvent&);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
bool Pcsx2App::OnInit()
|
||||
|
@ -268,6 +269,9 @@ bool Pcsx2App::OnInit()
|
|||
#define pxMessageBoxEventThing(func) \
|
||||
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxMessageBoxEventFunction, &func )
|
||||
|
||||
#define pxPingEventHandler(func) \
|
||||
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxPingEventFunction, &func )
|
||||
|
||||
Connect( pxEVT_MSGBOX, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) );
|
||||
Connect( pxEVT_ASSERTION, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) );
|
||||
Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
||||
|
@ -291,6 +295,9 @@ bool Pcsx2App::OnInit()
|
|||
Connect( pxEVT_CoreThreadStatus, wxCommandEventHandler( Pcsx2App::OnCoreThreadStatus ) );
|
||||
Connect( pxEVT_FreezeThreadFinished, wxCommandEventHandler( Pcsx2App::OnFreezeThreadFinished ) );
|
||||
|
||||
Connect( pxEVT_Ping, pxPingEventHandler( Pcsx2App::OnPingEvent ) );
|
||||
Connect( wxEVT_IDLE, wxIdleEventHandler( Pcsx2App::OnIdleEvent ) );
|
||||
|
||||
Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
|
||||
|
||||
// User/Admin Mode Dual Setup:
|
||||
|
@ -465,6 +472,8 @@ void Pcsx2App::CleanupMess()
|
|||
try
|
||||
{
|
||||
sys_resume_lock += 10;
|
||||
|
||||
PingDispatch( "Cleanup" );
|
||||
CoreThread.Cancel();
|
||||
|
||||
if( m_CorePlugins )
|
||||
|
|
|
@ -38,6 +38,7 @@ DEFINE_EVENT_TYPE( pxEVT_SysExecute );
|
|||
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
|
||||
DEFINE_EVENT_TYPE( pxEVT_CoreThreadStatus );
|
||||
DEFINE_EVENT_TYPE( pxEVT_FreezeThreadFinished );
|
||||
DEFINE_EVENT_TYPE( pxEVT_Ping );
|
||||
|
||||
#include "Utilities/EventSource.inl"
|
||||
EventSource_ImplementType( IniInterface );
|
||||
|
@ -83,6 +84,74 @@ void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const
|
|||
m_MainFrame->GetEventHandler()->AddPendingEvent( joe );
|
||||
}
|
||||
|
||||
class pxPingEvent : public wxEvent
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxPingEvent)
|
||||
|
||||
protected:
|
||||
Semaphore* m_PostBack;
|
||||
|
||||
public:
|
||||
virtual ~pxPingEvent() throw() { }
|
||||
virtual pxPingEvent *Clone() const { return new pxPingEvent(*this); }
|
||||
|
||||
explicit pxPingEvent( int msgtype, Semaphore* sema=NULL )
|
||||
: wxEvent( 0, msgtype )
|
||||
{
|
||||
m_PostBack = sema;
|
||||
}
|
||||
|
||||
explicit pxPingEvent( Semaphore* sema=NULL )
|
||||
: wxEvent( 0, pxEVT_Ping )
|
||||
{
|
||||
m_PostBack = sema;
|
||||
}
|
||||
|
||||
pxPingEvent( const pxPingEvent& src )
|
||||
: wxEvent( src )
|
||||
{
|
||||
m_PostBack = src.m_PostBack;
|
||||
}
|
||||
|
||||
Semaphore* GetSemaphore() { return m_PostBack; }
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS( pxPingEvent, wxEvent )
|
||||
|
||||
void Pcsx2App::OnPingEvent( pxPingEvent& evt )
|
||||
{
|
||||
m_PingWhenIdle.push_back( evt.GetSemaphore() );
|
||||
}
|
||||
|
||||
void Pcsx2App::PingDispatch( const char* action )
|
||||
{
|
||||
size_t size = m_PingWhenIdle.size();
|
||||
if( size == 0 ) return;
|
||||
|
||||
DbgCon.WriteLn( Color_Gray, "App Event Ping (%s) -> %u listeners.", action, size );
|
||||
|
||||
for( size_t i=0; i<size; ++i )
|
||||
{
|
||||
if( Semaphore* sema = m_PingWhenIdle[i] ) sema->Post();
|
||||
}
|
||||
|
||||
m_PingWhenIdle.clear();
|
||||
}
|
||||
|
||||
void Pcsx2App::OnIdleEvent( wxIdleEvent& evt )
|
||||
{
|
||||
evt.Skip();
|
||||
PingDispatch( "Idle" );
|
||||
}
|
||||
|
||||
void Pcsx2App::Ping()
|
||||
{
|
||||
Semaphore sema;
|
||||
pxPingEvent evt( &sema );
|
||||
AddPendingEvent( evt );
|
||||
sema.WaitNoCancel();
|
||||
}
|
||||
|
||||
void Pcsx2App::PostPadKey( wxKeyEvent& evt )
|
||||
{
|
||||
// HACK: Legacy PAD plugins expect PCSX2 to ignore keyboard messages on the
|
||||
|
|
|
@ -402,9 +402,9 @@ void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
|
|||
else
|
||||
{
|
||||
// give gui thread time to repaint and handle other pending messages.
|
||||
// (those are prioritized lower than wxEvents, typically, which means we
|
||||
// can't post a ping event since it'll still just starve out paint msgs.)
|
||||
pxYieldToMain();
|
||||
|
||||
//pxYield( 1 );
|
||||
wxGetApp().Ping();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -672,18 +672,18 @@ void Panels::PluginSelectorPanel::EnumThread::ExecuteTaskInThread()
|
|||
{
|
||||
DevCon.WriteLn( "Plugin Enumeration Thread started..." );
|
||||
|
||||
YieldToMain();
|
||||
Sleep( 15 ); // give the window some time to paint.
|
||||
wxGetApp().Ping();
|
||||
Sleep( 2 );
|
||||
|
||||
for( int curidx=0; curidx < m_master.FileCount(); ++curidx )
|
||||
{
|
||||
DoNextPlugin( curidx );
|
||||
|
||||
// speed isn't critical here, but the pretty status bar sure is.
|
||||
// second try yield should give the status bars UI a "good" chance to refresh before we advance. :)
|
||||
// speed isn't critical here, but the pretty status bar sure is. Sleep off
|
||||
// some brief cycles to give the status bar time to refresh.
|
||||
|
||||
Sleep( 2 );
|
||||
|
||||
YieldToMain();
|
||||
YieldToMain();
|
||||
//Sleep(150); // uncomment this to slow down the selector, for debugging threading.
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ LoadPluginsTask::~LoadPluginsTask() throw()
|
|||
|
||||
void LoadPluginsTask::ExecuteTaskInThread()
|
||||
{
|
||||
pxYieldToMain();
|
||||
wxGetApp().Ping();
|
||||
|
||||
// This is for testing of the error handler... uncomment for fun?
|
||||
//throw Exception::PluginError( PluginId_PAD, "This one is for testing the error handler!" );
|
||||
|
|
Loading…
Reference in New Issue