mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 20:22:30 +01:00
SPU: ensure sys_spu_thread_group_join receives correct exit status
Following #5334
This commit is contained in:
parent
453344c232
commit
cfdf50dcff
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user