mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-10 03:18:55 +02:00
[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>
This commit is contained in:
parent
3d0eb4b5d7
commit
c95cb8f8ec
1 changed files with 43 additions and 59 deletions
|
|
@ -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();
|
||||
|
||||
{
|
||||
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();
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
msg_cv.notify_one();
|
||||
{
|
||||
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();
|
||||
}
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue