sys_spu: Fix warning and theoretical bug

This commit is contained in:
Eladash 2024-01-01 08:35:37 +02:00 committed by Elad Ashkenazi
parent 9455bfe6c2
commit f0c93ae9dc
3 changed files with 26 additions and 4 deletions

View file

@ -1603,6 +1603,7 @@ void spu_thread::cpu_return()
if (ensure(group->running)-- == 1) if (ensure(group->running)-- == 1)
{ {
u32 last_stop = 0;
{ {
lv2_obj::notify_all_t notify; lv2_obj::notify_all_t notify;
std::lock_guard lock(group->mutex); std::lock_guard lock(group->mutex);
@ -1632,7 +1633,17 @@ void spu_thread::cpu_return()
exit_status.set_value(last_exit_status); exit_status.set_value(last_exit_status);
} }
group->stop_count++; last_stop = group->stop_count;
if (last_stop == umax)
{
// Restart with some high count to preserve some meaning
group->stop_count = 1000;
}
else
{
group->stop_count++;
}
if (const auto ppu = std::exchange(group->waiter, nullptr)) if (const auto ppu = std::exchange(group->waiter, nullptr))
{ {
@ -1646,6 +1657,12 @@ void spu_thread::cpu_return()
// Notify on last thread stopped // Notify on last thread stopped
group->stop_count.notify_all(); group->stop_count.notify_all();
// Wait for terminators manually if needed (ensuring they quit before value-wrapping)
while (last_stop == umax && group->wait_term_count)
{
std::this_thread::yield();
}
} }
else if (status_npc.load().status >> 16 == SYS_SPU_THREAD_STOP_THREAD_EXIT) else if (status_npc.load().status >> 16 == SYS_SPU_THREAD_STOP_THREAD_EXIT)
{ {

View file

@ -1352,7 +1352,8 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value)
if (group->set_terminate) if (group->set_terminate)
{ {
// Wait for termination, only then return error code // Wait for termination, only then return error code
const u64 last_stop = group->stop_count; const u32 last_stop = group->stop_count;
group->wait_term_count++;
lock.unlock(); lock.unlock();
short_sleep(ppu); short_sleep(ppu);
@ -1361,6 +1362,7 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value)
group->stop_count.wait(last_stop); group->stop_count.wait(last_stop);
} }
group->wait_term_count--;
return CELL_ESTAT; return CELL_ESTAT;
} }
@ -1414,7 +1416,8 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value)
group->join_state = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED; group->join_state = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED;
// Wait until the threads are actually stopped // Wait until the threads are actually stopped
const u64 last_stop = group->stop_count; const u32 last_stop = group->stop_count;
group->wait_term_count++;
lock.unlock(); lock.unlock();
short_sleep(ppu); short_sleep(ppu);
@ -1423,6 +1426,7 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value)
group->stop_count.wait(last_stop); group->stop_count.wait(last_stop);
} }
group->wait_term_count--;
return CELL_OK; return CELL_OK;
} }

View file

@ -289,7 +289,8 @@ struct lv2_spu_group
atomic_t<s32> exit_status; // SPU Thread Group Exit Status atomic_t<s32> exit_status; // SPU Thread Group Exit Status
atomic_t<u32> join_state; // flags used to detect exit cause and signal atomic_t<u32> join_state; // flags used to detect exit cause and signal
atomic_t<u32> running = 0; // Number of running threads atomic_t<u32> running = 0; // Number of running threads
atomic_t<u64> stop_count = 0; atomic_t<u32> stop_count = 0;
atomic_t<u32> wait_term_count = 0;
u32 waiter_spu_index = -1; // Index of SPU executing a waiting syscall u32 waiter_spu_index = -1; // Index of SPU executing a waiting syscall
class ppu_thread* waiter = nullptr; class ppu_thread* waiter = nullptr;
bool set_terminate = false; bool set_terminate = false;