diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 36932536c1..23f7248e16 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -18,6 +18,7 @@ #include "Emu/Cell/lv2/sys_process.h" #include +#include #include "util/asm.hpp" LOG_CHANNEL(sceNpTrophy); @@ -462,7 +463,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, const auto trophy_manager = g_fxo->get(); - reader_lock lock(trophy_manager->mtx); + std::shared_lock lock(trophy_manager->mtx); if (!trophy_manager->is_initialized) { @@ -470,6 +471,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, } const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); + const auto handle_ptr = idm::get(handle); if (error) { @@ -529,13 +531,47 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, // * Installed const std::string trophyPath = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name; + const s32 trp_status = fs::is_dir(vfs::get(trophyPath)) ? SCE_NP_TROPHY_STATUS_INSTALLED : SCE_NP_TROPHY_STATUS_NOT_INSTALLED; + + lock.unlock(); + + sceNpTrophy.notice("sceNpTrophyRegisterContext(): Callback is being called (trp_status=%u)", trp_status); // The callback is called once and then if it returns >= 0 the cb is called through events(coming from vsh) that are passed to the CB through cellSysutilCheckCallback - if (statusCb(ppu, context, fs::is_dir(vfs::get(trophyPath)) ? SCE_NP_TROPHY_STATUS_INSTALLED : SCE_NP_TROPHY_STATUS_NOT_INSTALLED, 0, 0, arg) < 0) + if (statusCb(ppu, context, trp_status, 0, 0, arg) < 0) { return SCE_NP_TROPHY_ERROR_PROCESSING_ABORTED; } + std::unique_lock lock2(trophy_manager->mtx); + + // Rerun error checks, the callback could have changed stuff by calling sceNpTrophy functions internally + + if (!trophy_manager->is_initialized) + { + return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; + } + + const auto [ctxt2, error2] = trophy_manager->get_context_ex(context, handle); + + if (error2) + { + // Recheck for any errors, such as if AbortHandle was called + return error2; + } + + // Paranoid checks: context/handler could have been destroyed and replaced with new ones with the same IDs + // Return an error for such cases + if (ctxt2 != ctxt) + { + return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; + } + + if (handle_ptr.get() != idm::check(handle)) + { + return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + } + if (!trp.Install(trophyPath)) { sceNpTrophy.error("sceNpTrophyRegisterContext(): Failed to install trophy context '%s' (%s)", trophyPath, fs::g_tls_error); @@ -557,6 +593,8 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, { SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE, 0 } }; + lock2.unlock(); + lv2_obj::sleep(ppu); // Create a counter which is destroyed after the function ends