SPU: Fix minor race in sys_spu_thread_receive_event

Check final cpu_state::state value for suspend state because that's the variable the thread waits on.
This commit is contained in:
Eladash 2022-08-11 17:40:11 +03:00 committed by Ivan
parent 9a981b5292
commit a3007e11ca

View file

@ -4778,12 +4778,10 @@ bool spu_thread::stop_and_signal(u32 code)
while (true) while (true)
{ {
// Check group status, wait if necessary // Check group status (by actually checking thread status), wait if necessary
for (auto _state = +group->run_state; while (true)
_state >= SPU_THREAD_GROUP_STATUS_WAITING && _state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED;
_state = group->run_state)
{ {
const auto old = state.load(); const auto old = +state;
if (is_stopped(old)) if (is_stopped(old))
{ {
@ -4791,7 +4789,13 @@ bool spu_thread::stop_and_signal(u32 code)
return false; return false;
} }
thread_ctrl::wait_on(state, old);; if (!is_paused(old))
{
// The group is not suspended (anymore)
break;
}
thread_ctrl::wait_on(state, old);
} }
reader_lock{group->mutex}, queue = get_queue(spuq); reader_lock{group->mutex}, queue = get_queue(spuq);
@ -4819,6 +4823,7 @@ bool spu_thread::stop_and_signal(u32 code)
if (group->run_state >= SPU_THREAD_GROUP_STATUS_WAITING && group->run_state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED) if (group->run_state >= SPU_THREAD_GROUP_STATUS_WAITING && group->run_state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED)
{ {
// Try again // Try again
ensure(state & cpu_flag::suspend);
continue; continue;
} }
@ -4989,19 +4994,25 @@ bool spu_thread::stop_and_signal(u32 code)
while (true) while (true)
{ {
for (auto _state = +group->run_state; // Check group status (by actually checking thread status), wait if necessary
_state >= SPU_THREAD_GROUP_STATUS_WAITING && _state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED; while (true)
_state = group->run_state)
{ {
const auto old = +state; const auto old = +state;
if (is_stopped(old)) if (is_stopped(old))
{ {
ch_out_mbox.set_value(value); ch_out_mbox.set_value(value);
state += cpu_flag::again;
return false; return false;
} }
thread_ctrl::wait_on(state, old);; if (!is_paused(old))
{
// The group is not suspended (anymore)
break;
}
thread_ctrl::wait_on(state, old);
} }
std::lock_guard lock(group->mutex); std::lock_guard lock(group->mutex);