From e3962aa794db98a1c60e4ac5711350aebafc4169 Mon Sep 17 00:00:00 2001 From: isJuhn Date: Tue, 24 Jan 2023 20:28:03 +0100 Subject: [PATCH] PINE: Update to the age of Qt --- pcsx2-qt/Settings/AdvancedSettingsWidget.cpp | 3 + pcsx2-qt/Settings/AdvancedSettingsWidget.ui | 43 +++- pcsx2/CommonHost.cpp | 27 +- pcsx2/CommonHost.h | 3 + pcsx2/Config.h | 2 + pcsx2/Elfheader.cpp | 2 + pcsx2/Elfheader.h | 1 + pcsx2/PINE.cpp | 250 +++++++++---------- pcsx2/PINE.h | 66 +++-- pcsx2/Pcsx2Config.cpp | 5 +- 10 files changed, 234 insertions(+), 168 deletions(-) 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);