1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

SPU: ensure sys_spu_thread_group_join receives correct exit status

Following #5334
This commit is contained in:
Nekotekina 2018-12-25 20:23:03 +03:00
parent 453344c232
commit cfdf50dcff
3 changed files with 27 additions and 12 deletions

View File

@ -487,9 +487,16 @@ void spu_thread::cpu_stop()
if (verify(HERE, group->running--) == 1)
{
{
group->stop_count++;
std::lock_guard lock(group->mutex);
group->stop_count++;
group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
if (const auto ppu = std::exchange(group->waiter, nullptr))
{
// Send exit status directly to the joining thread
ppu->gpr[4] = group->join_state;
ppu->gpr[5] = group->exit_status;
}
}
// Notify on last thread stopped

View File

@ -633,9 +633,7 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
return CELL_ESRCH;
}
u32 join_state = 0;
s32 exit_value = 0;
do
{
std::unique_lock lock(group->mutex);
@ -644,12 +642,25 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
return CELL_ESTAT;
}
if (group->join_state.fetch_or(SPU_TGJSF_IS_JOINING) & SPU_TGJSF_IS_JOINING)
if (group->waiter)
{
// another PPU thread is joining this thread group
return CELL_EBUSY;
}
if (group->run_state == SPU_THREAD_GROUP_STATUS_INITIALIZED)
{
// Already terminated
ppu.gpr[4] = group->join_state;
ppu.gpr[5] = group->exit_status;
break;
}
else
{
// Subscribe to receive status in r4-r5
group->waiter = &ppu;
}
const u64 last_stop = group->stop_count - !group->running;
lv2_obj::sleep(ppu);
@ -663,18 +674,15 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
group->cond.wait(lock);
}
join_state = group->join_state;
exit_value = group->exit_status;
group->join_state &= ~SPU_TGJSF_IS_JOINING;
}
while (0);
if (ppu.test_stopped())
{
return 0;
}
switch (join_state & ~SPU_TGJSF_IS_JOINING)
switch (ppu.gpr[4] & (SPU_TGJSF_GROUP_EXIT | SPU_TGJSF_TERMINATED))
{
case 0:
{
@ -699,7 +707,7 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
if (status)
{
*status = group->exit_status;
*status = static_cast<s32>(ppu.gpr[5]);
}
return CELL_OK;

View File

@ -210,7 +210,6 @@ enum : u32
// SPU Thread Group Join State Flag
enum : u32
{
SPU_TGJSF_IS_JOINING = (1 << 0),
SPU_TGJSF_TERMINATED = (1 << 1), // set if SPU Thread Group is terminated by sys_spu_thread_group_terminate
SPU_TGJSF_GROUP_EXIT = (1 << 2), // set if SPU Thread Group is terminated by sys_spu_thread_group_exit
};
@ -237,6 +236,7 @@ struct lv2_spu_group
atomic_t<u32> running; // Number of running threads
cond_variable cond; // used to signal waiting PPU thread
atomic_t<u64> stop_count;
class ppu_thread* waiter = nullptr;
std::array<std::shared_ptr<named_thread<spu_thread>>, 256> threads; // SPU Threads
std::array<std::pair<sys_spu_image, std::vector<sys_spu_segment>>, 256> imgs; // SPU Images