diff options
| author | lizzie <lizzie@eden-emu.dev> | 2026-04-09 23:46:38 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-04-09 23:46:38 +0200 |
| commit | c95cb8f8ec6ce256b75fd85c858c7b80f91e088e (patch) | |
| tree | 40e5c55bd2bc7b7005e01b37033ec529f9529dda /src | |
| parent | 3d0eb4b5d71c6e051480408ab4274082c6b232e3 (diff) | |
[hle] improved flusher that uses jthread (#3837)
not happy with this impl, but I made this a bit quickly to demostrate it can be done better :)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3837
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/svc/svc_debug_string.cpp | 102 |
1 files changed, 43 insertions, 59 deletions
diff --git a/src/core/hle/kernel/svc/svc_debug_string.cpp b/src/core/hle/kernel/svc/svc_debug_string.cpp index 92cc334a81..c190fa7a3f 100644 --- a/src/core/hle/kernel/svc/svc_debug_string.cpp +++ b/src/core/hle/kernel/svc/svc_debug_string.cpp @@ -6,6 +6,8 @@ #include <condition_variable> #include <mutex> +#include <optional> +#include <stop_token> #include <thread> #include "core/core.h" @@ -18,59 +20,53 @@ namespace Kernel::Svc { constexpr auto MAX_MSG_TIME = std::chrono::milliseconds(250); const auto MAX_MSG_SIZE = 0x1000; -static std::string msg_buffer; -static std::mutex msg_mutex; -static std::condition_variable msg_cv; -static std::chrono::steady_clock::time_point last_msg_time; -static bool worker_running = true; -static std::unique_ptr<std::thread> flush_thread; -static std::once_flag start_flag; - -static void FlushDbgLoop() { - while (true) { - std::unique_lock lock(msg_mutex); - - msg_cv.wait(lock, [] { return !msg_buffer.empty() || !worker_running; }); - if (!worker_running && msg_buffer.empty()) break; - - auto timeout = last_msg_time + MAX_MSG_TIME; - bool woke_early = msg_cv.wait_until(lock, timeout, [] { - return msg_buffer.size() >= MAX_MSG_SIZE || !worker_running; - }); - - if (!woke_early || msg_buffer.size() >= MAX_MSG_SIZE || !worker_running) { - if (!msg_buffer.empty()) { - // Remove trailing newline as LOG_INFO adds that anyways - if (msg_buffer.back() == '\n') - msg_buffer.pop_back(); - - LOG_INFO(Debug_Emulated, "\n{}", msg_buffer); - msg_buffer.clear(); - } - if (!worker_running) break; - } - } -} - /// Used to output a message on a debug hardware unit - does nothing on a retail unit Result OutputDebugString(Core::System& system, u64 address, u64 len) { + static struct DebugFlusher { + std::string msg_buffer; + std::mutex msg_mutex; + std::condition_variable msg_cv; + std::chrono::steady_clock::time_point last_msg_time; + std::optional<std::jthread> thread; + } flusher_data; R_SUCCEED_IF(len == 0); - // Only start the thread the very first time this function is called - std::call_once(start_flag, [] { - flush_thread = std::make_unique<std::thread>(FlushDbgLoop); - }); - + if (!flusher_data.thread) { + flusher_data.thread.emplace([](std::stop_token stop_token) { + while (!stop_token.stop_requested()) { + std::unique_lock lock(flusher_data.msg_mutex); + flusher_data.msg_cv.wait(lock, [&stop_token] { + return !flusher_data.msg_buffer.empty() || stop_token.stop_requested(); + }); + if (stop_token.stop_requested() && flusher_data.msg_buffer.empty()) + break; + auto timeout = flusher_data.last_msg_time + MAX_MSG_TIME; + bool woke_early = flusher_data.msg_cv.wait_until(lock, timeout, [&stop_token] { + return flusher_data.msg_buffer.size() >= MAX_MSG_SIZE || stop_token.stop_requested(); + }); + if (!woke_early || flusher_data.msg_buffer.size() >= MAX_MSG_SIZE || stop_token.stop_requested()) { + if (!flusher_data.msg_buffer.empty()) { + // Remove trailing newline as LOG_INFO adds that anyways + if (flusher_data.msg_buffer.back() == '\n') + flusher_data.msg_buffer.pop_back(); + + LOG_INFO(Debug_Emulated, "\n{}", flusher_data.msg_buffer); + flusher_data.msg_buffer.clear(); + } + if (stop_token.stop_requested()) break; + } + } + flusher_data.msg_cv.notify_all(); + }); + } { - std::lock_guard lock(msg_mutex); - const auto old_size = msg_buffer.size(); - msg_buffer.resize(old_size + len); - GetCurrentMemory(system.Kernel()).ReadBlock(address, msg_buffer.data() + old_size, len); - - last_msg_time = std::chrono::steady_clock::now(); + std::lock_guard lock(flusher_data.msg_mutex); + const auto old_size = flusher_data.msg_buffer.size(); + flusher_data.msg_buffer.resize(old_size + len); + GetCurrentMemory(system.Kernel()).ReadBlock(address, flusher_data.msg_buffer.data() + old_size, len); + flusher_data.last_msg_time = std::chrono::steady_clock::now(); } - - msg_cv.notify_one(); + flusher_data.msg_cv.notify_one(); R_SUCCEED(); } @@ -82,16 +78,4 @@ Result OutputDebugString64From32(Core::System& system, uint32_t debug_str, uint3 R_RETURN(OutputDebugString(system, debug_str, len)); } -struct BufferAutoFlush { - ~BufferAutoFlush() { - { - std::lock_guard lock(msg_mutex); - worker_running = false; - } - msg_cv.notify_all(); - if (flush_thread && flush_thread->joinable()) flush_thread->join(); - } -}; -static BufferAutoFlush auto_flusher; - } // namespace Kernel::Svc |
