RawSPU: fix race condition in RunCntl stop request

This commit is contained in:
Eladash 2020-02-19 22:25:53 +02:00 committed by Ivan
parent ef6854ca46
commit c11074a128
3 changed files with 31 additions and 5 deletions

View file

@ -8,6 +8,8 @@
inline void try_start(spu_thread& spu) inline void try_start(spu_thread& spu)
{ {
std::shared_lock lock(spu.run_ctrl_mtx);
if (spu.status_npc.fetch_op([](typename spu_thread::status_npc_sync_var& value) if (spu.status_npc.fetch_op([](typename spu_thread::status_npc_sync_var& value)
{ {
if (value.status & SPU_STATUS_RUNNING) if (value.status & SPU_STATUS_RUNNING)
@ -246,8 +248,24 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
} }
else if (value == SPU_RUNCNTL_STOP_REQUEST) else if (value == SPU_RUNCNTL_STOP_REQUEST)
{ {
// TODO: Wait for the SPU to stop? if (get_current_cpu_thread() == this)
{
// TODO
state += cpu_flag::stop; state += cpu_flag::stop;
return true;
}
std::scoped_lock lock(run_ctrl_mtx);
if (status_npc.load().status & SPU_STATUS_RUNNING)
{
state += cpu_flag::stop;
for (status_npc_sync_var old; (old = status_npc).status & SPU_STATUS_RUNNING;)
{
status_npc.wait(old);
}
}
} }
else else
{ {

View file

@ -1096,7 +1096,7 @@ void spu_thread::cpu_stop()
{ {
if (!group && offset >= RAW_SPU_BASE_ADDR) if (!group && offset >= RAW_SPU_BASE_ADDR)
{ {
status_npc.fetch_op([this](status_npc_sync_var& state) if (status_npc.fetch_op([this](status_npc_sync_var& state)
{ {
if (state.status & SPU_STATUS_RUNNING) if (state.status & SPU_STATUS_RUNNING)
{ {
@ -1108,7 +1108,10 @@ void spu_thread::cpu_stop()
} }
return false; return false;
}); }).second)
{
status_npc.notify_one();
}
} }
else if (group && is_stopped()) else if (group && is_stopped())
{ {
@ -2842,6 +2845,8 @@ bool spu_thread::stop_and_signal(u32 code)
state.npc = (pc + 4) | +interrupts_enabled; state.npc = (pc + 4) | +interrupts_enabled;
}); });
status_npc.notify_one();
int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT); int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT);
check_state(); check_state();
return true; return true;
@ -3196,6 +3201,8 @@ void spu_thread::halt()
state.npc = pc | +interrupts_enabled; state.npc = pc | +interrupts_enabled;
}); });
status_npc.notify_one();
int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT); int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT);
spu_runtime::g_escape(this); spu_runtime::g_escape(this);

View file

@ -580,6 +580,7 @@ public:
u32 ch_dec_value; // written decrementer value u32 ch_dec_value; // written decrementer value
atomic_t<u32> run_ctrl; // SPU Run Control register (only provided to get latest data written) atomic_t<u32> run_ctrl; // SPU Run Control register (only provided to get latest data written)
shared_mutex run_ctrl_mtx;
struct alignas(8) status_npc_sync_var struct alignas(8) status_npc_sync_var
{ {