From f2997e4c00ef0bd74ac8cd455eae54fed86119c5 Mon Sep 17 00:00:00 2001 From: Eladash Date: Tue, 9 Aug 2022 16:50:27 +0300 Subject: [PATCH] LV2: Fix the most annoying race ever Timeline of the race: 1. The PPU is in SLEEP state. state = suspend. 2. lv2_obj::awake is called on the traced thread and is now in ONPROC state, state = signal. 3. lv2_obj::awake is called by another thread externally with a priority higher than our traced thread and appends it to g_pending. state = suspend + signal. 4. lv2_obj::sleep/set_priority (higering priority) is called on any thread which is in ONPROC. Causing it to enter SLEEP or RUNNING state, while the traced thread is back in queue in ONPROC. state = suspend + signal. 5. The traced thread finally calls lv2_obj::awake on itself, g_pending decrements to 0 and we a have a rescheduling event, after XOR state = 0!!! (no signal) 6. In check_state: cpu_sleep_called is now true and remains this way. 7. Another thread with a higher prioty kicks in and appends the traced thread into g_pending. state = suspend. 8. The traced thread is at cpu_thread::cpu_wait(), and that's where it's gonna spend the rest of its life. --- rpcs3/Emu/Cell/lv2/lv2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 08294949a0..e3333532f0 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -1592,7 +1592,7 @@ void lv2_obj::schedule_all(u64 current_time) if (target->state & cpu_flag::suspend) { ppu_log.trace("schedule(): %s", target->id); - target->state ^= (cpu_flag::signal + cpu_flag::suspend); + target->state.atomic_op(FN(x += cpu_flag::signal, x -= cpu_flag::suspend)); target->start_time = 0; if (notify_later_idx == std::size(g_to_notify))