diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 09f611423b..85762c9a03 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -97,6 +97,27 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](ppu_thread_status s) + { + switch (s) + { + case PPU_THREAD_STATUS_IDLE: return "IDLE"; + case PPU_THREAD_STATUS_RUNNABLE: return "RUN"; + case PPU_THREAD_STATUS_ONPROC: return "ONPROC"; + case PPU_THREAD_STATUS_SLEEP: return "SLEEP"; + case PPU_THREAD_STATUS_STOP: return "STOP"; + case PPU_THREAD_STATUS_ZOMBIE: return "Zombie"; + case PPU_THREAD_STATUS_DELETED: return "Deleted"; + case PPU_THREAD_STATUS_UNKNOWN: break; + } + + return unknown; + }); +} + const ppu_decoder g_ppu_interpreter_precise; const ppu_decoder g_ppu_interpreter_fast; const ppu_decoder g_ppu_itype; diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 3c3c6c3e7c..9a1b123fac 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -34,6 +34,18 @@ enum class ppu_join_status : u32 max = 4, // Values above it indicate PPU id of joining thread }; +enum ppu_thread_status : u32 +{ + PPU_THREAD_STATUS_IDLE, + PPU_THREAD_STATUS_RUNNABLE, + PPU_THREAD_STATUS_ONPROC, + PPU_THREAD_STATUS_SLEEP, + PPU_THREAD_STATUS_STOP, + PPU_THREAD_STATUS_ZOMBIE, + PPU_THREAD_STATUS_DELETED, + PPU_THREAD_STATUS_UNKNOWN, +}; + // Formatting helper enum class ppu_syscall_code : u64 { diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 1a0c8228b8..cc839967d3 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -48,6 +48,8 @@ #include "sys_uart.h" #include "sys_crypto_engine.h" +#include + extern std::string ppu_get_syscall_name(u64 code); template <> @@ -1387,3 +1389,41 @@ void lv2_obj::schedule_all() } } } + +ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm) +{ + std::optional opt_lock; + + if (lock_idm) + { + opt_lock.emplace(id_manager::g_mutex); + } + + if (ppu->state & cpu_flag::stop) + { + return PPU_THREAD_STATUS_IDLE; + } + + switch (ppu->joiner) + { + case ppu_join_status::zombie: return PPU_THREAD_STATUS_ZOMBIE; + case ppu_join_status::exited: return PPU_THREAD_STATUS_DELETED; + default: break; + } + + reader_lock lock(g_mutex); + + const auto it = std::find(g_ppu.begin(), g_ppu.end(), ppu); + + if (it == g_ppu.end()) + { + return PPU_THREAD_STATUS_SLEEP; + } + + if (it - g_ppu.begin() >= g_cfg.core.ppu_threads) + { + return PPU_THREAD_STATUS_RUNNABLE; + } + + return PPU_THREAD_STATUS_ONPROC; +} diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h index 7aad07d40a..81598288ea 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h @@ -41,18 +41,6 @@ struct sys_ppu_thread_icontext_t be_t pc; }; -enum : u32 -{ - PPU_THREAD_STATUS_IDLE, - PPU_THREAD_STATUS_RUNNABLE, - PPU_THREAD_STATUS_ONPROC, - PPU_THREAD_STATUS_SLEEP, - PPU_THREAD_STATUS_STOP, - PPU_THREAD_STATUS_ZOMBIE, - PPU_THREAD_STATUS_DELETED, - PPU_THREAD_STATUS_UNKNOWN, -}; - // Syscalls void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode); diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index 44cfa719c5..6b0108ad26 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -60,6 +60,8 @@ enum SYS_SYNC_ATTR_ADAPTIVE_MASK = 0xf000, }; +enum ppu_thread_status : u32; + // Base class for some kernel objects (shared set of 8192 objects). struct lv2_obj { @@ -185,6 +187,8 @@ public: g_to_awake.clear(); } + static ppu_thread_status ppu_state(ppu_thread* ppu, bool lock_idm = true); + static inline void append(cpu_thread* const thread) { g_to_awake.emplace_back(thread); diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index f112debd14..2e70e8fd11 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -553,8 +553,13 @@ void kernel_explorer::Update() idm::select>([&](u32 id, ppu_thread& ppu) { const auto func = ppu.last_function; - add_leaf(find_node(root, additional_nodes::ppu_threads), qstr(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, State: %s, %s func: “%s”", id, *ppu.ppu_tname.load(), +ppu.prio, ppu.joiner.load(), ppu.state.load() - , ppu.current_function ? "In" : "Last", func ? func : ""))); + const ppu_thread_status status = lv2_obj::ppu_state(&ppu, false); + + if (status != PPU_THREAD_STATUS_DELETED) + { + add_leaf(find_node(root, additional_nodes::ppu_threads), qstr(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, Status: %s, State: %s, %s func: “%s”", id, *ppu.ppu_tname.load(), +ppu.prio, ppu.joiner.load(), status, ppu.state.load() + , ppu.current_function ? "In" : "Last", func ? func : ""))); + } }); idm::select>([&](u32 /*id*/, spu_thread& spu)