From c6dcf3f1d373daabc9121593afeb505f0af79832 Mon Sep 17 00:00:00 2001 From: Ivan Chikish Date: Sun, 6 Aug 2023 10:04:38 +0300 Subject: [PATCH] (Linux) Fixup futex_waitv --- rpcs3/util/atomic.cpp | 50 ++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/rpcs3/util/atomic.cpp b/rpcs3/util/atomic.cpp index f9541320e9..97f0ac35d0 100644 --- a/rpcs3/util/atomic.cpp +++ b/rpcs3/util/atomic.cpp @@ -1,7 +1,6 @@ #include "atomic.hpp" #if defined(__linux__) -// This definition is unused on Linux #define USE_FUTEX #elif !defined(_WIN32) #define USE_STD @@ -29,6 +28,21 @@ namespace utils #include "Utilities/sync.h" #include "Utilities/StrFmt.h" +#ifdef __linux__ +static bool has_waitv() +{ + static const bool s_has_waitv = [] + { + syscall(SYS_futex_waitv, 0, 0, 0, 0, 0); + if (errno == ENOSYS) + return false; + return true; + }(); + + return s_has_waitv; +} +#endif + #include #include #include @@ -843,7 +857,7 @@ atomic_wait_engine::wait(const void* data, u32 old_value, u64 timeout, atomic_wa ::timespec ts{}; if (timeout + 1) { - if (ext) [[unlikely]] + if (ext && ext->data) [[unlikely]] { // futex_waitv uses absolute timeout ::clock_gettime(CLOCK_MONOTONIC, &ts); @@ -851,7 +865,7 @@ atomic_wait_engine::wait(const void* data, u32 old_value, u64 timeout, atomic_wa ts.tv_sec += timeout / 1'000'000'000; ts.tv_nsec += timeout % 1'000'000'000; - if (ts.tv_nsec > 1'000'000'000) + if (ts.tv_nsec >= 1'000'000'000) { ts.tv_sec++; ts.tv_nsec -= 1'000'000'000; @@ -874,7 +888,7 @@ atomic_wait_engine::wait(const void* data, u32 old_value, u64 timeout, atomic_wa } } - if (ext_size) [[unlikely]] + if (ext_size && has_waitv()) [[unlikely]] { if (syscall(SYS_futex_waitv, +vec, ext_size + 1, 0, timeout + 1 ? &ts : nullptr, CLOCK_MONOTONIC) == -1) { @@ -887,8 +901,9 @@ atomic_wait_engine::wait(const void* data, u32 old_value, u64 timeout, atomic_wa fmt::throw_exception("futex_waitv: bad param"); } } + return; } - else + else if (has_waitv()) { if (futex(const_cast(data), FUTEX_WAIT_PRIVATE, old_value, timeout + 1 ? &ts : nullptr) == -1) { @@ -897,9 +912,8 @@ atomic_wait_engine::wait(const void* data, u32 old_value, u64 timeout, atomic_wa fmt::throw_exception("futex: bad param"); } } + return; } - - return; #endif if (!s_tls_wait_cb(data, 0, 0)) @@ -1242,8 +1256,14 @@ void atomic_wait_engine::notify_one(const void* data) s_tls_notify_cb(data, 0); #ifdef __linux__ - futex(const_cast(data), FUTEX_WAKE_PRIVATE, 1); -#else + if (has_waitv()) + { + futex(const_cast(data), FUTEX_WAKE_PRIVATE, 1); + if (s_tls_notify_cb) + s_tls_notify_cb(data, -1); + return; + } +#endif const uptr iptr = reinterpret_cast(data) & (~s_ref_mask >> 16); root_info::slot_search(iptr, [&](u32 cond_id) @@ -1255,7 +1275,6 @@ void atomic_wait_engine::notify_one(const void* data) return false; }); -#endif if (s_tls_notify_cb) s_tls_notify_cb(data, -1); @@ -1268,8 +1287,14 @@ atomic_wait_engine::notify_all(const void* data) s_tls_notify_cb(data, 0); #ifdef __linux__ - futex(const_cast(data), FUTEX_WAKE_PRIVATE, 1); -#else + if (has_waitv()) + { + futex(const_cast(data), FUTEX_WAKE_PRIVATE, INT_MAX); + if (s_tls_notify_cb) + s_tls_notify_cb(data, -1); + return; + } +#endif const uptr iptr = reinterpret_cast(data) & (~s_ref_mask >> 16); // Array count for batch notification @@ -1342,7 +1367,6 @@ atomic_wait_engine::notify_all(const void* data) { cond_free(~*(std::end(cond_ids) - i - 1)); } -#endif if (s_tls_notify_cb) s_tls_notify_cb(data, -1);