1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 10:42: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) if (verify(HERE, group->running--) == 1)
{ {
{ {
group->stop_count++;
std::lock_guard lock(group->mutex); std::lock_guard lock(group->mutex);
group->stop_count++;
group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; 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 // 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; return CELL_ESRCH;
} }
u32 join_state = 0; do
s32 exit_value = 0;
{ {
std::unique_lock lock(group->mutex); 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; 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 // another PPU thread is joining this thread group
return CELL_EBUSY; 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; const u64 last_stop = group->stop_count - !group->running;
lv2_obj::sleep(ppu); 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); 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()) if (ppu.test_stopped())
{ {
return 0; return 0;
} }
switch (join_state & ~SPU_TGJSF_IS_JOINING) switch (ppu.gpr[4] & (SPU_TGJSF_GROUP_EXIT | SPU_TGJSF_TERMINATED))
{ {
case 0: case 0:
{ {
@ -699,7 +707,7 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
if (status) if (status)
{ {
*status = group->exit_status; *status = static_cast<s32>(ppu.gpr[5]);
} }
return CELL_OK; return CELL_OK;

View File

@ -210,7 +210,6 @@ enum : u32
// SPU Thread Group Join State Flag // SPU Thread Group Join State Flag
enum : u32 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_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 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 atomic_t<u32> running; // Number of running threads
cond_variable cond; // used to signal waiting PPU thread cond_variable cond; // used to signal waiting PPU thread
atomic_t<u64> stop_count; 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::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 std::array<std::pair<sys_spu_image, std::vector<sys_spu_segment>>, 256> imgs; // SPU Images