mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 03:55:32 +00:00
sceNpTrophy: Fix sceNpTrophyRegisterContext for handler abortion (#9586)
* Implement handler abortion during context registration. * Fixed recursive calls to sceNpTrophy functions such as by callbacks from registering context. * Turns out the reader lock for context registeration was incorrect because ctxt->tropusr and trophy directory are being modified. Made it an exclusive lock after callback.
This commit is contained in:
parent
eb77495d5f
commit
e1f95ceb54
1 changed files with 40 additions and 2 deletions
|
@ -18,6 +18,7 @@
|
|||
#include "Emu/Cell/lv2/sys_process.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <shared_mutex>
|
||||
#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<sce_np_trophy_manager>();
|
||||
|
||||
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<trophy_handle_t>(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<trophy_handle_t>(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
|
||||
|
|
Loading…
Add table
Reference in a new issue