diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index fde4d5ca3c..f9fe54ade8 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -136,29 +136,43 @@ static int oldStatus = -1; static std::map currentlyLoadedModules; static int volatileUnlockEvent = -1; static HLEHelperThread *accessThread = nullptr; +static const char *accessThreadState = "initial"; -static void CleanupDialogThreads() { - if (accessThread && accessThread->Stopped()) { - delete accessThread; - accessThread = nullptr; +static void CleanupDialogThreads(bool force = false) { + if (accessThread) { + if (accessThread->Stopped()) { + delete accessThread; + accessThread = nullptr; + accessThreadState = "cleaned up"; + } else if (force) { + ERROR_LOG_REPORT(SCEUTILITY, "Utility access thread still running, state: %s, dialog=%d/%d", accessThreadState, currentDialogType, currentDialogActive); + + // Try to force shutdown anyway. + accessThread->Terminate(); + delete accessThread; + accessThread = nullptr; + accessThreadState = "force terminated"; + // Try to unlock in case other dialog was shutting down. + KernelVolatileMemUnlock(0); + } } } static void ActivateDialog(UtilityDialogType type) { + CleanupDialogThreads(); if (!currentDialogActive) { currentDialogType = type; currentDialogActive = true; // So that we log the next one. oldStatus = -1; } - CleanupDialogThreads(); } static void DeactivateDialog() { + CleanupDialogThreads(); if (currentDialogActive) { currentDialogActive = false; } - CleanupDialogThreads(); } static PSPDialog *CurrentDialog(UtilityDialogType type) { @@ -241,6 +255,8 @@ void __UtilityDoState(PointerWrap &p) { Do(p, hasAccessThread); if (hasAccessThread) { Do(p, accessThread); + if (p.mode == p.MODE_READ) + accessThreadState = "from save state"; } } else { hasAccessThread = false; @@ -250,6 +266,7 @@ void __UtilityDoState(PointerWrap &p) { accessThread->Forget(); delete accessThread; accessThread = nullptr; + accessThreadState = "cleared from save state"; } } @@ -264,6 +281,7 @@ void __UtilityShutdown() { if (accessThread) { delete accessThread; accessThread = nullptr; + accessThreadState = "shutdown"; } delete saveDialog; @@ -299,10 +317,10 @@ void UtilityDialogInitialize(UtilityDialogType type, int delayUs, int priority) (u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityInitDialog"), }; - CleanupDialogThreads(); - _assert_(accessThread == nullptr); + CleanupDialogThreads(true); accessThread = new HLEHelperThread("ScePafJob", insts, (uint32_t)ARRAY_SIZE(insts), priority, 0x200); accessThread->Start(partDelay, 0); + accessThreadState = "initializing"; } void UtilityDialogShutdown(UtilityDialogType type, int delayUs, int priority) { @@ -325,12 +343,12 @@ void UtilityDialogShutdown(UtilityDialogType type, int delayUs, int priority) { (u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityFinishDialog"), }; - CleanupDialogThreads(); - _assert_(accessThread == nullptr); + CleanupDialogThreads(true); bool prevInterrupts = __InterruptsEnabled(); __DisableInterrupts(); accessThread = new HLEHelperThread("ScePafJob", insts, (uint32_t)ARRAY_SIZE(insts), priority, 0x200); accessThread->Start(partDelay, 0); + accessThreadState = "shutting down"; if (prevInterrupts) __EnableInterrupts(); } @@ -349,6 +367,7 @@ static int UtilityWorkUs(int us) { static int UtilityInitDialog(int type) { PSPDialog *dialog = CurrentDialog((UtilityDialogType)type); + accessThreadState = "init finished"; if (dialog) return hleLogSuccessI(SCEUTILITY, dialog->FinishInit()); return hleLogError(SCEUTILITY, 0, "invalid dialog type?"); @@ -356,6 +375,7 @@ static int UtilityInitDialog(int type) { static int UtilityFinishDialog(int type) { PSPDialog *dialog = CurrentDialog((UtilityDialogType)type); + accessThreadState = "shutdown finished"; if (dialog) return hleLogSuccessI(SCEUTILITY, dialog->FinishShutdown()); return hleLogError(SCEUTILITY, 0, "invalid dialog type?"); @@ -367,6 +387,9 @@ static int sceUtilitySavedataInitStart(u32 paramAddr) { WARN_LOG(SCEUTILITY, "Yugioh Savedata Correction"); if (accessThread) { accessThread->Terminate(); + delete accessThread; + accessThread = nullptr; + accessThreadState = "terminated"; // Try to unlock in case other dialog was shutting down. KernelVolatileMemUnlock(0); }