mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 04:02:42 +01:00
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.
This commit is contained in:
parent
249686708c
commit
d86c9a2549
@ -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<page_fault_event_entries>();
|
||||
{
|
||||
std::lock_guard pf_lock(pf_events->pf_mutex);
|
||||
pf_events->events.emplace(static_cast<u32>(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<u32>(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);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Wait until the thread is recovered
|
||||
for (std::shared_lock pf_lock(pf_events->pf_mutex);
|
||||
pf_events->events.count(static_cast<u32>(data2)) && !sending_error;)
|
||||
while (!cpu->state.test_and_reset(cpu_flag::signal))
|
||||
{
|
||||
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
|
||||
|
@ -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<page_fault_event_entries>();
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -58,10 +58,9 @@ struct page_fault_notification_entries
|
||||
|
||||
struct page_fault_event_entries
|
||||
{
|
||||
// First = thread id, second = addr
|
||||
std::unordered_map<u32, u32> events;
|
||||
// First = thread, second = addr
|
||||
std::unordered_map<class cpu_thread*, u32> 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<u32> alloc_addr);
|
||||
|
@ -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<sys_ppu_thread_icontext_t> ctxt)
|
||||
@ -572,7 +572,7 @@ error_code sys_ppu_thread_get_page_fault_context(u32 thread_id, vm::ptr<sys_ppu_
|
||||
auto pf_events = g_fxo->get<page_fault_event_entries>();
|
||||
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;
|
||||
|
@ -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<u32> id, vm::ptr<void> attr)
|
||||
|
Loading…
Reference in New Issue
Block a user