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; 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)) 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
@ -1003,6 +1009,10 @@ void spu_thread::cpu_stop()
// Notify on last thread stopped // Notify on last thread stopped
group->cond.notify_all(); 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); 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) status_npc.atomic_op([&](status_npc_sync_var& state)
{ {
state.status = (state.status & 0xffff) | (code << 16); 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.status &= ~SPU_STATUS_RUNNING;
state.npc = (pc + 4) | +interrupts_enabled; 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(); status_npc.notify_one();
@ -2810,7 +2825,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true; return true;
} }
case 0x110: case SYS_SPU_THREAD_STOP_RECEIVE_EVENT:
{ {
/* ===== sys_spu_thread_receive_event ===== */ /* ===== sys_spu_thread_receive_event ===== */
@ -2977,7 +2992,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true; return true;
} }
case 0x111: case SYS_SPU_THREAD_STOP_TRY_RECEIVE_EVENT:
{ {
/* ===== sys_spu_thread_tryreceive_event ===== */ /* ===== sys_spu_thread_tryreceive_event ===== */
@ -3037,7 +3052,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true; return true;
} }
case 0x100: case SYS_SPU_THREAD_STOP_YIELD:
{ {
// SPU thread group yield (TODO) // SPU thread group yield (TODO)
if (ch_out_mbox.get_count()) if (ch_out_mbox.get_count())
@ -3049,7 +3064,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true; return true;
} }
case 0x101: case SYS_SPU_THREAD_STOP_GROUP_EXIT:
{ {
/* ===== sys_spu_thread_group_exit ===== */ /* ===== sys_spu_thread_group_exit ===== */
@ -3098,6 +3113,7 @@ bool spu_thread::stop_and_signal(u32 code)
group->exit_status = value; group->exit_status = value;
group->join_state = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT; group->join_state = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT;
set_status_npc();
break; break;
} }
@ -3106,7 +3122,7 @@ bool spu_thread::stop_and_signal(u32 code)
return true; return true;
} }
case 0x102: case SYS_SPU_THREAD_STOP_THREAD_EXIT:
{ {
/* ===== sys_spu_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); 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()); const u32 value = ch_out_mbox.get_value();
status_npc = {SPU_STATUS_STOPPED_BY_STOP, 0}; spu_log.trace("sys_spu_thread_exit(status=0x%x)", value);
last_exit_status = value;
set_status_npc();
state += cpu_flag::stop; state += cpu_flag::stop;
check_state(); check_state();
return true; 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::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 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 index; // SPU index
const u32 offset; // SPU LS offset 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; 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); 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; 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; return CELL_OK;
} }

View file

@ -68,6 +68,16 @@ enum : s32
SYS_SPU_SEGMENT_TYPE_INFO = 4, 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 struct sys_spu_thread_group_attribute
{ {
be_t<u32> nsize; // name length including NULL terminator 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_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_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_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_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); error_code sys_raw_spu_create(ppu_thread&, vm::ptr<u32> id, vm::ptr<void> attr);