sys_spu: Improve sys_spu_thread_get_exit_status

This commit is contained in:
Eladash 2020-05-09 19:49:12 +03:00 committed by Ani
parent 14969cd8d0
commit 09797c3584
4 changed files with 46 additions and 14 deletions

View file

@ -991,6 +991,12 @@ void spu_thread::cpu_stop()
group->join_state = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
}
if (status_npc.load().status >> 16 == SYS_SPU_THREAD_STOP_THREAD_EXIT)
{
// Set exit status now, in conjunction with group state changes
exit_status.set_value(last_exit_status);
}
if (const auto ppu = std::exchange(group->waiter, nullptr))
{
// Send exit status directly to the joining thread
@ -1003,6 +1009,10 @@ void spu_thread::cpu_stop()
// Notify on last thread stopped
group->cond.notify_all();
}
else if (status_npc.load().status >> 16 == SYS_SPU_THREAD_STOP_THREAD_EXIT)
{
exit_status.set_value(last_exit_status);
}
}
}
@ -2737,10 +2747,8 @@ bool spu_thread::stop_and_signal(u32 code)
{
spu_log.trace("stop_and_signal(code=0x%x)", code);
if (offset >= RAW_SPU_BASE_ADDR)
auto set_status_npc = [&]()
{
// Save next PC and current SPU Interrupt Status
state += cpu_flag::stop + cpu_flag::wait;
status_npc.atomic_op([&](status_npc_sync_var& state)
{
state.status = (state.status & 0xffff) | (code << 16);
@ -2748,6 +2756,13 @@ bool spu_thread::stop_and_signal(u32 code)
state.status &= ~SPU_STATUS_RUNNING;
state.npc = (pc + 4) | +interrupts_enabled;
});
};
if (offset >= RAW_SPU_BASE_ADDR)
{
// Save next PC and current SPU Interrupt Status
state += cpu_flag::stop + cpu_flag::wait;
set_status_npc();
status_npc.notify_one();
@ -2810,7 +2825,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true;
}
case 0x110:
case SYS_SPU_THREAD_STOP_RECEIVE_EVENT:
{
/* ===== sys_spu_thread_receive_event ===== */
@ -2977,7 +2992,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true;
}
case 0x111:
case SYS_SPU_THREAD_STOP_TRY_RECEIVE_EVENT:
{
/* ===== sys_spu_thread_tryreceive_event ===== */
@ -3037,7 +3052,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true;
}
case 0x100:
case SYS_SPU_THREAD_STOP_YIELD:
{
// SPU thread group yield (TODO)
if (ch_out_mbox.get_count())
@ -3049,7 +3064,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true;
}
case 0x101:
case SYS_SPU_THREAD_STOP_GROUP_EXIT:
{
/* ===== sys_spu_thread_group_exit ===== */
@ -3098,6 +3113,7 @@ bool spu_thread::stop_and_signal(u32 code)
group->exit_status = value;
group->join_state = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT;
set_status_npc();
break;
}
@ -3106,7 +3122,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true;
}
case 0x102:
case SYS_SPU_THREAD_STOP_THREAD_EXIT:
{
/* ===== sys_spu_thread_exit ===== */
@ -3117,8 +3133,10 @@ bool spu_thread::stop_and_signal(u32 code)
fmt::throw_exception("sys_spu_thread_exit(): Out_MBox is empty" HERE);
}
spu_log.trace("sys_spu_thread_exit(status=0x%x)", ch_out_mbox.get_value());
status_npc = {SPU_STATUS_STOPPED_BY_STOP, 0};
const u32 value = ch_out_mbox.get_value();
spu_log.trace("sys_spu_thread_exit(status=0x%x)", value);
last_exit_status = value;
set_status_npc();
state += cpu_flag::stop;
check_state();
return true;

View file

@ -599,6 +599,8 @@ public:
std::array<std::pair<u32, std::weak_ptr<lv2_event_queue>>, 32> spuq; // Event Queue Keys for SPU Thread
std::weak_ptr<lv2_event_queue> spup[64]; // SPU Ports
spu_channel exit_status{}; // Threaded SPU exit status (not a channel, but the interface fits)
u32 last_exit_status; // Value to be written in exit_status after checking group termination
const u32 index; // SPU index
const u32 offset; // SPU LS offset

View file

@ -453,7 +453,7 @@ error_code sys_spu_thread_set_argument(ppu_thread& ppu, u32 id, vm::ptr<sys_spu_
return CELL_OK;
}
error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr<u32> status)
error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr<s32> status)
{
vm::temporary_unlock(ppu);
@ -466,9 +466,11 @@ error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr<u32>
return CELL_ESRCH;
}
if (thread->status_npc.load().status & SPU_STATUS_STOPPED_BY_STOP)
const u64 exit_status = thread->exit_status.data.load();
if (exit_status & spu_channel::bit_count)
{
*status = thread->ch_out_mbox.get_value();
*status = static_cast<s32>(exit_status);
return CELL_OK;
}

View file

@ -68,6 +68,16 @@ enum : s32
SYS_SPU_SEGMENT_TYPE_INFO = 4,
};
enum : u32
{
SYS_SPU_THREAD_STOP_YIELD = 0x0100,
SYS_SPU_THREAD_STOP_GROUP_EXIT = 0x0101,
SYS_SPU_THREAD_STOP_THREAD_EXIT = 0x0102,
SYS_SPU_THREAD_STOP_RECEIVE_EVENT = 0x0110,
SYS_SPU_THREAD_STOP_TRY_RECEIVE_EVENT = 0x0111,
SYS_SPU_THREAD_STOP_SWITCH_SYSTEM_MODULE = 0x0120,
};
struct sys_spu_thread_group_attribute
{
be_t<u32> nsize; // name length including NULL terminator
@ -367,7 +377,7 @@ error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u8
error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 event_type, u8 spup);
error_code sys_spu_thread_bind_queue(ppu_thread&, u32 id, u32 spuq, u32 spuq_num);
error_code sys_spu_thread_unbind_queue(ppu_thread&, u32 id, u32 spuq_num);
error_code sys_spu_thread_get_exit_status(ppu_thread&, u32 id, vm::ptr<u32> status);
error_code sys_spu_thread_get_exit_status(ppu_thread&, u32 id, vm::ptr<s32> status);
error_code sys_spu_thread_recover_page_fault(ppu_thread&, u32 id);
error_code sys_raw_spu_create(ppu_thread&, vm::ptr<u32> id, vm::ptr<void> attr);