From 43b94f255daf1b054ffa8de54c879e355360e6a4 Mon Sep 17 00:00:00 2001 From: Elad Ashkenazi Date: Wed, 24 May 2023 17:21:28 +0300 Subject: [PATCH] LV2 Timer: Fix thread wait_for_accurate, use it --- Utilities/Thread.cpp | 32 +++++++++++++++++++++++--------- Utilities/Thread.h | 6 +++--- rpcs3/Emu/Cell/lv2/sys_timer.cpp | 2 +- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 05379c5b888c..e349f563d596 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2396,7 +2396,7 @@ thread_state thread_ctrl::state() return static_cast(_this->m_sync & 3); } -void thread_ctrl::wait_for(u64 usec, [[maybe_unused]] bool alert /* true */) +bool thread_ctrl::wait_for(u64 usec, bool alert) { auto _this = g_tls_this_thread; @@ -2440,23 +2440,33 @@ void thread_ctrl::wait_for(u64 usec, [[maybe_unused]] bool alert /* true */) timerfd_settime(fd_timer, 0, &timeout, NULL); if (read(fd_timer, &missed, sizeof(missed)) != sizeof(missed)) sig_log.error("timerfd: read() failed"); - return; + return true; } #endif - if (_this->m_sync.bit_test_reset(2) || _this->m_taskq) + if ((alert && (_this->m_sync.bit_test_reset(2) || _this->m_taskq)) || _this->m_sync & 1) { - return; + // Notified or aborted + return false; + } + + const atomic_wait_timeout timeout{usec <= 0xffff'ffff'ffff'ffff / 1000 ? usec * 1000 : 0xffff'ffff'ffff'ffff}; + + if (!alert) + { + _this->m_sync.wait(0, 1, timeout); + return true; } // Wait for signal and thread state abort atomic_wait::list<2> list{}; list.set<0>(_this->m_sync, 0, 4 + 1); list.set<1>(_this->m_taskq, nullptr); - list.wait(atomic_wait_timeout{usec <= 0xffff'ffff'ffff'ffff / 1000 ? usec * 1000 : 0xffff'ffff'ffff'ffff}); + list.wait(timeout); + return true; // Unknown if notified for now } -void thread_ctrl::wait_for_accurate(u64 usec) +void thread_ctrl::wait_for_accurate(u64 usec, bool alert) { if (!usec) { @@ -2481,11 +2491,15 @@ void thread_ctrl::wait_for_accurate(u64 usec) { #ifdef __linux__ // Do not wait for the last quantum to avoid loss of accuracy - wait_for(usec - ((usec % host_min_quantum) + host_min_quantum), false); + if (!wait_for(usec - ((usec % host_min_quantum) + host_min_quantum), alert)) #else // Wait on multiple of min quantum for large durations to avoid overloading low thread cpus - wait_for(usec - (usec % host_min_quantum), false); + if (!wait_for(usec - (usec % host_min_quantum), alert)) #endif + { + // Notified + return; + } } // TODO: Determine best value for yield delay else if (usec >= host_min_quantum / 2) @@ -2504,7 +2518,7 @@ void thread_ctrl::wait_for_accurate(u64 usec) break; } - usec = (until - current).count(); + usec = std::chrono::duration_cast(until - current).count(); } } diff --git a/Utilities/Thread.h b/Utilities/Thread.h index a64d64cb995b..83ab8dd56cd4 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -260,11 +260,11 @@ class thread_ctrl final // Read current state, possibly executing some tasks static thread_state state(); - // Wait once with timeout. Infinite value is -1. - static void wait_for(u64 usec, bool alert = true); + // Wait once with timeout. Infinite value is -1. (returns false if known to be notified) + static bool wait_for(u64 usec, bool alert = true); // Waiting with accurate timeout - static void wait_for_accurate(u64 usec); + static void wait_for_accurate(u64 usec, bool alert = false); // Wait. static inline void wait() diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp index 4816a4ef3f1c..0a8de120aa26 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -123,7 +123,7 @@ void lv2_timer_thread::operator()() sleep_time = std::min(sleep_time, u64{umax} / 100) * 100 / g_cfg.core.clocks_scale; } - thread_ctrl::wait_for(sleep_time); + thread_ctrl::wait_for_accurate(sleep_time); if (thread_ctrl::state() == thread_state::aborting) {