mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Revert "Implement exit callbacks. Attempt to solve #21828"
This reverts commit e4d3cc841c.
This commit is contained in:
@@ -300,31 +300,6 @@ public:
|
||||
SceUID cbId;
|
||||
};
|
||||
|
||||
// Set when an exit callback dispatch is in flight, cleared by the action below when it returns.
|
||||
static bool g_exitCallbackPending = false;
|
||||
|
||||
class ActionAfterExitCallback : public PSPAction {
|
||||
public:
|
||||
ActionAfterExitCallback() {}
|
||||
void run(MipsCall &call) override {
|
||||
INFO_LOG(Log::sceKernel, "Exit callback returned (v0 = %08x). Powering down.", currentMIPS->r[MIPS_REG_V0]);
|
||||
g_exitCallbackPending = false;
|
||||
// The callback may have already powered down by calling sceKernelExitGame - that's fine,
|
||||
// Core_Stop is idempotent. Either way, the host will see CORE_POWERDOWN and tear the game down.
|
||||
Core_Stop();
|
||||
}
|
||||
|
||||
static PSPAction *Create() {
|
||||
return new ActionAfterExitCallback;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p) override {
|
||||
auto s = p.Section("ActionAfterExitCallback", 1);
|
||||
if (!s)
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
u32 PSPThread::GetMissingErrorCode() {
|
||||
return SCE_KERNEL_ERROR_UNKNOWN_THID;
|
||||
}
|
||||
@@ -546,7 +521,6 @@ static bool dispatchEnabled = true;
|
||||
static MipsCallManager mipsCalls;
|
||||
static int actionAfterCallback;
|
||||
static int actionAfterMipsCall;
|
||||
static int actionAfterExitCallback;
|
||||
|
||||
// When inside a callback, delays are "paused", and rechecked after the callback returns.
|
||||
static std::map<SceUID, u64> pausedDelays;
|
||||
@@ -834,8 +808,6 @@ void __KernelThreadingInit()
|
||||
eventThreadEndTimeout = CoreTiming::RegisterEvent("ThreadEndTimeout", &hleThreadEndTimeout);
|
||||
actionAfterMipsCall = __KernelRegisterActionType(ActionAfterMipsCall::Create);
|
||||
actionAfterCallback = __KernelRegisterActionType(ActionAfterCallback::Create);
|
||||
actionAfterExitCallback = __KernelRegisterActionType(ActionAfterExitCallback::Create);
|
||||
g_exitCallbackPending = false;
|
||||
|
||||
// Create the two idle threads, as well. With the absolute minimal possible priority.
|
||||
// 4096 stack size - don't know what the right value is. Hm, if callbacks are ever to run on these threads...
|
||||
@@ -853,7 +825,7 @@ void __KernelThreadingInit()
|
||||
|
||||
void __KernelThreadingDoState(PointerWrap &p)
|
||||
{
|
||||
auto s = p.Section("sceKernelThread", 1, 5);
|
||||
auto s = p.Section("sceKernelThread", 1, 4);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@@ -889,10 +861,6 @@ void __KernelThreadingDoState(PointerWrap &p)
|
||||
__KernelRestoreActionType(actionAfterMipsCall, ActionAfterMipsCall::Create);
|
||||
Do(p, actionAfterCallback);
|
||||
__KernelRestoreActionType(actionAfterCallback, ActionAfterCallback::Create);
|
||||
if (s >= 5) {
|
||||
Do(p, actionAfterExitCallback);
|
||||
__KernelRestoreActionType(actionAfterExitCallback, ActionAfterExitCallback::Create);
|
||||
}
|
||||
|
||||
Do(p, pausedDelays);
|
||||
|
||||
@@ -1082,7 +1050,6 @@ void __KernelThreadingShutdown() {
|
||||
pausedDelays.clear();
|
||||
threadEventHandlers.clear();
|
||||
pendingDeleteThreads.clear();
|
||||
g_exitCallbackPending = false;
|
||||
}
|
||||
|
||||
std::string __KernelThreadingSummary() {
|
||||
@@ -2722,7 +2689,7 @@ SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg)
|
||||
if (thread)
|
||||
thread->callbacks.push_back(id);
|
||||
|
||||
return hleLogInfo(Log::sceKernel, id);
|
||||
return hleLogDebug(Log::sceKernel, id);
|
||||
}
|
||||
|
||||
int sceKernelDeleteCallback(SceUID cbId)
|
||||
@@ -3523,51 +3490,6 @@ int sceKernelRegisterExitCallback(SceUID cbId)
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
}
|
||||
|
||||
// Dispatch the exit callback registered via sceKernelRegisterExitCallback on the thread that registered
|
||||
// it, so the game has a chance to run its cleanup before we shut down. Returns false if no callback can
|
||||
// be dispatched (none registered, registering thread dead, etc.) - the caller should then power down
|
||||
// immediately. While true is returned, __KernelIsExitCallbackPending() will report true until the
|
||||
// callback returns (via the chained ActionAfterExitCallback).
|
||||
bool __KernelInvokeRegisteredExitCallback() {
|
||||
if (g_exitCallbackPending) {
|
||||
WARN_LOG(Log::sceKernel, "__KernelInvokeRegisteredExitCallback: already in progress");
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 error;
|
||||
PSPCallback *cb = kernelObjects.Get<PSPCallback>(registeredExitCbId, error);
|
||||
if (!cb) {
|
||||
INFO_LOG(Log::sceKernel, "__KernelInvokeRegisteredExitCallback: no exit callback registered");
|
||||
return false;
|
||||
}
|
||||
|
||||
PSPThread *thread = kernelObjects.Get<PSPThread>(cb->nc.threadId, error);
|
||||
if (!thread) {
|
||||
WARN_LOG(Log::sceKernel, "__KernelInvokeRegisteredExitCallback: registering thread %08x is gone", cb->nc.threadId);
|
||||
return false;
|
||||
}
|
||||
if (thread->isStopped()) {
|
||||
WARN_LOG(Log::sceKernel, "__KernelInvokeRegisteredExitCallback: registering thread %s is stopped", thread->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
ActionAfterExitCallback *action = (ActionAfterExitCallback *)__KernelCreateAction(actionAfterExitCallback);
|
||||
|
||||
// Exit callbacks on real PSP receive (arg1, arg2, common) where arg1/arg2 are zero for HOME-button exit.
|
||||
const u32 args[] = { 0, 0, cb->nc.commonArgument };
|
||||
|
||||
INFO_LOG(Log::sceKernel, "__KernelInvokeRegisteredExitCallback: dispatching '%s' (cb %08x) on thread '%s'",
|
||||
cb->nc.name, registeredExitCbId, thread->GetName());
|
||||
|
||||
g_exitCallbackPending = true;
|
||||
__KernelCallAddress(thread, cb->nc.entrypoint, action, args, 3, true, registeredExitCbId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __KernelIsExitCallbackPending() {
|
||||
return g_exitCallbackPending;
|
||||
}
|
||||
|
||||
// Update the exit callback status?
|
||||
int LoadExecForUser_362A956B()
|
||||
{
|
||||
|
||||
@@ -451,15 +451,6 @@ void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus);
|
||||
int LoadExecForUser_362A956B();
|
||||
int sceKernelRegisterExitCallback(SceUID cbId);
|
||||
|
||||
// Dispatch the exit callback registered via sceKernelRegisterExitCallback on its registering thread,
|
||||
// so the game has a chance to clean up before we shut down. Returns false if no callback can be
|
||||
// dispatched (none registered, the thread is gone, etc.) - in that case, the host should proceed
|
||||
// to power down immediately.
|
||||
bool __KernelInvokeRegisteredExitCallback();
|
||||
// True while a previously-invoked exit callback hasn't yet returned. The host should keep running
|
||||
// emulation while this is true, and only tear down after it goes false (or after a timeout).
|
||||
bool __KernelIsExitCallbackPending();
|
||||
|
||||
KernelObject *__KernelThreadEventHandlerObject();
|
||||
SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u32 mask, u32 handlerPtr, u32 commonArg);
|
||||
int sceKernelReleaseThreadEventHandler(SceUID uid);
|
||||
|
||||
+2
-39
@@ -65,7 +65,6 @@ using namespace std::placeholders;
|
||||
#include "GPU/GPUCommon.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/HLE/sceCtrl.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceSas.h"
|
||||
#include "Core/HLE/sceNet.h"
|
||||
#include "Core/HLE/sceDisplay.h"
|
||||
@@ -472,33 +471,6 @@ EmuScreen::~EmuScreen() {
|
||||
bootPending_ = false;
|
||||
}
|
||||
|
||||
// Catch-all for shutdown paths that didn't go through REQUEST_GAME_STOP (e.g. user navigated
|
||||
// away with the back button, opened a different game, etc.). If an exit callback is registered
|
||||
// and the core is still running, drive the CPU synchronously here so the callback gets a chance
|
||||
// to run - there are no more host frames after this point. Capped tightly so a misbehaving
|
||||
// callback can't stall shutdown.
|
||||
if (!bootPending_ && PSP_IsInited() && coreState != CORE_POWERDOWN) {
|
||||
const bool inflight = __KernelIsExitCallbackPending();
|
||||
if (inflight || __KernelInvokeRegisteredExitCallback()) {
|
||||
INFO_LOG(Log::Loader, "EmuScreen dtor: %s exit callback synchronously before shutdown",
|
||||
inflight ? "finishing in-flight" : "running");
|
||||
if (coreState == CORE_NEXTFRAME)
|
||||
coreState = CORE_RUNNING_CPU;
|
||||
const s64 chunkCycles = usToCycles(100000); // ~100ms of emulated time per chunk
|
||||
const int maxChunks = 20; // hard cap: ~2s of emulated time total
|
||||
for (int i = 0; i < maxChunks && __KernelIsExitCallbackPending(); i++) {
|
||||
if (coreState != CORE_RUNNING_CPU && coreState != CORE_NEXTFRAME)
|
||||
break;
|
||||
PSP_RunLoopFor((int)chunkCycles);
|
||||
if (coreState == CORE_NEXTFRAME)
|
||||
coreState = CORE_RUNNING_CPU;
|
||||
}
|
||||
if (__KernelIsExitCallbackPending()) {
|
||||
WARN_LOG(Log::Loader, "Exit callback didn't return in time; powering down anyway.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Achievements::UnloadGame();
|
||||
PSP_Shutdown(true);
|
||||
|
||||
@@ -591,17 +563,8 @@ void EmuScreen::sendMessage(UIMessage message, const char *value) {
|
||||
WARN_LOG(Log::Loader, "Can't stop during a pending boot");
|
||||
return;
|
||||
}
|
||||
// Give the game a chance to run its registered exit callback before tearing things down.
|
||||
// If the dispatch took, we keep running emulation; ActionAfterExitCallback (or a direct
|
||||
// sceKernelExitGame from inside the callback) flips coreState to CORE_POWERDOWN, and
|
||||
// checkPowerDown() then switches us to MainScreen as usual. Pressing stop again while
|
||||
// the callback is in flight, or stopping a non-running core, falls through to immediate shutdown.
|
||||
if (coreState == CORE_RUNNING_CPU && !__KernelIsExitCallbackPending() && __KernelInvokeRegisteredExitCallback()) {
|
||||
INFO_LOG(Log::Loader, "REQUEST_GAME_STOP: running exit callback before shutdown.");
|
||||
} else {
|
||||
// No callback (or already in flight, or core not running) - the destructor will take care of shutting down.
|
||||
screenManager()->switchScreen(new MainScreen());
|
||||
}
|
||||
// The destructor will take care of shutting down.
|
||||
screenManager()->switchScreen(new MainScreen());
|
||||
} else if (message == UIMessage::REQUEST_GAME_RESET) {
|
||||
if (bootPending_) {
|
||||
WARN_LOG(Log::Loader, "Can't reset during a pending boot");
|
||||
|
||||
Reference in New Issue
Block a user