diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp
index 5cf04952dc..1d676a3637 100644
--- a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp
+++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp
@@ -67,6 +67,9 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.ntscFrameRate, "EmuCore/GS", "FramerateNTSC", 59.94f);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.palFrameRate, "EmuCore/GS", "FrameratePAL", 50.00f);
+ SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pineEnable, "EmuCore", "EnablePINE", false);
+ SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.pineSlot, "EmuCore", "PINESlot", 28011);
+
dialog->registerWidgetHelp(m_ui.eeRoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
dialog->registerWidgetHelp(m_ui.eeClampMode, tr("Clamping Mode"), tr("Normal (Default)"), tr(""));
diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui
index ff46be9e7d..67717592fb 100644
--- a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui
+++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui
@@ -7,7 +7,7 @@
0
0
809
- 647
+ 725
@@ -37,7 +37,7 @@
0
0
807
- 645
+ 723
@@ -417,6 +417,45 @@
+ -
+
+
+ PINE Settings
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Slot:
+
+
+
+ -
+
+
+ Enable
+
+
+
+
+
+
-
diff --git a/pcsx2/CommonHost.cpp b/pcsx2/CommonHost.cpp
index 894be30aa6..429f701f35 100644
--- a/pcsx2/CommonHost.cpp
+++ b/pcsx2/CommonHost.cpp
@@ -31,6 +31,7 @@
#include "PerformanceMetrics.h"
#include "Sio.h"
#include "VMManager.h"
+#include "PINE.h"
#include "common/Assertions.h"
#include "common/CrashHandler.h"
@@ -77,6 +78,8 @@ static std::string s_session_serial;
static bool s_screensaver_inhibited = false;
+static PINEServer s_pine_server;
+
#ifdef ENABLE_DISCORD_PRESENCE
static bool s_discord_presence_active = false;
#endif
@@ -272,6 +275,8 @@ void CommonHost::CPUThreadInitialize()
if (EmuConfig.EnableDiscordPresence)
InitializeDiscordPresence();
#endif
+
+ ReloadPINE();
}
void CommonHost::CPUThreadShutdown()
@@ -284,6 +289,8 @@ void CommonHost::CPUThreadShutdown()
Achievements::Shutdown();
#endif
+ s_pine_server.Deinitialize();
+
InputManager::CloseSources();
VMManager::WaitForSaveStateFlush();
VMManager::Internal::ReleaseMemory();
@@ -379,6 +386,8 @@ void CommonHost::OnGameChanged(const std::string& disc_path, const std::string&
#ifdef ENABLE_DISCORD_PRESENCE
UpdateDiscordPresence(GetRichPresenceString());
#endif
+
+ ReloadPINE();
}
void CommonHost::CPUThreadVSync()
@@ -539,4 +548,20 @@ std::string CommonHost::GetRichPresenceString()
return rich_presence_string;
}
-#endif
\ No newline at end of file
+#endif
+
+void CommonHost::ReloadPINE()
+{
+ if (EmuConfig.EnablePINE && (s_pine_server.m_slot != EmuConfig.PINESlot || s_pine_server.m_end))
+ {
+ if (!s_pine_server.m_end)
+ {
+ s_pine_server.Deinitialize();
+ }
+ s_pine_server.Initialize(EmuConfig.PINESlot);
+ }
+ else if ((!EmuConfig.EnablePINE && !s_pine_server.m_end))
+ {
+ s_pine_server.Deinitialize();
+ }
+}
diff --git a/pcsx2/CommonHost.h b/pcsx2/CommonHost.h
index 46143f11d7..0c340571e1 100644
--- a/pcsx2/CommonHost.h
+++ b/pcsx2/CommonHost.h
@@ -85,6 +85,9 @@ namespace CommonHost
void UpdateDiscordPresence(const std::string& rich_presence);
#endif
+ /// Reloads PINE IPC Server if needed. Does nothing if it's already running on the correct port.
+ void ReloadPINE();
+
namespace Internal
{
/// Resets any state for hotkey-related VMs, called on VM startup.
diff --git a/pcsx2/Config.h b/pcsx2/Config.h
index c493ecddc0..21b7d2d7bf 100644
--- a/pcsx2/Config.h
+++ b/pcsx2/Config.h
@@ -1293,6 +1293,8 @@ struct Pcsx2Config
McdOptions Mcd[8];
std::string GzipIsoIndexTemplate; // for quick-access index with gzipped ISO
+ int PINESlot;
+
// Set at runtime, not loaded from config.
std::string CurrentBlockdump;
std::string CurrentIRX;
diff --git a/pcsx2/Elfheader.cpp b/pcsx2/Elfheader.cpp
index 2b1663badf..3f71c357a2 100644
--- a/pcsx2/Elfheader.cpp
+++ b/pcsx2/Elfheader.cpp
@@ -27,6 +27,7 @@ u32 ElfEntry;
std::pair ElfTextRange;
std::string LastELF;
bool isPSXElf;
+std::string ElfVersion;
// All of ElfObjects functions.
ElfObject::ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf)
@@ -365,6 +366,7 @@ int GetPS2ElfName( std::string& name )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Software version = %.*s",
static_cast(value.size()), value.data());
+ ElfVersion = value;
}
}
diff --git a/pcsx2/Elfheader.h b/pcsx2/Elfheader.h
index 6b08001582..26237372f5 100644
--- a/pcsx2/Elfheader.h
+++ b/pcsx2/Elfheader.h
@@ -163,3 +163,4 @@ extern u32 ElfEntry;
extern std::pair ElfTextRange;
extern std::string LastELF;
extern bool isPSXElf;
+extern std::string ElfVersion;
diff --git a/pcsx2/PINE.cpp b/pcsx2/PINE.cpp
index fbea8dbea6..44659638f0 100644
--- a/pcsx2/PINE.cpp
+++ b/pcsx2/PINE.cpp
@@ -15,15 +15,12 @@
#include "PrecompiledHeader.h"
-#ifdef PCSX2_LEFTOVER_FROM_WX
-
#include
#include
-#include
#include
#if _WIN32
-#define read_portable(a, b, c) (recv(a, b, c, 0))
-#define write_portable(a, b, c) (send(a, b, c, 0))
+#define read_portable(a, b, c) (recv(a, (char*)b, c, 0))
+#define write_portable(a, b, c) (send(a, (const char*)b, c, 0))
#define close_portable(a) (closesocket(a))
#define bzero(b, len) (memset((b), '\0', (len)), (void)0)
#include
@@ -34,35 +31,44 @@
#define close_portable(a) (close(a))
#include
#include
+#include
#endif
#include "Common.h"
#include "Memory.h"
-#include "gui/AppSaveStates.h"
-#include "gui/AppCoreThread.h"
-#include "gui/SysThreads.h"
+#include "Elfheader.h"
+#include "pcsx2/VMManager.h"
#include "svnrev.h"
#include "PINE.h"
-PINEServer::PINEServer(SysCoreThread* vm, unsigned int slot)
- : pxThread("PINE_Server")
+PINEServer::PINEServer() {}
+
+PINEServer::~PINEServer()
{
+ Deinitialize();
+}
+
+bool PINEServer::Initialize(int slot)
+{
+ m_end.store(false, std::memory_order_release);
+ m_slot = slot;
#ifdef _WIN32
WSADATA wsa;
struct sockaddr_in server;
-
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
Console.WriteLn(Color_Red, "PINE: Cannot initialize winsock! Shutting down...");
- return;
+ Deinitialize();
+ return false;
}
m_sock = socket(AF_INET, SOCK_STREAM, 0);
if ((m_sock == INVALID_SOCKET) || slot > 65536)
{
Console.WriteLn(Color_Red, "PINE: Cannot open socket! Shutting down...");
- return;
+ Deinitialize();
+ return false;
}
// yes very good windows s/sun/sin/g sure is fine
@@ -74,7 +80,8 @@ PINEServer::PINEServer(SysCoreThread* vm, unsigned int slot)
if (bind(m_sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
Console.WriteLn(Color_Red, "PINE: Error while binding to socket! Shutting down...");
- return;
+ Deinitialize();
+ return false;
}
#else
@@ -103,7 +110,8 @@ PINEServer::PINEServer(SysCoreThread* vm, unsigned int slot)
if (m_sock < 0)
{
Console.WriteLn(Color_Red, "PINE: Cannot open socket! Shutting down...");
- return;
+ Deinitialize();
+ return false;
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, m_socket_name.c_str());
@@ -114,32 +122,42 @@ PINEServer::PINEServer(SysCoreThread* vm, unsigned int slot)
if (bind(m_sock, (struct sockaddr*)&server, sizeof(struct sockaddr_un)))
{
Console.WriteLn(Color_Red, "PINE: Error while binding to socket! Shutting down...");
- return;
+ Deinitialize();
+ return false;
}
#endif
// maximum queue of 4096 commands before refusing, approximated to the
// nearest legal value. We do not use SOMAXCONN as windows have this idea
// that a "reasonable" value is 5, which is not.
- listen(m_sock, 4096);
+ if (listen(m_sock, 4096))
+ {
+ Console.WriteLn(Color_Red, "PINE: Cannot listen for connections! Shutting down...");
+ Deinitialize();
+ return false;
+ }
- // we save a handle of the main vm object
- m_vm = vm;
+ // we allocate once buffers to not have to do mallocs for each IPC
+ // request, as malloc is expansive when we optimize for µs.
+ m_ret_buffer.resize(MAX_IPC_RETURN_SIZE);
+ m_ipc_buffer.resize(MAX_IPC_SIZE);
// we start the thread
- Start();
+ m_thread = std::thread(&PINEServer::MainLoop, this);
+
+ return true;
}
-char* PINEServer::MakeOkIPC(char* ret_buffer, uint32_t size = 5)
+std::vector& PINEServer::MakeOkIPC(std::vector& ret_buffer, uint32_t size = 5)
{
- ToArray(ret_buffer, size, 0);
+ ToResultVector(ret_buffer, size, 0);
ret_buffer[4] = IPC_OK;
return ret_buffer;
}
-char* PINEServer::MakeFailIPC(char* ret_buffer, uint32_t size = 5)
+std::vector& PINEServer::MakeFailIPC(std::vector& ret_buffer, uint32_t size = 5)
{
- ToArray(ret_buffer, size, 0);
+ ToResultVector(ret_buffer, size, 0);
ret_buffer[4] = IPC_FAIL;
return ret_buffer;
}
@@ -170,30 +188,24 @@ int PINEServer::StartSocket()
return 0;
}
-void PINEServer::ExecuteTaskInThread()
+void PINEServer::MainLoop()
{
- m_end = false;
-
- // we allocate once buffers to not have to do mallocs for each IPC
- // request, as malloc is expansive when we optimize for µs.
- m_ret_buffer = new char[MAX_IPC_RETURN_SIZE];
- m_ipc_buffer = new char[MAX_IPC_SIZE];
-
if (StartSocket() < 0)
return;
- while (true)
+ while (!m_end.load(std::memory_order_acquire))
{
// either int or ssize_t depending on the platform, so we have to
// use a bunch of auto
auto receive_length = 0;
auto end_length = 4;
+ const gsl::span ipc_buffer_span = gsl::make_span(m_ipc_buffer);
// while we haven't received the entire packet, maybe due to
// socket datagram splittage, we continue to read
while (receive_length < end_length)
{
- auto tmp_length = read_portable(m_msgsock, &m_ipc_buffer[receive_length], MAX_IPC_SIZE - receive_length);
+ const auto tmp_length = read_portable(m_msgsock, &ipc_buffer_span[receive_length], MAX_IPC_SIZE - receive_length);
// we recreate the socket if an error happens
if (tmp_length <= 0)
@@ -209,7 +221,7 @@ void PINEServer::ExecuteTaskInThread()
// if we got at least the final size then update
if (end_length == 4 && receive_length >= 4)
{
- end_length = FromArray(m_ipc_buffer, 0);
+ end_length = FromSpan(ipc_buffer_span, 0);
// we'd like to avoid a client trying to do OOB
if (end_length > MAX_IPC_SIZE || end_length < 4)
{
@@ -227,10 +239,10 @@ void PINEServer::ExecuteTaskInThread()
// disconnects
if (receive_length != 0)
{
- res = ParseCommand(&m_ipc_buffer[4], m_ret_buffer, (u32)end_length - 4);
+ res = ParseCommand(ipc_buffer_span.subspan(4), m_ret_buffer, (u32)end_length - 4);
// if we cannot send back our answer restart the socket
- if (write_portable(m_msgsock, res.buffer, res.size) < 0)
+ if (write_portable(m_msgsock, res.buffer.data(), res.size) < 0)
{
if (StartSocket() < 0)
return;
@@ -240,9 +252,10 @@ void PINEServer::ExecuteTaskInThread()
return;
}
-PINEServer::~PINEServer()
+void PINEServer::Deinitialize()
{
- m_end = true;
+ m_end.store(true, std::memory_order_release);
+
#ifdef _WIN32
WSACleanup();
#else
@@ -250,17 +263,14 @@ PINEServer::~PINEServer()
#endif
close_portable(m_sock);
close_portable(m_msgsock);
- delete[] m_ret_buffer;
- delete[] m_ipc_buffer;
- // destroy the thread
- try
+
+ if (m_thread.joinable())
{
- pxThread::Cancel();
+ m_thread.join();
}
- DESTRUCTOR_CATCHALL
}
-PINEServer::IPCBuffer PINEServer::ParseCommand(char* buf, char* ret_buffer, u32 buf_size)
+PINEServer::IPCBuffer PINEServer::ParseCommand(gsl::span buf, std::vector& ret_buffer, u32 buf_size)
{
u32 ret_cnt = 5;
u32 buf_cnt = 0;
@@ -285,211 +295,197 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(char* buf, char* ret_buffer, u32
{
case MsgRead8:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 1, buf_size))
goto error;
- const u32 a = FromArray(&buf[buf_cnt], 0);
+ const u32 a = FromSpan(buf, buf_cnt);
const u8 res = memRead8(a);
- ToArray(ret_buffer, res, ret_cnt);
+ ToResultVector(ret_buffer, res, ret_cnt);
ret_cnt += 1;
buf_cnt += 4;
break;
}
case MsgRead16:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 2, buf_size))
goto error;
- const u32 a = FromArray(&buf[buf_cnt], 0);
+ const u32 a = FromSpan(buf, buf_cnt);
const u16 res = memRead16(a);
- ToArray(ret_buffer, res, ret_cnt);
+ ToResultVector(ret_buffer, res, ret_cnt);
ret_cnt += 2;
buf_cnt += 4;
break;
}
case MsgRead32:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 4, buf_size))
goto error;
- const u32 a = FromArray(&buf[buf_cnt], 0);
+ const u32 a = FromSpan(buf, buf_cnt);
const u32 res = memRead32(a);
- ToArray(ret_buffer, res, ret_cnt);
+ ToResultVector(ret_buffer, res, ret_cnt);
ret_cnt += 4;
buf_cnt += 4;
break;
}
case MsgRead64:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 8, buf_size))
goto error;
- const u32 a = FromArray(&buf[buf_cnt], 0);
+ const u32 a = FromSpan(buf, buf_cnt);
const u64 res = memRead64(a);
- ToArray(ret_buffer, res, ret_cnt);
+ ToResultVector(ret_buffer, res, ret_cnt);
ret_cnt += 8;
buf_cnt += 4;
break;
}
case MsgWrite8:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 1 + 4, ret_cnt, 0, buf_size))
goto error;
- const u32 a = FromArray(&buf[buf_cnt], 0);
- memWrite8(a, FromArray(&buf[buf_cnt], 4));
+ const u32 a = FromSpan(buf, buf_cnt);
+ memWrite8(a, FromSpan(buf, buf_cnt + 4));
buf_cnt += 5;
break;
}
case MsgWrite16:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 2 + 4, ret_cnt, 0, buf_size))
goto error;
- const u32 a = FromArray(&buf[buf_cnt], 0);
- memWrite16(a, FromArray(&buf[buf_cnt], 4));
+ const u32 a = FromSpan(buf, buf_cnt);
+ memWrite16(a, FromSpan(buf, buf_cnt + 4));
buf_cnt += 6;
break;
}
case MsgWrite32:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 4 + 4, ret_cnt, 0, buf_size))
goto error;
- const u32 a = FromArray(&buf[buf_cnt], 0);
- memWrite32(a, FromArray(&buf[buf_cnt], 4));
+ const u32 a = FromSpan(buf, buf_cnt);
+ memWrite32(a, FromSpan(buf, buf_cnt + 4));
buf_cnt += 8;
break;
}
case MsgWrite64:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 8 + 4, ret_cnt, 0, buf_size))
goto error;
- const u32 a = FromArray(&buf[buf_cnt], 0);
- memWrite64(a, FromArray(&buf[buf_cnt], 4));
+ const u32 a = FromSpan(buf, buf_cnt);
+ memWrite64(a, FromSpan(buf, buf_cnt + 4));
buf_cnt += 12;
break;
}
case MsgVersion:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
- char version[256] = {};
+ std::string version;
if (GIT_TAGGED_COMMIT) // Nightly builds
{
// tagged commit - more modern implementation of dev build versioning
// - there is no need to include the commit - that is associated with the tag, git is implied
- sprintf(version, "PCSX2 Nightly - %s", GIT_TAG);
+ version = fmt::format("PCSX2 Nightly - {}", GIT_TAG);
}
else
{
- sprintf(version, "PCSX2 %u.%u.%u-%lld", PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo, SVN_REV);
+ version = fmt::format("PCSX2 {}.{}.{}-{}", PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo, SVN_REV);
}
- const u32 size = strlen(version) + 1;
- version[size] = 0x00;
+ const u32 size = version.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
- ToArray(ret_buffer, size, ret_cnt);
+ ToResultVector(ret_buffer, size, ret_cnt);
ret_cnt += 4;
- memcpy(&ret_buffer[ret_cnt], version, size);
+ memcpy(&ret_buffer[ret_cnt], version.c_str(), size);
ret_cnt += size;
break;
}
case MsgSaveState:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 1, ret_cnt, 0, buf_size))
goto error;
- StateCopy_SaveToSlot(FromArray(&buf[buf_cnt], 0));
+ VMManager::SaveStateToSlot(FromSpan(buf, buf_cnt));
buf_cnt += 1;
break;
}
case MsgLoadState:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
if (!SafetyChecks(buf_cnt, 1, ret_cnt, 0, buf_size))
goto error;
- StateCopy_LoadFromSlot(FromArray(&buf[buf_cnt], 0), false);
+ VMManager::LoadStateFromSlot(FromSpan(buf, buf_cnt));
buf_cnt += 1;
break;
}
case MsgTitle:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
- char* title = new char[GameInfo::gameName.size() + 1];
- sprintf(title, "%s", GameInfo::gameName.ToUTF8().data());
- const u32 size = strlen(title) + 1;
- title[size] = 0x00;
+ const std::string gameName = VMManager::GetGameName();
+ const u32 size = gameName.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
- ToArray(ret_buffer, size, ret_cnt);
+ ToResultVector(ret_buffer, size, ret_cnt);
ret_cnt += 4;
- memcpy(&ret_buffer[ret_cnt], title, size);
+ memcpy(&ret_buffer[ret_cnt], gameName.c_str(), size);
ret_cnt += size;
- delete[] title;
break;
}
case MsgID:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
- char* title = new char[GameInfo::gameSerial.size() + 1];
- sprintf(title, "%s", GameInfo::gameSerial.ToUTF8().data());
- const u32 size = strlen(title) + 1;
- title[size] = 0x00;
+ const std::string gameSerial = VMManager::GetGameSerial();
+ const u32 size = gameSerial.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
- ToArray(ret_buffer, size, ret_cnt);
+ ToResultVector(ret_buffer, size, ret_cnt);
ret_cnt += 4;
- memcpy(&ret_buffer[ret_cnt], title, size);
+ memcpy(&ret_buffer[ret_cnt], gameSerial.c_str(), size);
ret_cnt += size;
- delete[] title;
break;
}
case MsgUUID:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
- char* title = new char[GameInfo::gameCRC.size() + 1];
- sprintf(title, "%s", GameInfo::gameCRC.ToUTF8().data());
- const u32 size = strlen(title) + 1;
- title[size] = 0x00;
+ const std::string crc(fmt::format("{:08x}", VMManager::GetGameCRC()));
+ const u32 size = crc.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
- ToArray(ret_buffer, size, ret_cnt);
+ ToResultVector(ret_buffer, size, ret_cnt);
ret_cnt += 4;
- memcpy(&ret_buffer[ret_cnt], title, size);
+ memcpy(&ret_buffer[ret_cnt], crc.c_str(), size);
ret_cnt += size;
- delete[] title;
break;
}
case MsgGameVersion:
{
- if (!m_vm->HasActiveMachine())
+ if (!VMManager::HasValidVM())
goto error;
- char* title = new char[GameInfo::gameVersion.size() + 1];
- sprintf(title, "%s", GameInfo::gameVersion.ToUTF8().data());
- const u32 size = strlen(title) + 1;
- title[size] = 0x00;
+ const u32 size = ElfVersion.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
- ToArray(ret_buffer, size, ret_cnt);
+ ToResultVector(ret_buffer, size, ret_cnt);
ret_cnt += 4;
- memcpy(&ret_buffer[ret_cnt], title, size);
+ memcpy(&ret_buffer[ret_cnt], ElfVersion.c_str(), size);
ret_cnt += size;
- delete[] title;
break;
}
case MsgStatus:
@@ -497,18 +493,20 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(char* buf, char* ret_buffer, u32
if (!SafetyChecks(buf_cnt, 0, ret_cnt, 4, buf_size))
goto error;
EmuStatus status;
- if (m_vm->HasActiveMachine())
- {
- if (GetCoreThread().IsClosing())
- status = Paused;
- else
- status = Running;
+
+ switch (VMManager::GetState()) {
+ case VMState::Running:
+ status = EmuStatus::Running;
+ break;
+ case VMState::Paused:
+ status = EmuStatus::Paused;
+ break;
+ default:
+ status = EmuStatus::Shutdown;
+ break;
}
- else
- {
- status = Shutdown;
- }
- ToArray(ret_buffer, status, ret_cnt);
+
+ ToResultVector(ret_buffer, status, ret_cnt);
ret_cnt += 4;
break;
}
@@ -521,5 +519,3 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(char* buf, char* ret_buffer, u32
}
return IPCBuffer{(int)ret_cnt, MakeOkIPC(ret_buffer, ret_cnt)};
}
-
-#endif
\ No newline at end of file
diff --git a/pcsx2/PINE.h b/pcsx2/PINE.h
index 7a296a6178..f924b8136a 100644
--- a/pcsx2/PINE.h
+++ b/pcsx2/PINE.h
@@ -18,8 +18,6 @@
#pragma once
-#ifdef PCSX2_LEFTOVER_FROM_WX
-
// PINE uses a concept of "slot" to be able to communicate with multiple
// emulators at the same time, each slot should be unique to each emulator to
// allow PnP and configurable by the end user so that several runs don't
@@ -27,22 +25,20 @@
#define PINE_DEFAULT_SLOT 28011
#define PINE_EMULATOR_NAME "pcsx2"
-#include "gui/PersistentThread.h"
-#include "gui/SysThreads.h"
+#include
#include
+#include
+#include
+#include
#ifdef _WIN32
#include
#include
#endif
-using namespace Threading;
-class SysCoreThread;
-
-class PINEServer : public pxThread
+class PINEServer
{
- // parent thread
- typedef pxThread _parent;
+ std::thread m_thread;
protected:
#ifdef _WIN32
@@ -77,13 +73,13 @@ protected:
* A preallocated buffer used to store all IPC replies.
* to the size of 50.000 MsgWrite64 IPC calls.
*/
- char* m_ret_buffer;
+ std::vector m_ret_buffer{};
/**
* IPC messages buffer.
* A preallocated buffer used to store all IPC messages.
*/
- char* m_ipc_buffer;
+ std::vector m_ipc_buffer{};
/**
* IPC Command messages opcodes.
@@ -130,7 +126,7 @@ protected:
struct IPCBuffer
{
int size; /**< Size of the buffer. */
- char* buffer; /**< Buffer. */
+ std::vector buffer; /**< Buffer. */
};
/**
@@ -145,11 +141,8 @@ protected:
IPC_FAIL = 0xFF /**< IPC command failed to complete. */
};
- // handle to the main vm thread
- SysCoreThread* m_vm;
-
// Thread used to relay IPC commands.
- void ExecuteTaskInThread();
+ void MainLoop();
/**
* Internal function, Parses an IPC command.
@@ -159,7 +152,7 @@ protected:
* return value: IPCBuffer containing a buffer with the result
* of the command and its size.
*/
- IPCBuffer ParseCommand(char* buf, char* ret_buffer, u32 buf_size);
+ IPCBuffer ParseCommand(gsl::span buf, std::vector& ret_buffer, u32 buf_size);
/**
* Formats an IPC buffer
@@ -167,8 +160,8 @@ protected:
* size: size of the IPC buffer.
* return value: buffer containing the status code allocated of size
*/
- static inline char* MakeOkIPC(char* ret_buffer, uint32_t size);
- static inline char* MakeFailIPC(char* ret_buffer, uint32_t size);
+ static inline std::vector& MakeOkIPC(std::vector& ret_buffer, uint32_t size);
+ static inline std::vector& MakeFailIPC(std::vector& ret_buffer, uint32_t size);
/**
* Initializes an open socket for IPC communication.
@@ -177,31 +170,29 @@ protected:
int StartSocket();
/**
- * Converts an uint to an char* in little endian
- * res_array: the array to modify
+ * Converts a primitive value to bytes in little endian
+ * res_vector: the vector to modify
* res: the value to convert
- * i: when to insert it into the array
- * return value: res_array
+ * i: where to insert it into the vector
* NB: implicitely inlined
*/
template
- static char* ToArray(char* res_array, T res, int i)
+ static void ToResultVector(std::vector& res_vector, T res, int i)
{
- memcpy((res_array + i), (char*)&res, sizeof(T));
- return res_array;
+ memcpy(&res_vector[i], (char*)&res, sizeof(T));
}
/**
- * Converts a char* to an uint in little endian
- * arr: the array to convert
- * i: when to load it from the array
+ * Converts bytes in little endian to a primitive value
+ * span: the span to convert
+ * i: where to load it from the span
* return value: the converted value
* NB: implicitely inlined
*/
template
- static T FromArray(char* arr, int i)
+ static T FromSpan(gsl::span span, int i)
{
- return *(T*)(arr + i);
+ return *(T*)(&span[i]);
}
/**
@@ -210,7 +201,7 @@ protected:
*/
static inline bool SafetyChecks(u32 command_len, int command_size, u32 reply_len, int reply_size = 0, u32 buf_size = MAX_IPC_SIZE - 1)
{
- bool res = ((command_len + command_size) > buf_size ||
+ const bool res = ((command_len + command_size) > buf_size ||
(reply_len + reply_size) >= MAX_IPC_RETURN_SIZE);
if (unlikely(res))
return false;
@@ -219,12 +210,13 @@ protected:
public:
// Whether the socket processing thread should stop executing/is stopped.
- bool m_end = true;
+ std::atomic_bool m_end{ false };
+ int m_slot;
/* Initializers */
- PINEServer(SysCoreThread* vm, unsigned int slot = PINE_DEFAULT_SLOT);
+ PINEServer();
virtual ~PINEServer();
+ bool Initialize(int slot = PINE_DEFAULT_SLOT);
+ void Deinitialize();
}; // class SocketIPC
-
-#endif
diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp
index c25d534bfa..7a39aa3fdd 100644
--- a/pcsx2/Pcsx2Config.cpp
+++ b/pcsx2/Pcsx2Config.cpp
@@ -1318,6 +1318,7 @@ Pcsx2Config::Pcsx2Config()
}
GzipIsoIndexTemplate = "$(f).pindex.tmp";
+ PINESlot = 28011;
}
void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
@@ -1371,6 +1372,7 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
#endif
SettingsWrapEntry(GzipIsoIndexTemplate);
+ SettingsWrapEntry(PINESlot);
// For now, this in the derived config for backwards ini compatibility.
SettingsWrapEntryEx(CurrentBlockdump, "BlockDumpSaveDirectory");
@@ -1446,7 +1448,8 @@ bool Pcsx2Config::operator==(const Pcsx2Config& right) const
OpEqu(Framerate) &&
OpEqu(Trace) &&
OpEqu(BaseFilenames) &&
- OpEqu(GzipIsoIndexTemplate);
+ OpEqu(GzipIsoIndexTemplate) &&
+ OpEqu(PINESlot);
for (u32 i = 0; i < sizeof(Mcd) / sizeof(Mcd[0]); i++)
{
equal &= OpEqu(Mcd[i].Enabled);