Make sys_spu_thread_group_join return once per termination

This commit is contained in:
eladash 2019-02-08 19:23:49 +02:00 committed by Ivan
parent 19ff95da70
commit e3ee481f01
3 changed files with 16 additions and 35 deletions

View file

@ -521,6 +521,11 @@ void spu_thread::cpu_stop()
group->stop_count++; group->stop_count++;
group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
if (!group->join_state)
{
group->join_state = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
}
if (const auto ppu = std::exchange(group->waiter, nullptr)) if (const auto ppu = std::exchange(group->waiter, nullptr))
{ {
// Send exit status directly to the joining thread // Send exit status directly to the joining thread
@ -2436,7 +2441,7 @@ bool spu_thread::stop_and_signal(u32 code)
} }
group->exit_status = value; group->exit_status = value;
group->join_state |= SPU_TGJSF_GROUP_EXIT; group->join_state = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT;
state += cpu_flag::stop; state += cpu_flag::stop;
return true; return true;

View file

@ -607,7 +607,7 @@ error_code sys_spu_thread_group_terminate(u32 id, s32 value)
} }
group->exit_status = value; group->exit_status = value;
group->join_state |= SPU_TGJSF_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 - !group->running; const u64 last_stop = group->stop_count - !group->running;
@ -648,11 +648,12 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
return CELL_EBUSY; return CELL_EBUSY;
} }
if (group->run_state == SPU_THREAD_GROUP_STATUS_INITIALIZED) if (group->join_state)
{ {
// Already terminated // Already signaled
ppu.gpr[4] = group->join_state; ppu.gpr[4] = group->join_state;
ppu.gpr[5] = group->exit_status; ppu.gpr[5] = group->exit_status;
group->join_state.release(0);
break; break;
} }
else else
@ -661,11 +662,9 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
group->waiter = &ppu; group->waiter = &ppu;
} }
const u64 last_stop = group->stop_count - !group->running;
lv2_obj::sleep(ppu); lv2_obj::sleep(ppu);
while (group->stop_count == last_stop) while (!group->join_state)
{ {
if (ppu.is_stopped()) if (ppu.is_stopped())
{ {
@ -674,6 +673,8 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
group->cond.wait(lock); group->cond.wait(lock);
} }
group->join_state.release(0);
} }
while (0); while (0);
@ -682,27 +683,9 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
return 0; return 0;
} }
switch (ppu.gpr[4] & (SPU_TGJSF_GROUP_EXIT | SPU_TGJSF_TERMINATED)) if (cause)
{ {
case 0: *cause = static_cast<u32>(ppu.gpr[4]);
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
break;
}
case SPU_TGJSF_GROUP_EXIT:
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT;
break;
}
case SPU_TGJSF_TERMINATED:
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED;
break;
}
default:
{
fmt::throw_exception("Unexpected join_state" HERE);
}
} }
if (status) if (status)

View file

@ -207,13 +207,6 @@ enum : u32
SYS_SPU_IMAGE_DIRECT = 1, SYS_SPU_IMAGE_DIRECT = 1,
}; };
// SPU Thread Group Join State Flag
enum : u32
{
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
};
struct lv2_spu_group struct lv2_spu_group
{ {
static const u32 id_base = 1; // Wrong? static const u32 id_base = 1; // Wrong?
@ -232,7 +225,7 @@ struct lv2_spu_group
atomic_t<s32> prio; // SPU Thread Group Priority atomic_t<s32> prio; // SPU Thread Group Priority
atomic_t<u32> run_state; // SPU Thread Group State atomic_t<u32> run_state; // SPU Thread Group State
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 atomic_t<u32> join_state; // flags used to detect exit cause and signal
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;