fix mwaitx timer

This commit is contained in:
lizzie 2026-05-23 22:00:21 +00:00
parent f123ba00c5
commit 94ffe4cf7c

View file

@ -171,19 +171,27 @@ __attribute__((target("waitpkg,mwaitx")))
#endif #endif
bool Event::WaitFor(const std::chrono::nanoseconds time) { bool Event::WaitFor(const std::chrono::nanoseconds time) {
auto const start = Common::X64::FencedRDTSC(); auto const start = Common::X64::FencedRDTSC();
auto const& caps = Common::g_cpu_caps; auto const& caps = Common::g_cpu_caps;
auto const ns_ratio = std::max<u64>(1, caps.base_frequency / 1'000); auto const ns_ratio = std::max<u64>(1, caps.base_frequency / 1'000);
auto const end = start + time.count() * ns_ratio; auto const end = start + time.count() * ns_ratio;
if (caps.monitorx) { if (caps.monitorx) {
while (true) { while (true) {
// Armed monitor, as per manual, MWAITX must be conditional if the condition isn't satisfied
// to prevent a race condition.
_mm_monitorx(reinterpret_cast<u64*>(std::addressof(is_set)), 0, 0); _mm_monitorx(reinterpret_cast<u64*>(std::addressof(is_set)), 0, 0);
if (!is_set.load()) { if (!is_set.load()) {
constexpr auto EnableWaitTimeFlag = 1U << 1; // RDTSC may be fenced here due to atomic load
constexpr auto RequestC1State = 0U; s32 const cycles = s64(_rdtsc()) - s64(start);
_mm_mwaitx(EnableWaitTimeFlag, RequestC1State, end); if (cycles > 0) {
if (!is_set.load()) // See here: https://github.com/torvalds/linux/blob/948a64995aca6820abefd17f1a4258f5835c5ad9/arch/x86/lib/delay.c#L93
return false; // MWAITX accepts a 32-bit input timer which determines the total number of cycles to wait for
// NOT THE TOTAL ABSOLUTE TSC VALUE, it's just a delta
// BIT[1] = use a timer
// Hint = 0: Use C1 state when sleepy (means faster wakeup but less power saving)
_mm_mwaitx(1 << 1, 0u, cycles);
if (!is_set.load())
return false;
}
} }
bool expected = true; bool expected = true;
if (is_set.compare_exchange_weak(expected, false, std::memory_order_release)) if (is_set.compare_exchange_weak(expected, false, std::memory_order_release))