From 697cacd85491e1e7710af4e415be9ccf52ccd264 Mon Sep 17 00:00:00 2001 From: jpolo1224 Date: Mon, 10 Aug 2026 15:12:16 -0400 Subject: [PATCH] Bound the waits on an SPU compile claim Waiting on the claim was untimed, so a waiter that missed the owner's transition waited for the rest of the session, and the duplicate waiter could only leave on the failure state -- an owner that published state 2 without publishing a function left it waiting on something that was never coming. SPURS brings all of its kernels to the same block at once, so this is four threads at a time, and the PPU then blocks on SPUs that never answer. Measured during one: the PPU thread took no CPU at all across eleven minutes while the SPU threads churned two-to-one system time. Both waits are bounded now and the duplicate leaves when the owner has finished and published nothing. --- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 896a2d3b5..20960cf3c 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -1671,6 +1671,15 @@ public: return nullptr; } + // The owner finished and published nothing. It is not coming back, so + // waiting on `compiled` here is waiting forever -- state 2 is set after + // the publication it promises, so seeing it with nothing published means + // there is nothing to wait for. + if (add_loc->llvm_compile_state == 2) + { + return nullptr; + } + add_loc->compiled.wait(nullptr, atomic_wait_timeout{10'000'000}); } @@ -1684,9 +1693,14 @@ public: // of cold compilation work. if (add_loc->llvm_compile_state.compare_and_swap(0, 1) != 0) { + // Bounded, like the duplicate wait above. An untimed wait on a claim is only + // as sound as every path the owner can leave by, and a waiter that misses the + // transition waits for the rest of the session -- SPURS brings all its kernels + // to the same block at once, so it is five threads, and the game sits polling + // for an SPU that will never answer. while (add_loc->llvm_compile_state == 1) { - add_loc->llvm_compile_state.wait(1); + add_loc->llvm_compile_state.wait(1, atomic_wait_timeout{10'000'000}); } if (add_loc->llvm_compile_state == 2)