From d86c9a254974806e78c3a234c985fd1be9ac7fa9 Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 21 May 2020 19:47:47 +0300 Subject: [PATCH] sys_mmapper: rewrite page fault thread notifications * Fix a corner case where SPU thread has the same ID as a PPU thread. * Fix a potential deadlock on Emu.Stop() while sending event in EBUSY loop. * Thread specific notifications. --- Utilities/Thread.cpp | 40 +++++++++++++-------------- rpcs3/Emu/Cell/lv2/sys_mmapper.cpp | 15 ++++++++-- rpcs3/Emu/Cell/lv2/sys_mmapper.h | 7 ++--- rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp | 4 +-- rpcs3/Emu/Cell/lv2/sys_spu.cpp | 4 +-- 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index a3ae3212e1..f6d5158ed7 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1442,13 +1442,19 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no } } + // Deschedule + if (cpu->id_type() == 1) + { + lv2_obj::sleep(*cpu); + } + // Now, place the page fault event onto table so that other functions [sys_mmapper_free_address and pagefault recovery funcs etc] // know that this thread is page faulted and where. auto pf_events = g_fxo->get(); { std::lock_guard pf_lock(pf_events->pf_mutex); - pf_events->events.emplace(static_cast(data2), addr); + pf_events->events.emplace(cpu, addr); } sig_log.warning("Page_fault %s location 0x%x because of %s memory", is_writing ? "writing" : "reading", @@ -1467,38 +1473,32 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no // If we fail due to being busy, wait a bit and try again. while (static_cast(sending_error) == CELL_EBUSY) { - if (cpu->id_type() == 1) + if (cpu->is_stopped()) { - lv2_obj::sleep(*cpu, 1000); + sending_error = {}; + break; } thread_ctrl::wait_for(1000); sending_error = sys_event_port_send(pf_port_id, data1, data2, data3); } - if (cpu->id_type() == 1) - { - // Deschedule - lv2_obj::sleep(*cpu); - } - if (sending_error) { - vm_log.fatal("Unknown error %x while trying to pass page fault.", +sending_error); - cpu->state += cpu_flag::dbg_pause; + vm_log.fatal("Unknown error 0x%x while trying to pass page fault.", +sending_error); } - - // Wait until the thread is recovered - for (std::shared_lock pf_lock(pf_events->pf_mutex); - pf_events->events.count(static_cast(data2)) && !sending_error;) + else { - if (cpu->is_stopped()) + // Wait until the thread is recovered + while (!cpu->state.test_and_reset(cpu_flag::signal)) { - break; - } + if (cpu->is_stopped()) + { + break; + } - // Timeout in case the emulator is stopping - pf_events->cond.wait(pf_lock, 10000); + thread_ctrl::wait(); + } } // Reschedule, test cpu state and try recovery if stopped diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index f25fa24387..a665a5ace6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -739,13 +739,13 @@ error_code sys_mmapper_enable_page_fault_notification(ppu_thread& ppu, u32 start return CELL_OK; } -error_code mmapper_thread_recover_page_fault(u32 id) +error_code mmapper_thread_recover_page_fault(cpu_thread* cpu) { // We can only wake a thread if it is being suspended for a page fault. auto pf_events = g_fxo->get(); { std::lock_guard pf_lock(pf_events->pf_mutex); - auto pf_event_ind = pf_events->events.find(id); + const auto pf_event_ind = pf_events->events.find(cpu); if (pf_event_ind == pf_events->events.end()) { @@ -756,6 +756,15 @@ error_code mmapper_thread_recover_page_fault(u32 id) pf_events->events.erase(pf_event_ind); } - pf_events->cond.notify_all(); + if (cpu->id_type() == 1u) + { + lv2_obj::awake(cpu); + } + else + { + cpu->state += cpu_flag::signal; + cpu->notify(); + } + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.h b/rpcs3/Emu/Cell/lv2/sys_mmapper.h index 85579c25b5..053b920a40 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.h +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -58,10 +58,9 @@ struct page_fault_notification_entries struct page_fault_event_entries { - // First = thread id, second = addr - std::unordered_map events; + // First = thread, second = addr + std::unordered_map events; shared_mutex pf_mutex; - cond_variable cond; }; struct mmapper_unk_entry_struct0 @@ -76,7 +75,7 @@ struct mmapper_unk_entry_struct0 // Aux class ppu_thread; -error_code mmapper_thread_recover_page_fault(u32 id); +error_code mmapper_thread_recover_page_fault(cpu_thread* cpu); // SysCalls error_code sys_mmapper_allocate_address(ppu_thread&, u64 size, u64 flags, u64 alignment, vm::ptr alloc_addr); diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 078a183841..bf10615aba 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -551,7 +551,7 @@ error_code sys_ppu_thread_recover_page_fault(u32 thread_id) return CELL_ESRCH; } - return mmapper_thread_recover_page_fault(thread_id); + return mmapper_thread_recover_page_fault(thread.ptr.get()); } error_code sys_ppu_thread_get_page_fault_context(u32 thread_id, vm::ptr ctxt) @@ -572,7 +572,7 @@ error_code sys_ppu_thread_get_page_fault_context(u32 thread_id, vm::ptrget(); std::shared_lock lock(pf_events->pf_mutex); - const auto evt = pf_events->events.find(thread_id); + const auto evt = pf_events->events.find(thread.ptr.get()); if (evt == pf_events->events.end()) { return CELL_EINVAL; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index a9a24a0745..ba67c6c77d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -1790,7 +1790,7 @@ error_code sys_spu_thread_recover_page_fault(ppu_thread& ppu, u32 id) return CELL_ESRCH; } - return mmapper_thread_recover_page_fault(id); + return mmapper_thread_recover_page_fault(thread); } error_code sys_raw_spu_recover_page_fault(ppu_thread& ppu, u32 id) @@ -1806,7 +1806,7 @@ error_code sys_raw_spu_recover_page_fault(ppu_thread& ppu, u32 id) return CELL_ESRCH; } - return mmapper_thread_recover_page_fault(id); + return mmapper_thread_recover_page_fault(thread.get()); } error_code sys_raw_spu_create(ppu_thread& ppu, vm::ptr id, vm::ptr attr)