Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sceNpTrophy: Fix sceNpTrophyRegisterContext for handler abortion #9586

Merged
merged 1 commit into from Jan 12, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 40 additions & 2 deletions rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp
Expand Up @@ -18,6 +18,7 @@
#include "Emu/Cell/lv2/sys_process.h"

#include <cmath>
#include <shared_mutex>
#include "util/asm.hpp"

LOG_CHANNEL(sceNpTrophy);
Expand Down Expand Up @@ -462,14 +463,15 @@ 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)
{
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
}

const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle);
const auto handle_ptr = idm::get<trophy_handle_t>(handle);

if (error)
{
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down