Files
PS2Recomp/ps2xRuntime/include/runtime
Shane Michael Mathews (Personal Account) 61621b8313 fix(runtime): make GS CSR atomic to fix vsync-worker/guest data race (#145)
updateGsCsrFieldForVSync runs on the detached vsync worker and updated the
FIELD bit with a non-atomic read-modify-write of GSRegisters::csr while
guest threads concurrently read/write the same word (MMIO read32/read64 and
the W1C handling in write32/write64) and the GIF path sets SIGNAL/FINISH.
Even though the writers touch disjoint bits, a whole-word RMW loses the
other side's update: a clobbered SIGNAL/FINISH set hangs a game
synchronizing on GS completion, a clobbered W1C clear re-asserts a handled
interrupt, and a clobbered FIELD toggle stalls interlace field polling.
ThreadSanitizer flags the race on main (updateGsCsrFieldForVSync vs
PS2Memory::write64 and GS::writeRegister).

Make the field std::atomic<uint64_t> and perform every update as a single
atomic RMW:

- vsync FIELD toggle -> fetch_or / fetch_and
- MMIO W1C writes -> compare_exchange loop in shared helpers (a
  load-then-store pair would still race); a 32-bit store to the CSR's upper
  dword previously bypassed the W1C special case entirely and went through
  the plain merge branch - both halves now share the same atomic helper
  with unchanged guest-visible semantics
- GIF SIGNAL/FINISH -> fetch_or
- reads -> load()

std::atomic<uint64_t> is lock-free on all supported targets (static_assert
added), the struct's size/alignment asserts are unchanged, GSRegisters is
never copied by value, and default (seq_cst) ordering is used throughout -
these operations are rare (vblank ticks, GIF signals, CSR MMIO), so
reviewability wins over micro-optimization.

New regression test: two racer threads each own one status bit (SIGNAL /
FINISH) and loop 80k GIF-set + W1C-clear cycles verifying their own bit
after each half-op while the vsync worker toggles FIELD. Fails 20/20 runs
against the previous code, passes 50/50 with the fix, ~350ms runtime, no
sanitizer needed.
2026-07-06 12:35:44 -03:00
..
2026-06-26 21:04:39 -03:00
2026-06-21 00:07:26 -03:00
2026-06-26 21:04:39 -03:00
2026-06-26 21:04:39 -03:00
2026-06-26 21:04:39 -03:00
2026-06-26 21:04:39 -03:00
2026-06-26 21:04:39 -03:00
2026-06-26 21:04:39 -03:00