From 7c4b1ba3ca2d723d03735abfce3b3ae5ef057876 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 18 Jan 2025 20:15:18 +0100 Subject: [PATCH] Speedup GDB data processing --- src/gdb-stub/connection_handler.cpp | 73 +++++++++++++++++++++++++++-- src/gdb-stub/connection_handler.hpp | 29 +++++++++++- src/gdb-stub/gdb_stub.cpp | 35 ++++++-------- src/gdb-stub/stream_processor.hpp | 1 - 4 files changed, 111 insertions(+), 27 deletions(-) diff --git a/src/gdb-stub/connection_handler.cpp b/src/gdb-stub/connection_handler.cpp index 9ef40d21..e6ee6ffc 100644 --- a/src/gdb-stub/connection_handler.cpp +++ b/src/gdb-stub/connection_handler.cpp @@ -27,6 +27,23 @@ namespace gdb_stub : client_(client) { this->client_.set_blocking(false); + + this->stop_ = false; + + this->output_thread_ = std::thread([this] { + this->transmission_loop(); // + }); + } + + connection_handler::~connection_handler() + { + this->stop_ = true; + this->condition_variable_.notify_all(); + + if (this->output_thread_.joinable()) + { + this->output_thread_.join(); + } } std::optional connection_handler::get_packet() @@ -35,7 +52,7 @@ namespace gdb_stub { if (!read_from_socket(this->processor_, this->client_)) { - std::this_thread::sleep_for(100ms); + (void)this->client_.sleep(100ms, true); } } @@ -47,19 +64,67 @@ namespace gdb_stub return std::nullopt; } - void connection_handler::send_reply(const std::string_view data) const + void connection_handler::send_reply(const std::string_view data) { const auto checksum = utils::string::to_hex_string(compute_checksum(data)); this->send_raw_data("$" + std::string(data) + "#" + checksum); } - void connection_handler::send_raw_data(const std::string_view data) const + void connection_handler::send_raw_data(const std::string_view data) { - (void)this->client_.send(data); + { + std::lock_guard _{this->mutex_}; + this->output_stream_.append(data); + } + + this->condition_variable_.notify_one(); + } + + bool connection_handler::should_stop() const + { + return this->stop_ || !this->client_.is_valid(); } void connection_handler::close() const { this->client_.close(); } + + void connection_handler::await_transmission(const std::function& handler) + { + std::unique_lock lock{this->mutex_}; + + const auto can_run = [this] { + return this->should_stop() // + || !this->output_stream_.empty(); + }; + + const auto run = this->condition_variable_.wait_for(lock, 100ms, can_run); + + if (run && !this->should_stop()) + { + handler(); + } + } + + std::string connection_handler::get_next_data_to_transmit() + { + std::string transmit_data{}; + + this->await_transmission([&] { + transmit_data = std::move(this->output_stream_); + this->output_stream_ = {}; + }); + + return transmit_data; + } + + void connection_handler::transmission_loop() + { + while (!this->should_stop()) + { + const auto data = this->get_next_data_to_transmit(); + (void)this->client_.send(data); + } + } } diff --git a/src/gdb-stub/connection_handler.hpp b/src/gdb-stub/connection_handler.hpp index afd326ca..28d7a76f 100644 --- a/src/gdb-stub/connection_handler.hpp +++ b/src/gdb-stub/connection_handler.hpp @@ -1,23 +1,48 @@ #pragma once #include "stream_processor.hpp" + +#include #include +#include +#include +#include + namespace gdb_stub { class connection_handler { public: connection_handler(network::tcp_client_socket& client); + ~connection_handler(); + + connection_handler(connection_handler&&) = delete; + connection_handler(const connection_handler&) = delete; + + connection_handler& operator=(connection_handler&&) = delete; + connection_handler& operator=(const connection_handler&) = delete; std::optional get_packet(); - void send_reply(std::string_view data) const; - void send_raw_data(std::string_view data) const; + void send_reply(std::string_view data); + void send_raw_data(std::string_view data); void close() const; + bool should_stop() const; + private: network::tcp_client_socket& client_; stream_processor processor_{}; + + std::mutex mutex_{}; + std::atomic_bool stop_{}; + std::string output_stream_{}; + std::thread output_thread_{}; + std::condition_variable condition_variable_{}; + + void transmission_loop(); + void await_transmission(const std::function& handler); + std::string get_next_data_to_transmit(); }; } diff --git a/src/gdb-stub/gdb_stub.cpp b/src/gdb-stub/gdb_stub.cpp index 0ebabd8c..d259fdb2 100644 --- a/src/gdb-stub/gdb_stub.cpp +++ b/src/gdb-stub/gdb_stub.cpp @@ -49,8 +49,7 @@ namespace gdb_stub return {name, args}; } - void process_xfer(const connection_handler& connection, debugging_handler& handler, - const std::string_view payload) + void process_xfer(connection_handler& connection, debugging_handler& handler, const std::string_view payload) { auto [name, args] = split_string(payload, ':'); @@ -66,8 +65,7 @@ namespace gdb_stub } } - void process_query(const connection_handler& connection, debugging_handler& handler, - const std::string_view payload) + void process_query(connection_handler& connection, debugging_handler& handler, const std::string_view payload) { const auto [name, args] = split_string(payload, ':'); @@ -93,7 +91,7 @@ namespace gdb_stub } } - void process_action(const connection_handler& connection, const action a) + void process_action(connection_handler& connection, const action a) { if (a == action::shutdown) { @@ -122,8 +120,8 @@ namespace gdb_stub return handler.delete_breakpoint(type, address, size); } - void handle_breakpoint(const connection_handler& connection, debugging_handler& handler, - const std::string& data, const bool set) + void handle_breakpoint(connection_handler& connection, debugging_handler& handler, const std::string& data, + const bool set) { uint32_t type{}; uint64_t addr{}; @@ -134,7 +132,7 @@ namespace gdb_stub connection.send_reply(res ? "OK" : "E01"); } - void handle_v_packet(const connection_handler& connection, const std::string_view data) + void handle_v_packet(connection_handler& connection, const std::string_view data) { const auto [name, args] = split_string(data, ':'); @@ -151,7 +149,7 @@ namespace gdb_stub } } - void read_registers(const connection_handler& connection, debugging_handler& handler) + void read_registers(connection_handler& connection, debugging_handler& handler) { std::string response{}; std::vector data{}; @@ -176,8 +174,7 @@ namespace gdb_stub connection.send_reply(response); } - void write_registers(const connection_handler& connection, debugging_handler& handler, - const std::string_view payload) + void write_registers(connection_handler& connection, debugging_handler& handler, const std::string_view payload) { const auto data = utils::string::from_hex_string(payload); @@ -207,7 +204,7 @@ namespace gdb_stub connection.send_reply("OK"); } - void read_single_register(const connection_handler& connection, debugging_handler& handler, + void read_single_register(connection_handler& connection, debugging_handler& handler, const std::string& payload) { size_t reg{}; @@ -228,7 +225,7 @@ namespace gdb_stub } } - void write_single_register(const connection_handler& connection, debugging_handler& handler, + void write_single_register(connection_handler& connection, debugging_handler& handler, const std::string_view payload) { const auto [reg, hex_data] = split_string(payload, '='); @@ -245,7 +242,7 @@ namespace gdb_stub connection.send_reply(res ? "OK" : "E01"); } - void read_memory(const connection_handler& connection, debugging_handler& handler, const std::string& payload) + void read_memory(connection_handler& connection, debugging_handler& handler, const std::string& payload) { uint64_t address{}; size_t size{}; @@ -270,8 +267,7 @@ namespace gdb_stub connection.send_reply(utils::string::to_hex_string(data)); } - void write_memory(const connection_handler& connection, debugging_handler& handler, - const std::string_view payload) + void write_memory(connection_handler& connection, debugging_handler& handler, const std::string_view payload) { const auto [info, hex_data] = split_string(payload, ':'); @@ -318,8 +314,7 @@ namespace gdb_stub return result; } - void write_x_memory(const connection_handler& connection, debugging_handler& handler, - const std::string_view payload) + void write_x_memory(connection_handler& connection, debugging_handler& handler, const std::string_view payload) { const auto [info, encoded_data] = split_string(payload, ':'); @@ -346,7 +341,7 @@ namespace gdb_stub connection.send_reply("OK"); } - void handle_command(const connection_handler& connection, async_handler& async, debugging_handler& handler, + void handle_command(connection_handler& connection, async_handler& async, debugging_handler& handler, const uint8_t command, const std::string_view data) { // printf("GDB command: %c -> %.*s\n", command, static_cast(data.size()), data.data()); @@ -420,7 +415,7 @@ namespace gdb_stub } } - void process_packet(const connection_handler& connection, async_handler& async, debugging_handler& handler, + void process_packet(connection_handler& connection, async_handler& async, debugging_handler& handler, const std::string_view packet) { connection.send_raw_data("+"); diff --git a/src/gdb-stub/stream_processor.hpp b/src/gdb-stub/stream_processor.hpp index c6b48442..b882fcce 100644 --- a/src/gdb-stub/stream_processor.hpp +++ b/src/gdb-stub/stream_processor.hpp @@ -1,7 +1,6 @@ #pragma once #include #include -#include namespace gdb_stub {