From 41241d7500419ac03c82641e560fc6afe9d8b8f9 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 6 Jul 2026 15:47:05 -0700 Subject: [PATCH] Wow64: Spin loop on atomic with WFE Instead of burning roughly a million watts, put this spinloop on a WFE. This tends to occur on a crash during shutdown that isn't fully able to be avoided. The least we can do is not consume all the power in the world. --- FEXCore/include/FEXCore/Utils/SpinWaitLock.h | 25 ++++++++++++++++++++ Source/Windows/WOW64/Module.cpp | 7 ++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/FEXCore/include/FEXCore/Utils/SpinWaitLock.h b/FEXCore/include/FEXCore/Utils/SpinWaitLock.h index 1fa0c03561..af59a6efb3 100644 --- a/FEXCore/include/FEXCore/Utils/SpinWaitLock.h +++ b/FEXCore/include/FEXCore/Utils/SpinWaitLock.h @@ -144,6 +144,21 @@ static inline void WaitPred(T* Futex, T ComparisonValue) { } } +template +static inline void WaitBitMaskPred(T* Futex, T BitMask, T ComparisonValue, Pred Predicate) { + auto AtomicFutex = std::atomic_ref(*Futex); + T Result = AtomicFutex.load(); + + while (!Predicate(Result & BitMask, ComparisonValue)) { + Result = LoadExclusive(Futex); + if (Predicate(Result & BitMask, ComparisonValue)) { + return; + } + + Result = WFELoadAtomic(Futex); + } +} + template static inline bool Wait(T* Futex, TT ExpectedValue, const std::chrono::nanoseconds& Timeout) { auto AtomicFutex = std::atomic_ref(*Futex); @@ -213,6 +228,16 @@ static inline void WaitPred(T* Futex, T ComparisonValue) { } } +template +static inline void WaitBitMaskPred(T* Futex, T BitMask, T ComparisonValue, Pred Predicate) { + auto AtomicFutex = std::atomic_ref(*Futex); + T Result = AtomicFutex.load(); + + while (!Predicate(Result & BitMask, ComparisonValue)) { + Result = AtomicFutex.load(); + } +} + template static inline bool Wait(T* Futex, TT ExpectedValue, const std::chrono::nanoseconds& Timeout) { auto AtomicFutex = std::atomic_ref(*Futex); diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index bff9ae2da5..f623023154 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -95,6 +95,10 @@ struct TLS { return reinterpret_cast&>(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::CONTROL_WORD)]); } + uint32_t* ControlWordAddress() const { + return reinterpret_cast(&TEB->TlsSlots[FEXCore::ToUnderlying(Slot::CONTROL_WORD)]); + } + CONTEXT*& EntryContext() const { return reinterpret_cast(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::ENTRY_CONTEXT)]); } @@ -822,8 +826,7 @@ NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG* Count) { } // Spin until the JIT is interrupted - while (TLS.ControlWord().load() & ControlBits::IN_JIT) - ; + FEXCore::Utils::SpinWaitLock::WaitBitMaskPred(TLS.ControlWordAddress(), ControlBits::IN_JIT, 0U, std::equal_to<>()); // The JIT has now been interrupted and the context stored in the thread's CPU area is up-to-date if (Err = NtSuspendThread(*ThreadDup, Count); Err) {