From 015804c43447a74dd2b861609d161ff2d574a489 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Mon, 27 May 2024 00:10:39 +1000 Subject: [PATCH] System: Move GDB server into core --- dep/msvc/vsprops/QtCompile.props | 16 +- src/core/CMakeLists.txt | 4 +- src/core/core.vcxproj | 4 +- src/core/core.vcxproj.filters | 4 +- src/core/gdb_protocol.h | 13 -- src/core/{gdb_protocol.cpp => gdb_server.cpp} | 221 +++++++++++++++++- src/core/gdb_server.h | 14 ++ src/core/system.cpp | 30 ++- src/duckstation-qt/CMakeLists.txt | 8 +- src/duckstation-qt/duckstation-qt.vcxproj | 6 - .../duckstation-qt.vcxproj.filters | 10 - src/duckstation-qt/gdbconnection.cpp | 95 -------- src/duckstation-qt/gdbconnection.h | 29 --- src/duckstation-qt/gdbserver.cpp | 52 ----- src/duckstation-qt/gdbserver.h | 23 -- src/duckstation-qt/mainwindow.cpp | 10 - src/duckstation-qt/qthost.cpp | 18 +- src/duckstation-qt/qthost.h | 2 - src/util/sockets.cpp | 19 ++ src/util/sockets.h | 3 +- 20 files changed, 307 insertions(+), 274 deletions(-) delete mode 100644 src/core/gdb_protocol.h rename src/core/{gdb_protocol.cpp => gdb_server.cpp} (59%) create mode 100644 src/core/gdb_server.h delete mode 100644 src/duckstation-qt/gdbconnection.cpp delete mode 100644 src/duckstation-qt/gdbconnection.h delete mode 100644 src/duckstation-qt/gdbserver.cpp delete mode 100644 src/duckstation-qt/gdbserver.h diff --git a/dep/msvc/vsprops/QtCompile.props b/dep/msvc/vsprops/QtCompile.props index 280d1a9e3..ccdd91241 100644 --- a/dep/msvc/vsprops/QtCompile.props +++ b/dep/msvc/vsprops/QtCompile.props @@ -32,7 +32,7 @@ $(QtLibDir);%(AdditionalLibraryDirectories) - Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Network$(QtLibSuffix).lib;Qt6Concurrent$(QtLibSuffix).lib;%(AdditionalDependencies) + Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Concurrent$(QtLibSuffix).lib;%(AdditionalDependencies) @@ -118,24 +118,21 @@ - + - - - $(BinaryOutputDir)qt.conf + Inputs="@(QtDlls);@(QtPlugins)" + Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPluginsDest)"> - + @@ -51,7 +52,6 @@ - @@ -122,6 +122,7 @@ + @@ -131,7 +132,6 @@ - diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 3dc3f95a1..b02bcfd85 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -6,7 +6,6 @@ - @@ -68,6 +67,7 @@ + @@ -120,7 +120,6 @@ - @@ -142,5 +141,6 @@ + \ No newline at end of file diff --git a/src/core/gdb_protocol.h b/src/core/gdb_protocol.h deleted file mode 100644 index d0cc1fc2f..000000000 --- a/src/core/gdb_protocol.h +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin and contributors. -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once -#include - -namespace GDBProtocol { -bool IsPacketInterrupt(std::string_view data); -bool IsPacketContinue(std::string_view data); - -bool IsPacketComplete(std::string_view data); -std::string ProcessPacket(std::string_view data); -} // namespace GDBProtocol diff --git a/src/core/gdb_protocol.cpp b/src/core/gdb_server.cpp similarity index 59% rename from src/core/gdb_protocol.cpp rename to src/core/gdb_server.cpp index 8e79bfcd9..50dbf3e73 100644 --- a/src/core/gdb_protocol.cpp +++ b/src/core/gdb_server.cpp @@ -1,7 +1,7 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin and contributors. +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin and contributors. // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) -#include "gdb_protocol.h" +#include "gdb_server.h" #include "bus.h" #include "cpu_core.h" #include "cpu_core_private.h" @@ -11,6 +11,8 @@ #include "common/small_string.h" #include "common/string_util.h" +#include "util/sockets.h" + #include #include #include @@ -20,6 +22,14 @@ Log_SetChannel(GDBProtocol); +namespace GDBProtocol { +static bool IsPacketInterrupt(std::string_view data); +static bool IsPacketContinue(std::string_view data); + +static bool IsPacketComplete(std::string_view data); +static std::string ProcessPacket(std::string_view data); +} // namespace GDBProtocol + namespace GDBProtocol { static u8* GetMemoryPointer(PhysicalMemoryAddress address, u32 length) @@ -345,3 +355,210 @@ std::string ProcessPacket(std::string_view data) } } // namespace GDBProtocol + +namespace GDBServer { + +namespace { +class ClientSocket final : public BufferedStreamSocket +{ +public: + ClientSocket(SocketMultiplexer& multiplexer, SocketDescriptor descriptor); + ~ClientSocket() override; + + void OnSystemPaused(); + void OnSystemResumed(); + +protected: + void OnConnected() override; + void OnDisconnected(const Error& error) override; + void OnRead() override; + +private: + void SendPacket(std::string_view sv); + + bool m_seen_resume = false; +}; +} // namespace + +static std::shared_ptr s_gdb_listen_socket; +static std::vector> s_gdb_clients; +} // namespace GDBServer + +GDBServer::ClientSocket::ClientSocket(SocketMultiplexer& multiplexer, SocketDescriptor descriptor) + : BufferedStreamSocket(multiplexer, descriptor, 65536, 65536) +{ +} + +GDBServer::ClientSocket::~ClientSocket() = default; + +void GDBServer::ClientSocket::OnConnected() +{ + INFO_LOG("Client {} connected.", GetRemoteAddress().ToString()); + + m_seen_resume = System::IsPaused(); + System::PauseSystem(true); + + s_gdb_clients.push_back(std::static_pointer_cast(shared_from_this())); +} + +void GDBServer::ClientSocket::OnDisconnected(const Error& error) +{ + INFO_LOG("Client {} disconnected: {}", GetRemoteAddress().ToString(), error.GetDescription()); + + const auto iter = std::find_if(s_gdb_clients.begin(), s_gdb_clients.end(), + [this](const std::shared_ptr& rhs) { return (rhs.get() == this); }); + if (iter == s_gdb_clients.end()) + { + ERROR_LOG("Unknown GDB client disconnected? This should never happen."); + return; + } + + s_gdb_clients.erase(iter); +} + +void GDBServer::ClientSocket::OnRead() +{ + const std::span buffer = AcquireReadBuffer(); + if (buffer.empty()) + return; + + size_t buffer_offset = 0; + while (buffer_offset < buffer.size()) + { + size_t current_packet_size = 1; + bool packet_complete = false; + for (; (buffer_offset + current_packet_size) <= buffer.size(); current_packet_size++) + { + const std::string_view current_packet(reinterpret_cast(buffer.data() + buffer_offset), + current_packet_size); + + if (GDBProtocol::IsPacketInterrupt(current_packet)) + { + DEV_LOG("{} > Interrupt request", GetRemoteAddress().ToString()); + System::PauseSystem(true); + packet_complete = true; + break; + } + else if (GDBProtocol::IsPacketContinue(current_packet)) + { + DEV_LOG("{} > Continue request", GetRemoteAddress().ToString()); + System::PauseSystem(false); + packet_complete = true; + break; + } + else if (GDBProtocol::IsPacketComplete(current_packet)) + { + // TODO: Make this not copy. + DEV_LOG("{} > {}", GetRemoteAddress().ToString(), current_packet); + SendPacket(GDBProtocol::ProcessPacket(current_packet)); + packet_complete = true; + break; + } + } + + if (!packet_complete) + { + WARNING_LOG("Incomplete packet, got {} bytes.", buffer.size() - buffer_offset); + break; + } + else + { + buffer_offset += current_packet_size; + } + } + + ReleaseReadBuffer(buffer_offset); +} + +void GDBServer::ClientSocket::SendPacket(std::string_view sv) +{ + if (sv.empty()) + return; + + WARNING_LOG("Write: {}", sv); + if (size_t written = Write(sv.data(), sv.length()); written != sv.length()) + ERROR_LOG("Only wrote {} of {} bytes.", written, sv.length()); +} + +void GDBServer::ClientSocket::OnSystemPaused() +{ + if (!m_seen_resume) + return; + + m_seen_resume = false; + + // Generate a stop reply packet, insert '?' command to generate it. + SendPacket(GDBProtocol::ProcessPacket("$?#3f")); +} + +void GDBServer::ClientSocket::OnSystemResumed() +{ + m_seen_resume = true; + + // Send ack, in case GDB sent a continue request. + SendPacket("+"); +} + +bool GDBServer::Initialize(u16 port) +{ + Error error; + Assert(!s_gdb_listen_socket); + + const std::optional address = + SocketAddress::Parse(SocketAddress::Type::IPv4, "127.0.0.1", port, &error); + if (!address.has_value()) + { + ERROR_LOG("Failed to parse address: {}", error.GetDescription()); + return false; + } + + SocketMultiplexer* multiplexer = System::GetSocketMultiplexer(); + if (!multiplexer) + return false; + + s_gdb_listen_socket = multiplexer->CreateListenSocket(address.value(), &error); + if (!s_gdb_listen_socket) + { + ERROR_LOG("Failed to create listen socket: {}", error.GetDescription()); + System::ReleaseSocketMultiplexer(); + return false; + } + + INFO_LOG("GDB server is now listening on {}.", address->ToString()); + return true; +} + +bool GDBServer::HasAnyClients() +{ + return !s_gdb_clients.empty(); +} + +void GDBServer::Shutdown() +{ + if (!s_gdb_listen_socket) + return; + + INFO_LOG("Disconnecting {} GDB clients...", s_gdb_clients.size()); + while (!s_gdb_clients.empty()) + { + // maintain a reference so we don't delete while in scope + std::shared_ptr client = s_gdb_clients.back(); + client->Close(); + } + + INFO_LOG("Stopping GDB server."); + s_gdb_listen_socket.reset(); + System::ReleaseSocketMultiplexer(); +} + +void GDBServer::OnSystemPaused() +{ + for (auto& it : s_gdb_clients) + it->OnSystemPaused(); +} + +void GDBServer::OnSystemResumed() +{ + for (auto& it : s_gdb_clients) + it->OnSystemResumed(); +} diff --git a/src/core/gdb_server.h b/src/core/gdb_server.h new file mode 100644 index 000000000..6e80d4612 --- /dev/null +++ b/src/core/gdb_server.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin and contributors. +// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) + +#pragma once +#include + +namespace GDBServer { +bool Initialize(u16 port); +bool HasAnyClients(); +void Shutdown(); + +void OnSystemPaused(); +void OnSystemResumed(); +} // namespace GDBServer diff --git a/src/core/system.cpp b/src/core/system.cpp index 0873fd5c9..4a616ce93 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -82,8 +82,9 @@ Log_SetChannel(System); #ifndef __ANDROID__ #define ENABLE_PINE_SERVER 1 -// #define ENABLE_GDB_SERVER 1 +#define ENABLE_GDB_SERVER 1 #define ENABLE_SOCKET_MULTIPLEXER 1 +#include "gdb_server.h" #include "pine_server.h" #endif @@ -1289,6 +1290,10 @@ void System::PauseSystem(bool paused) if (g_settings.inhibit_screensaver) PlatformMisc::ResumeScreensaver(); +#ifdef ENABLE_GDB_SERVER + GDBServer::OnSystemPaused(); +#endif + Host::OnSystemPaused(); Host::OnIdleStateChanged(); UpdateDisplayVSync(); @@ -1303,6 +1308,10 @@ void System::PauseSystem(bool paused) if (g_settings.inhibit_screensaver) PlatformMisc::SuspendScreensaver(); +#ifdef ENABLE_GDB_SERVER + GDBServer::OnSystemResumed(); +#endif + Host::OnSystemResumed(); Host::OnIdleStateChanged(); @@ -1670,6 +1679,11 @@ bool System::BootSystem(SystemBootParameters parameters, Error* error) if (g_settings.inhibit_screensaver) PlatformMisc::SuspendScreensaver(); +#ifdef ENABLE_GDB_SERVER + if (g_settings.debugging.enable_gdb_server) + GDBServer::Initialize(g_settings.debugging.gdb_server_port); +#endif + Host::OnSystemStarted(); Host::OnIdleStateChanged(); @@ -1816,6 +1830,10 @@ void System::DestroySystem() if (s_state == State::Shutdown) return; +#ifdef ENABLE_GDB_SERVER + GDBServer::Shutdown(); +#endif + Host::ClearOSDMessages(); PostProcessing::Shutdown(); @@ -4072,6 +4090,16 @@ void System::CheckForSettingsChanges(const Settings& old_settings) } PostProcessing::UpdateSettings(); + +#ifdef ENABLE_GDB_SERVER + if (g_settings.debugging.enable_gdb_server != old_settings.debugging.enable_gdb_server || + g_settings.debugging.gdb_server_port != old_settings.debugging.gdb_server_port) + { + GDBServer::Shutdown(); + if (g_settings.debugging.enable_gdb_server) + GDBServer::Initialize(g_settings.debugging.gdb_server_port); + } +#endif } else { diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt index a3299895c..1c4306172 100644 --- a/src/duckstation-qt/CMakeLists.txt +++ b/src/duckstation-qt/CMakeLists.txt @@ -1,4 +1,4 @@ -find_package(Qt6 6.6.0 COMPONENTS Core Gui Widgets Network LinguistTools REQUIRED) +find_package(Qt6 6.7.0 COMPONENTS Core Gui Widgets LinguistTools REQUIRED) include(CopyBaseTranslations) @@ -96,10 +96,6 @@ set(SRCS gamesummarywidget.cpp gamesummarywidget.h gamesummarywidget.ui - gdbconnection.cpp - gdbconnection.h - gdbserver.cpp - gdbserver.h graphicssettingswidget.cpp graphicssettingswidget.h graphicssettingswidget.ui @@ -175,7 +171,7 @@ set(TS_FILES add_executable(duckstation-qt ${SRCS} ${QM_FILES}) target_precompile_headers(duckstation-qt PRIVATE "pch.h") target_include_directories(duckstation-qt PRIVATE "${Qt6Gui_PRIVATE_INCLUDE_DIRS}" "${CMAKE_CURRENT_SOURCE_DIR}") -target_link_libraries(duckstation-qt PRIVATE core common imgui minizip scmversion Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network) +target_link_libraries(duckstation-qt PRIVATE core common imgui minizip scmversion Qt6::Core Qt6::Gui Qt6::Widgets) # Our Qt builds may have exceptions on, so force them off. target_compile_definitions(duckstation-qt PRIVATE QT_NO_EXCEPTIONS) diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj index e1937c8ce..07e34f8ee 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj +++ b/src/duckstation-qt/duckstation-qt.vcxproj @@ -36,8 +36,6 @@ - - @@ -97,8 +95,6 @@ - - @@ -243,8 +239,6 @@ - - diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters index eb3b670ce..25961d409 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj.filters +++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters @@ -15,8 +15,6 @@ - - @@ -126,12 +124,6 @@ moc - - moc - - - moc - moc @@ -219,8 +211,6 @@ - - diff --git a/src/duckstation-qt/gdbconnection.cpp b/src/duckstation-qt/gdbconnection.cpp deleted file mode 100644 index cd7acc3e2..000000000 --- a/src/duckstation-qt/gdbconnection.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin and contributors. -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "gdbconnection.h" -#include "common/log.h" -#include "core/gdb_protocol.h" -#include "qthost.h" -Log_SetChannel(GDBConnection); - -GDBConnection::GDBConnection(GDBServer* parent, intptr_t descriptor) : QTcpSocket(parent), m_descriptor(descriptor) -{ - if (!setSocketDescriptor(descriptor)) - { - ERROR_LOG("{} failed to set socket descriptor: {}", descriptor, errorString().toStdString()); - deleteLater(); - return; - } - - connect(g_emu_thread, &EmuThread::systemPaused, this, &GDBConnection::onEmulationPaused); - connect(g_emu_thread, &EmuThread::systemResumed, this, &GDBConnection::onEmulationResumed); - connect(this, &QTcpSocket::readyRead, this, &GDBConnection::receivedData); - connect(this, &QTcpSocket::disconnected, this, &GDBConnection::gotDisconnected); - - INFO_LOG("{} client connected", m_descriptor); - - m_seen_resume = System::IsPaused(); - g_emu_thread->setSystemPaused(true); -} - -void GDBConnection::gotDisconnected() -{ - INFO_LOG("{} client disconnected", m_descriptor); - deleteLater(); -} - -void GDBConnection::receivedData() -{ - qint64 bytesRead; - char buffer[256]; - - while ((bytesRead = read(buffer, sizeof(buffer))) > 0) - { - for (char c : std::string_view(buffer, bytesRead)) - { - m_readBuffer.push_back(c); - - if (GDBProtocol::IsPacketInterrupt(m_readBuffer)) - { - DEBUG_LOG("{} > Interrupt request", m_descriptor); - g_emu_thread->setSystemPaused(true); - m_readBuffer.erase(); - } - else if (GDBProtocol::IsPacketContinue(m_readBuffer)) - { - DEBUG_LOG("{} > Continue request", m_descriptor); - g_emu_thread->setSystemPaused(false); - m_readBuffer.erase(); - } - else if (GDBProtocol::IsPacketComplete(m_readBuffer)) - { - DEBUG_LOG("{} > {}", m_descriptor, m_readBuffer); - writePacket(GDBProtocol::ProcessPacket(m_readBuffer)); - m_readBuffer.erase(); - } - } - } - if (bytesRead == -1) - { - ERROR_LOG("{} failed to read from socket: {}", m_descriptor, errorString().toStdString()); - } -} - -void GDBConnection::onEmulationPaused() -{ - if (m_seen_resume) - { - m_seen_resume = false; - // Generate a stop reply packet, insert '?' command to generate it. - writePacket(GDBProtocol::ProcessPacket("$?#3f")); - } -} - -void GDBConnection::onEmulationResumed() -{ - m_seen_resume = true; - // Send ack, in case GDB sent a continue request. - writePacket("+"); -} - -void GDBConnection::writePacket(std::string_view packet) -{ - DEBUG_LOG("{} < {}", m_descriptor, packet); - if (write(packet.data(), packet.length()) == -1) - ERROR_LOG("{} failed to write to socket: {}", m_descriptor, errorString().toStdString()); -} diff --git a/src/duckstation-qt/gdbconnection.h b/src/duckstation-qt/gdbconnection.h deleted file mode 100644 index cea8ced8c..000000000 --- a/src/duckstation-qt/gdbconnection.h +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin and contributors. -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once -#include -#include - -class GDBServer; - -class GDBConnection : public QTcpSocket -{ - Q_OBJECT - -public: - GDBConnection(GDBServer *parent, intptr_t descriptor); - -public Q_SLOTS: - void gotDisconnected(); - void receivedData(); - void onEmulationPaused(); - void onEmulationResumed(); - -private: - void writePacket(std::string_view data); - - intptr_t m_descriptor; - std::string m_readBuffer; - bool m_seen_resume; -}; diff --git a/src/duckstation-qt/gdbserver.cpp b/src/duckstation-qt/gdbserver.cpp deleted file mode 100644 index 504cc0733..000000000 --- a/src/duckstation-qt/gdbserver.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin and contributors. -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "gdbserver.h" -#include "common/log.h" -#include "gdbconnection.h" -#include "qthost.h" -Log_SetChannel(GDBServer); - -GDBServer::GDBServer(QObject* parent) : QTcpServer(parent) -{ -} - -GDBServer::~GDBServer() -{ - stop(); -} - -void GDBServer::start(quint16 port) -{ - if (isListening()) - { - return; - } - - if (!listen(QHostAddress::LocalHost, port)) - { - ERROR_LOG("Failed to listen on TCP port {} for GDB server: {}", port, errorString().toUtf8().constData()); - return; - } - - INFO_LOG("GDB server listening on TCP port {}", port); -} - -void GDBServer::stop() -{ - if (isListening()) - { - close(); - INFO_LOG("GDB server stopped"); - } - - for (QObject* connection : children()) - { - connection->deleteLater(); - } -} - -void GDBServer::incomingConnection(qintptr descriptor) -{ - new GDBConnection(this, descriptor); -} diff --git a/src/duckstation-qt/gdbserver.h b/src/duckstation-qt/gdbserver.h deleted file mode 100644 index 5da9f432a..000000000 --- a/src/duckstation-qt/gdbserver.h +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin and contributors. -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once -#include "core/types.h" -#include "gdbconnection.h" -#include - -class GDBServer : public QTcpServer -{ - Q_OBJECT - -public: - GDBServer(QObject* parent = nullptr); - ~GDBServer(); - -public Q_SLOTS: - void start(quint16 port); - void stop(); - -protected: - void incomingConnection(qintptr socketDescriptor) override; -}; diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index f8bfa679d..895c0c197 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -1826,16 +1826,6 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool cheevo if ((!starting && !running) || running) m_open_debugger_on_start = false; - if (!g_gdb_server->isListening() && g_settings.debugging.enable_gdb_server && starting) - { - QMetaObject::invokeMethod(g_gdb_server, "start", Qt::QueuedConnection, - Q_ARG(quint16, g_settings.debugging.gdb_server_port)); - } - else if (g_gdb_server->isListening() && !running) - { - QMetaObject::invokeMethod(g_gdb_server, "stop", Qt::QueuedConnection); - } - m_ui.statusBar->clearMessage(); } diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 85c8d7434..3accb58a3 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -16,6 +16,7 @@ #include "core/fullscreen_ui.h" #include "core/game_database.h" #include "core/game_list.h" +#include "core/gdb_server.h" #include "core/gpu.h" #include "core/host.h" #include "core/imgui_overlays.h" @@ -81,6 +82,9 @@ static constexpr u32 BACKGROUND_CONTROLLER_POLLING_INTERVAL = 100; /// Poll at half the vsync rate for FSUI to reduce the chance of getting a press+release in the same frame. static constexpr u32 FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL = 8; +/// Poll at 1ms when running GDB server. We can get rid of this once we move networking to its own thread. +static constexpr u32 GDB_SERVER_POLLING_INTERVAL = 1; + ////////////////////////////////////////////////////////////////////////// // Local function declarations ////////////////////////////////////////////////////////////////////////// @@ -116,8 +120,7 @@ static bool s_start_fullscreen_ui_fullscreen = false; static bool s_run_setup_wizard = false; static bool s_cleanup_after_update = false; -EmuThread* g_emu_thread; -GDBServer* g_gdb_server; +EmuThread* g_emu_thread = nullptr; EmuThread::EmuThread(QThread* ui_thread) : QThread(), m_ui_thread(ui_thread) { @@ -1670,8 +1673,13 @@ void EmuThread::startBackgroundControllerPollTimer() if (m_background_controller_polling_timer->isActive()) return; - m_background_controller_polling_timer->start( - FullscreenUI::IsInitialized() ? FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL : BACKGROUND_CONTROLLER_POLLING_INTERVAL); + u32 poll_interval = BACKGROUND_CONTROLLER_POLLING_INTERVAL; + if (FullscreenUI::IsInitialized()) + poll_interval = FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL; + if (GDBServer::HasAnyClients()) + poll_interval = GDB_SERVER_POLLING_INTERVAL; + + m_background_controller_polling_timer->start(poll_interval); } void EmuThread::stopBackgroundControllerPollTimer() @@ -1687,8 +1695,6 @@ void EmuThread::start() AssertMsg(!g_emu_thread, "Emu thread does not exist"); g_emu_thread = new EmuThread(QThread::currentThread()); - g_gdb_server = new GDBServer(); - g_gdb_server->moveToThread(g_emu_thread); g_emu_thread->QThread::start(); g_emu_thread->m_started_semaphore.acquire(); g_emu_thread->moveToThread(g_emu_thread); diff --git a/src/duckstation-qt/qthost.h b/src/duckstation-qt/qthost.h index 9290747af..046041a62 100644 --- a/src/duckstation-qt/qthost.h +++ b/src/duckstation-qt/qthost.h @@ -3,7 +3,6 @@ #pragma once -#include "gdbserver.h" #include "qtutils.h" #include "core/game_list.h" @@ -246,7 +245,6 @@ private: }; extern EmuThread* g_emu_thread; -extern GDBServer* g_gdb_server; namespace QtHost { /// Sets batch mode (exit after game shutdown). diff --git a/src/util/sockets.cpp b/src/util/sockets.cpp index 96546f08d..7734f4f8d 100644 --- a/src/util/sockets.cpp +++ b/src/util/sockets.cpp @@ -755,6 +755,9 @@ void BufferedStreamSocket::ReleaseReadBuffer(size_t bytes_consumed) std::span BufferedStreamSocket::AcquireWriteBuffer(size_t wanted_bytes, bool allow_smaller /* = false */) { + if (!m_connected) + return {}; + // If to get the desired space, we need to move backwards, do so. if ((m_send_buffer_offset + m_send_buffer_size + wanted_bytes) > m_send_buffer.size()) { @@ -776,6 +779,9 @@ std::span BufferedStreamSocket::AcquireWriteBuffer(size_t wanted_bytes, bool void BufferedStreamSocket::ReleaseWriteBuffer(size_t bytes_written, bool commit /* = true */) { + if (!m_connected) + return; + DebugAssert((m_send_buffer_offset + m_send_buffer_size + bytes_written) <= m_send_buffer.size()); m_send_buffer_size += static_cast(bytes_written); @@ -819,6 +825,9 @@ size_t BufferedStreamSocket::Read(void* buffer, size_t buffer_size) size_t BufferedStreamSocket::Write(const void* buffer, size_t buffer_size) { + if (!m_connected) + return 0; + // Read from receive buffer. const std::span wrbuf = AcquireWriteBuffer(buffer_size, true); if (wrbuf.empty()) @@ -857,6 +866,16 @@ size_t BufferedStreamSocket::WriteVector(const void** buffers, const size_t* buf return written_bytes; } +void BufferedStreamSocket::Close() +{ + StreamSocket::Close(); + + m_receive_buffer_offset = 0; + m_receive_buffer_size = 0; + m_send_buffer_offset = 0; + m_send_buffer_size = 0; +} + void BufferedStreamSocket::OnReadEvent() { std::unique_lock lock(m_lock); diff --git a/src/util/sockets.h b/src/util/sockets.h index f9b4db71a..ddd608eb2 100644 --- a/src/util/sockets.h +++ b/src/util/sockets.h @@ -197,7 +197,7 @@ public: static u32 GetSocketProtocolForAddress(const SocketAddress& sa); - virtual void Close() override final; + virtual void Close() override; // Accessors const SocketAddress& GetLocalAddress() const { return m_local_address; } @@ -251,6 +251,7 @@ public: size_t Read(void* buffer, size_t buffer_size); size_t Write(const void* buffer, size_t buffer_size); size_t WriteVector(const void** buffers, const size_t* buffer_lengths, size_t num_buffers); + virtual void Close() override; protected: void OnReadEvent() override final;