diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index fe9bda7676..48bd8bc6c7 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -466,6 +466,7 @@ bool cpu_thread::check_state() noexcept bool cpu_sleep_called = false; bool cpu_flag_memory = false; + bool escape, retval; if (!(state & cpu_flag::wait)) { @@ -474,54 +475,73 @@ bool cpu_thread::check_state() noexcept while (true) { - if (state & cpu_flag::memory) + // Process all flags in a single atomic op + const auto state0 = state.fetch_op([&](bs_t& flags) { - if (auto& ptr = vm::g_tls_locked) + bool store = false; + + if (flags & cpu_flag::signal) { - ptr->compare_and_swap(this, nullptr); - ptr = nullptr; + flags -= cpu_flag::signal; + cpu_sleep_called = false; + store = true; } - cpu_flag_memory = true; - state -= cpu_flag::memory; - } - - if (state & (cpu_flag::exit + cpu_flag::dbg_global_stop)) - { - state += cpu_flag::wait; - return true; - } - - const auto [state0, escape] = state.fetch_op([&](bs_t& flags) - { // Atomically clean wait flag and escape if (!(flags & (cpu_flag::exit + cpu_flag::dbg_global_stop + cpu_flag::ret + cpu_flag::stop))) { // Check pause flags which hold thread inside check_state if (flags & (cpu_flag::pause + cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause)) { - return false; + escape = false; + return store; } - flags -= cpu_flag::wait; + if (flags & cpu_flag::memory) + { + // wait flag will be cleared later (optimization) + cpu_flag_memory = true; + } + else + { + AUDIT(!cpu_flag_memory); + flags -= cpu_flag::wait; + store = true; + } + + retval = false; + } + else + { + cpu_flag_memory = false; + retval = true; } - return true; - }); + if (flags & cpu_flag::dbg_step) + { + flags += cpu_flag::dbg_pause; + flags -= cpu_flag::dbg_step; + store = true; + } - if (state & cpu_flag::signal && state.test_and_reset(cpu_flag::signal)) - { - cpu_sleep_called = false; - } + escape = true; + return store; + }).first; if (escape) { if (cpu_flag_memory) { cpu_mem(); + + if (state & (cpu_flag::pause + cpu_flag::memory)) [[unlikely]] + { + state += cpu_flag::wait; + continue; + } } - break; + return retval; } else if (!cpu_sleep_called && state0 & cpu_flag::suspend) { @@ -540,21 +560,6 @@ bool cpu_thread::check_state() noexcept g_fxo->get()->cpu_suspend_lock.lock_unlock(); } } - - const auto state_ = state.load(); - - if (state_ & (cpu_flag::ret + cpu_flag::stop)) - { - return true; - } - - if (state_ & cpu_flag::dbg_step) - { - state += cpu_flag::dbg_pause; - state -= cpu_flag::dbg_step; - } - - return false; } void cpu_thread::notify() diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 118988fc71..24f4c0651f 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -129,9 +129,30 @@ namespace vm { if (g_tls_locked && *g_tls_locked == &cpu) [[unlikely]] { + if (cpu.state & cpu_flag::wait) + { + while (true) + { + g_mutex.lock_unlock(); + cpu.state -= cpu_flag::wait + cpu_flag::memory; + + if (g_mutex.is_lockable()) [[likely]] + { + return; + } + + cpu.state += cpu_flag::wait; + } + } + return; } + if (cpu.state & cpu_flag::memory) + { + cpu.state -= cpu_flag::memory; + } + if (g_mutex.is_lockable()) [[likely]] { // Optimistic path (hope that mutex is not exclusively locked) @@ -355,7 +376,8 @@ namespace vm for (auto lock = g_locks.cbegin(), end = lock + g_cfg.core.ppu_threads; lock != end; lock++) { - while (*lock) + cpu_thread* ptr; + while ((ptr = *lock) && !(ptr->state & cpu_flag::wait)) { _mm_pause(); }