From 9a67e02ba13f1c9839aab586c2ca52ce0d768c96 Mon Sep 17 00:00:00 2001 From: Elad Ashkenazi Date: Wed, 24 May 2023 17:21:28 +0300 Subject: [PATCH] Fix thread_ctrl::wait_for_accurate --- Utilities/Thread.cpp | 26 +++++++++++++++++--------- Utilities/Thread.h | 6 +++--- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 717e6a78099f..6e05a3396877 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2371,7 +2371,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, [[maybe_unused]] bool alert /* true */) { auto _this = g_tls_this_thread; @@ -2415,29 +2415,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 & (4 + 1))) { - return; + // Notified or aborted + return false; } // Wait for signal and thread state abort atomic_wait::list<2> list{}; - list.set<0>(_this->m_sync, 0, 4 + 1); + list.set<0>(_this->m_sync, 0, alert ? 4 + 1 : 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}); + 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) { return; } + const auto _this = g_tls_this_thread; + using namespace std::chrono_literals; const auto until = std::chrono::steady_clock::now() + 1us * usec; @@ -2456,11 +2460,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) @@ -2479,7 +2487,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 ae4d625f1e42..760ced341333 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()