mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-26 04:32:35 +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)
|
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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user