mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
Fix vm::writer_lock deadlock-inducing usage on PPU
This commit is contained in:
@@ -1964,8 +1964,15 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
|
||||
// Hack: allocate memory in case the emulator is stopping
|
||||
const auto hack_alloc = [&]()
|
||||
{
|
||||
const bool added_flag = cpu && !cpu->state.test_and_set(cpu_flag::wait);
|
||||
|
||||
if (vm::check_addr(addr, required_page_perms))
|
||||
{
|
||||
if (added_flag)
|
||||
{
|
||||
cpu->check_state();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1973,6 +1980,11 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
|
||||
|
||||
if (!area)
|
||||
{
|
||||
if (added_flag)
|
||||
{
|
||||
cpu->check_state();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1993,6 +2005,11 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
|
||||
{
|
||||
ppu_register_range(addr & -0x10000, 0x10000);
|
||||
}
|
||||
|
||||
if (added_flag)
|
||||
{
|
||||
cpu->check_state();
|
||||
}
|
||||
|
||||
g_tls_access_violation_recovered = addr;
|
||||
return true;
|
||||
@@ -2007,10 +2024,20 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
|
||||
ppu_register_range(addr & -0x10000, 0x10000);
|
||||
}
|
||||
|
||||
if (added_flag)
|
||||
{
|
||||
cpu->check_state();
|
||||
}
|
||||
|
||||
g_tls_access_violation_recovered = addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (added_flag)
|
||||
{
|
||||
cpu->check_state();
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
@@ -2483,6 +2483,9 @@ s32 _spurs::add_workload(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<u32>
|
||||
|
||||
u32 res_wkl;
|
||||
const auto wkl = &spurs->wklInfo(wnum);
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
vm::reservation_op(ppu, vm::unsafe_ptr_cast<spurs_wkl_state_op>(spurs.ptr(&CellSpurs::wklState1)), [&](spurs_wkl_state_op& op)
|
||||
{
|
||||
const u32 mask = op.wklMskB & ~(0x80000000u >> wnum);
|
||||
@@ -2567,6 +2570,8 @@ s32 cellSpursShutdownWorkload(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid
|
||||
if (spurs->exception)
|
||||
return CELL_SPURS_POLICY_MODULE_ERROR_STAT;
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
bool send_event;
|
||||
s32 rc, old_state;
|
||||
if (!vm::reservation_op(ppu, vm::unsafe_ptr_cast<spurs_wkl_state_op>(spurs.ptr(&CellSpurs::wklState1)), [&](spurs_wkl_state_op& op)
|
||||
@@ -3094,6 +3099,8 @@ s32 _cellSpursWorkloadFlagReceiver(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u3
|
||||
|
||||
s32 res = CELL_OK;
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
vm::reservation_op(ppu, vm::unsafe_ptr_cast<wklFlagOp>(spurs), [&](wklFlagOp& val)
|
||||
{
|
||||
if (is_set)
|
||||
@@ -3342,6 +3349,8 @@ s32 cellSpursEventFlagSet(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag
|
||||
u16 pendingRecv;
|
||||
u16 pendingRecvTaskEvents[16];
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
vm::reservation_op(ppu, vm::unsafe_ptr_cast<CellSpursEventFlag_x00>(eventFlag), [bits, &send, &ppuWaitSlot, &ppuEvents, &pendingRecv, &pendingRecvTaskEvents](CellSpursEventFlag_x00& eventFlag)
|
||||
{
|
||||
send = false;
|
||||
@@ -3407,6 +3416,8 @@ s32 cellSpursEventFlagSet(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag
|
||||
//eventFlagControl = ((u64)events << 48) | ((u64)spuTaskPendingRecv << 32) | ((u64)ppuWaitMask << 16) | ((u64)ppuWaitSlotAndMode << 8) | (u64)ppuPendingRecv;
|
||||
});
|
||||
|
||||
static_cast<void>(ppu.test_stopped());
|
||||
|
||||
if (send)
|
||||
{
|
||||
// Signal the PPU thread to be woken up
|
||||
@@ -4257,6 +4268,8 @@ s32 _cellSpursSendSignal(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset, u32
|
||||
|
||||
int signal;
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
vm::reservation_op(ppu, vm::unsafe_ptr_cast<spurs_taskset_signal_op>(taskset), [&](spurs_taskset_signal_op& op)
|
||||
{
|
||||
const u32 signalled = op.signalled[taskId / 32];
|
||||
@@ -4292,6 +4305,8 @@ s32 _cellSpursSendSignal(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset, u32
|
||||
{
|
||||
auto spurs = +taskset->spurs;
|
||||
|
||||
static_cast<void>(ppu.test_stopped());
|
||||
|
||||
ppu_execute<&cellSpursSendWorkloadSignal>(ppu, spurs, +taskset->wid);
|
||||
auto rc = ppu_execute<&cellSpursWakeUp>(ppu, spurs);
|
||||
if (rc + 0u == CELL_SPURS_POLICY_MODULE_ERROR_STAT)
|
||||
@@ -5146,6 +5161,8 @@ s32 cellSpursJobGuardNotify(ppu_thread& ppu, vm::ptr<CellSpursJobGuard> jobGuard
|
||||
u32 allow_jobchain_run = 0; // Affects cellSpursJobChainRun execution
|
||||
u32 old = 0;
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
const bool ok = vm::reservation_op(ppu, vm::unsafe_ptr_cast<CellSpursJobGuard_x00>(jobGuard), [&](CellSpursJobGuard_x00& jg)
|
||||
{
|
||||
allow_jobchain_run = jg.zero;
|
||||
@@ -5170,6 +5187,8 @@ s32 cellSpursJobGuardNotify(ppu_thread& ppu, vm::ptr<CellSpursJobGuard> jobGuard
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
static_cast<void>(ppu.test_stopped());
|
||||
|
||||
auto jobChain = +jobGuard->jobChain;
|
||||
|
||||
if (jobChain->jmVer <= CELL_SPURS_JOB_REVISION_1)
|
||||
@@ -5310,6 +5329,8 @@ s32 cellSpursAddUrgentCommand(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobCha
|
||||
|
||||
s32 result = CELL_OK;
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
vm::reservation_op(ppu, vm::unsafe_ptr_cast<CellSpursJobChain_x00>(jobChain), [&](CellSpursJobChain_x00& jch)
|
||||
{
|
||||
for (auto& cmd : jch.urgentCmds)
|
||||
|
||||
@@ -1291,6 +1291,8 @@ extern bool ppu_patch(u32 addr, u32 value)
|
||||
return false;
|
||||
}
|
||||
|
||||
ensure(!cpu_thread::get_current());
|
||||
|
||||
vm::writer_lock rlock;
|
||||
|
||||
if (!vm::check_addr(addr))
|
||||
@@ -3263,6 +3265,7 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
auto range_lock = vm::alloc_range_lock();
|
||||
bool success = false;
|
||||
{
|
||||
ppu.state += cpu_flag::wait; // for vm::writer_lock
|
||||
rsx::reservation_lock rsx_lock(addr, 128);
|
||||
|
||||
auto& super_data = *vm::get_super_ptr<spu_rdata_t>(addr);
|
||||
@@ -3285,6 +3288,7 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
}
|
||||
vm::free_range_lock(range_lock);
|
||||
|
||||
static_cast<void>(ppu.test_stopped());
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -3670,6 +3670,13 @@ void do_cell_atomic_128_store(u32 addr, const void* to_write)
|
||||
|
||||
// Hard lock
|
||||
auto spu = cpu ? cpu->try_get<spu_thread>() : nullptr;
|
||||
|
||||
if (!spu && cpu)
|
||||
{
|
||||
// For vm::writer_lock
|
||||
cpu->state += cpu_flag::wait;
|
||||
}
|
||||
|
||||
vm::writer_lock lock(addr, spu ? spu->range_lock : nullptr);
|
||||
mov_rdata(sdata, *static_cast<const spu_rdata_t*>(to_write));
|
||||
vm::reservation_acquire(addr) += 32;
|
||||
|
||||
@@ -28,6 +28,7 @@ error_code sys_dbg_read_process_memory(s32 pid, u32 address, u32 size, vm::ptr<v
|
||||
return CELL_LV2DBG_ERROR_DEINVALIDARGUMENTS;
|
||||
}
|
||||
|
||||
ensure(cpu_thread::get_current())->state += cpu_flag::wait;
|
||||
vm::writer_lock lock;
|
||||
|
||||
// Check if data destination is writable
|
||||
@@ -74,6 +75,7 @@ error_code sys_dbg_write_process_memory(s32 pid, u32 address, u32 size, vm::cptr
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
ensure(cpu_thread::get_current())->state += cpu_flag::wait;
|
||||
vm::writer_lock lock;
|
||||
|
||||
// Again
|
||||
|
||||
@@ -255,8 +255,10 @@ CellError process_is_spu_lock_line_reservation_address(u32 addr, u64 flags)
|
||||
return {};
|
||||
}
|
||||
|
||||
error_code sys_process_is_spu_lock_line_reservation_address(u32 addr, u64 flags)
|
||||
error_code sys_process_is_spu_lock_line_reservation_address(ppu_thread& ppu, u32 addr, u64 flags)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
sys_process.warning("sys_process_is_spu_lock_line_reservation_address(addr=0x%x, flags=0x%llx)", addr, flags);
|
||||
|
||||
if (auto err = process_is_spu_lock_line_reservation_address(addr, flags))
|
||||
|
||||
@@ -98,6 +98,8 @@ struct ps3_process_info_t
|
||||
|
||||
extern ps3_process_info_t g_ps3_process_info;
|
||||
|
||||
class ppu_thread;
|
||||
|
||||
// Auxiliary functions
|
||||
s32 process_getpid();
|
||||
s32 process_get_sdk_version(u32 pid, s32& ver);
|
||||
@@ -115,7 +117,7 @@ error_code sys_process_get_id2(u32 object, vm::ptr<u32> buffer, u32 size, vm::pt
|
||||
error_code _sys_process_get_paramsfo(vm::ptr<char> buffer);
|
||||
error_code sys_process_get_sdk_version(u32 pid, vm::ptr<s32> version);
|
||||
error_code sys_process_get_status(u64 unk);
|
||||
error_code sys_process_is_spu_lock_line_reservation_address(u32 addr, u64 flags);
|
||||
error_code sys_process_is_spu_lock_line_reservation_address(ppu_thread& ppu, u32 addr, u64 flags);
|
||||
error_code sys_process_kill(u32 pid);
|
||||
error_code sys_process_wait_for_child(u32 pid, vm::ptr<u32> status, u64 unk);
|
||||
error_code sys_process_wait_for_child2(u64 unk1, u64 unk2, u64 unk3, u64 unk4, u64 unk5, u64 unk6);
|
||||
|
||||
+13
-31
@@ -414,20 +414,6 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
void passive_unlock(cpu_thread& cpu)
|
||||
{
|
||||
if (auto& ptr = g_tls_locked)
|
||||
{
|
||||
ptr->release(nullptr);
|
||||
ptr = nullptr;
|
||||
|
||||
if (cpu.state & cpu_flag::memory)
|
||||
{
|
||||
cpu.state -= cpu_flag::memory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool temporary_unlock(cpu_thread& cpu) noexcept
|
||||
{
|
||||
bs_t<cpu_flag> add_state = cpu_flag::wait;
|
||||
@@ -437,6 +423,8 @@ namespace vm
|
||||
add_state += cpu_flag::memory;
|
||||
}
|
||||
|
||||
g_tls_locked = nullptr;
|
||||
|
||||
if (add_state - cpu.state)
|
||||
{
|
||||
cpu.state += add_state;
|
||||
@@ -462,20 +450,19 @@ namespace vm
|
||||
writer_lock::writer_lock(u32 const addr, atomic_t<u64, 128>* range_lock, u32 const size, u64 const flags) noexcept
|
||||
: range_lock(range_lock)
|
||||
{
|
||||
cpu_thread* cpu{};
|
||||
|
||||
if (g_tls_locked)
|
||||
if (cpu_thread* cpu = cpu_thread::get_current(); cpu && cpu->get_class() == thread_class::ppu)
|
||||
{
|
||||
cpu = get_current_cpu_thread();
|
||||
AUDIT(cpu);
|
||||
|
||||
if (*g_tls_locked != cpu || cpu->state & cpu_flag::wait)
|
||||
// cpu_flag::wait must be added by the caller
|
||||
// We cannot manage it internally within vm::writer_lock
|
||||
// Because in doing that, cpu_thread::check_state() needs to be called
|
||||
// Which may not be suitable for the code that writer_lock is used at
|
||||
if (!(cpu->state & cpu_flag::wait))
|
||||
{
|
||||
cpu = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu->state += cpu_flag::wait;
|
||||
// If lock is not set than it is technically fine, though a bit odd for usage
|
||||
if (g_tls_locked)
|
||||
{
|
||||
fmt::throw_exception("vm::writer_lock is being used without cpu_flag::wait set by the caller!\nPlease report to the developers.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,11 +590,6 @@ namespace vm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu)
|
||||
{
|
||||
cpu->state -= cpu_flag::memory + cpu_flag::wait;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_t<u32>* reservation_notifier_notify(u32 raddr, u64 rtime, bool postpone)
|
||||
|
||||
@@ -82,9 +82,6 @@ namespace vm
|
||||
// Release it
|
||||
void free_range_lock(atomic_t<u64, 128>*) noexcept;
|
||||
|
||||
// Unregister reader
|
||||
void passive_unlock(cpu_thread& cpu);
|
||||
|
||||
// Optimization (set cpu_flag::memory)
|
||||
bool temporary_unlock(cpu_thread& cpu) noexcept;
|
||||
void temporary_unlock() noexcept;
|
||||
|
||||
Reference in New Issue
Block a user