mirror of https://github.com/PCSX2/pcsx2.git
270 lines
8.8 KiB
C++
270 lines
8.8 KiB
C++
/* 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 "System.h"
|
|
|
|
#include "Utilities/PersistentThread.h"
|
|
#include "x86emitter/tools.h"
|
|
#include "IPC.h"
|
|
|
|
|
|
using namespace Threading;
|
|
|
|
typedef SafeArray<u8> VmStateBuffer;
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// SysThreadBase
|
|
// --------------------------------------------------------------------------------------
|
|
|
|
class SysThreadBase : public pxThread
|
|
{
|
|
typedef pxThread _parent;
|
|
|
|
public:
|
|
// Important: The order of these enumerations matters! Optimized tests are used for both
|
|
// Closed and Paused states.
|
|
enum ExecutionMode
|
|
{
|
|
// Thread has not been created yet. Typically this is the same as IsRunning()
|
|
// returning FALSE.
|
|
ExecMode_NoThreadYet,
|
|
|
|
// Thread is safely paused, with plugins in a "closed" state, and waiting for a
|
|
// resume/open signal.
|
|
ExecMode_Closed,
|
|
|
|
// Thread is safely paused, with plugins in an "open" state, and waiting for a
|
|
// resume/open signal.
|
|
ExecMode_Paused,
|
|
|
|
// Thread is active and running, with pluigns in an "open" state.
|
|
ExecMode_Opened,
|
|
|
|
// Close signal has been sent to the thread, but the thread's response is still
|
|
// pending (thread is busy/running).
|
|
ExecMode_Closing,
|
|
|
|
// Pause signal has been sent to the thread, but the thread's response is still
|
|
// pending (thread is busy/running).
|
|
ExecMode_Pausing,
|
|
};
|
|
|
|
protected:
|
|
std::atomic<ExecutionMode> m_ExecMode;
|
|
|
|
// This lock is used to avoid simultaneous requests to Suspend/Resume/Pause from
|
|
// contending threads.
|
|
MutexRecursive m_ExecModeMutex;
|
|
|
|
// Used to wake up the thread from sleeping when it's in a suspended state.
|
|
Semaphore m_sem_Resume;
|
|
|
|
// Used to synchronize inline changes from paused to suspended status.
|
|
Semaphore m_sem_ChangingExecMode;
|
|
|
|
// Locked whenever the thread is not in a suspended state (either closed or paused).
|
|
// Issue a Wait against this mutex for performing actions that require the thread
|
|
// to be suspended.
|
|
Mutex m_RunningLock;
|
|
|
|
public:
|
|
explicit SysThreadBase();
|
|
virtual ~SysThreadBase() = default;
|
|
|
|
// Thread safety for IsOpen / IsClosed: The execution mode can change at any time on
|
|
// any thread, so the actual status may have already changed by the time this function
|
|
// returns its result. Typically this isn't of major concern. However if you need
|
|
// more assured execution mode status, issue a lock against the ExecutionModeMutex()
|
|
// first.
|
|
bool IsOpen() const
|
|
{
|
|
return IsRunning() && (m_ExecMode > ExecMode_Closed);
|
|
}
|
|
|
|
bool IsClosed() const { return !IsOpen(); }
|
|
bool IsPaused() const { return !IsRunning() || (m_ExecMode <= ExecMode_Paused); }
|
|
|
|
bool IsClosing() const
|
|
{
|
|
return !IsRunning() || (m_ExecMode <= ExecMode_Closed) || (m_ExecMode == ExecMode_Closing);
|
|
}
|
|
|
|
bool HasPendingStateChangeRequest() const
|
|
{
|
|
return m_ExecMode >= ExecMode_Closing;
|
|
}
|
|
|
|
ExecutionMode GetExecutionMode() const { return m_ExecMode.load(); }
|
|
Mutex& ExecutionModeMutex() { return m_ExecModeMutex; }
|
|
|
|
virtual void Suspend( bool isBlocking = true );
|
|
virtual void Resume();
|
|
virtual void Pause(bool debug = false);
|
|
virtual void PauseSelf();
|
|
virtual void PauseSelfDebug();
|
|
|
|
protected:
|
|
virtual void OnStart();
|
|
|
|
// This function is called by Resume immediately prior to releasing the suspension of
|
|
// the core emulation thread. You should overload this rather than Resume(), since
|
|
// Resume() has a lot of checks and balances to prevent re-entrance and race conditions.
|
|
virtual void OnResumeReady() {}
|
|
virtual void OnPause() {}
|
|
virtual void OnPauseDebug() {}
|
|
|
|
virtual bool StateCheckInThread();
|
|
virtual void OnCleanupInThread();
|
|
virtual void OnStartInThread();
|
|
|
|
// Used internally from Resume(), so let's make it private here.
|
|
virtual void Start();
|
|
|
|
// Extending classes should implement this, but should not call it. The parent class
|
|
// handles invocation by the following guidelines: Called *in thread* from StateCheckInThread()
|
|
// prior to suspending the thread (ie, when Suspend() has been called on a separate
|
|
// thread, requesting this thread suspend itself temporarily). After this is called,
|
|
// the thread enters a waiting state on the m_sem_Resume 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 StateCheckInThread()
|
|
// 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_sem_Resume 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 StateCheckInThread() after the
|
|
// thread has been suspended and then subsequently resumed.
|
|
// 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;
|
|
};
|
|
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// SysCoreThread class
|
|
// --------------------------------------------------------------------------------------
|
|
class SysCoreThread : public SysThreadBase
|
|
{
|
|
typedef SysThreadBase _parent;
|
|
|
|
protected:
|
|
bool m_resetRecompilers;
|
|
bool m_resetProfilers;
|
|
bool m_resetVsyncTimers;
|
|
bool m_resetVirtualMachine;
|
|
|
|
// Stores the state of the socket IPC thread.
|
|
std::unique_ptr<SocketIPC> m_socketIpc;
|
|
|
|
// Current state of the IPC thread
|
|
enum StateIPC
|
|
{
|
|
OFF,
|
|
ON
|
|
};
|
|
StateIPC m_IpcState = OFF;
|
|
|
|
// Indicates if the system has an active virtual machine state. Pretty much always
|
|
// true anytime between plugins being initialized and plugins being shutdown. Gets
|
|
// set false when plugins are shutdown, the corethread is canceled, or when an error
|
|
// occurs while trying to upload a new state into the VM.
|
|
std::atomic<bool> m_hasActiveMachine;
|
|
|
|
wxString m_elf_override;
|
|
|
|
SSE_MXCSR m_mxcsr_saved;
|
|
|
|
public:
|
|
explicit SysCoreThread();
|
|
virtual ~SysCoreThread();
|
|
|
|
bool HasPendingStateChangeRequest() const;
|
|
|
|
virtual void OnResumeReady();
|
|
virtual void Reset();
|
|
virtual void ResetQuick();
|
|
virtual void Cancel( bool isBlocking=true );
|
|
virtual bool Cancel( const wxTimeSpan& timeout );
|
|
|
|
virtual bool StateCheckInThread();
|
|
virtual void VsyncInThread();
|
|
virtual void GameStartingInThread();
|
|
|
|
virtual void ApplySettings( const Pcsx2Config& src );
|
|
virtual void UploadStateCopy( const VmStateBuffer& copy );
|
|
|
|
virtual bool HasActiveMachine() const { return m_hasActiveMachine; }
|
|
|
|
virtual const wxString& GetElfOverride() const { return m_elf_override; }
|
|
virtual void SetElfOverride( const wxString& elf );
|
|
|
|
protected:
|
|
void _reset_stuff_as_needed();
|
|
|
|
virtual void Start();
|
|
virtual void OnStart();
|
|
virtual void OnSuspendInThread();
|
|
virtual void OnPauseInThread() {}
|
|
virtual void OnResumeInThread( bool IsSuspended );
|
|
virtual void OnCleanupInThread();
|
|
virtual void ExecuteTaskInThread();
|
|
virtual void DoCpuReset();
|
|
virtual void DoCpuExecute();
|
|
|
|
void _StateCheckThrows();
|
|
};
|
|
|
|
|
|
struct SysStateUnlockedParams
|
|
{
|
|
SysStateUnlockedParams() {}
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// IEventListener_SaveStateThread
|
|
// --------------------------------------------------------------------------------------
|
|
class IEventListener_SysState : public IEventDispatcher<SysStateUnlockedParams>
|
|
{
|
|
public:
|
|
typedef SysStateUnlockedParams EvtParams;
|
|
|
|
public:
|
|
IEventListener_SysState() {}
|
|
virtual ~IEventListener_SysState() = default;
|
|
|
|
virtual void DispatchEvent( const SysStateUnlockedParams& status )
|
|
{
|
|
SysStateAction_OnUnlocked();
|
|
}
|
|
|
|
protected:
|
|
virtual void SysStateAction_OnUnlocked();
|
|
};
|
|
|
|
// GetCoreThread() is a required external implementation. This function is *NOT*
|
|
// provided by the PCSX2 core library. It provides an interface for the linking User
|
|
// Interface apps or DLLs to reference their own instance of SysCoreThread (also allowing
|
|
// them to extend the class and override virtual methods).
|
|
//
|
|
extern SysCoreThread& GetCoreThread();
|
|
|
|
extern bool g_CDVDReset;
|