From 8bf1ef26160c2137e6e5e2a9001ae4ef320bc09d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Sep 2013 13:18:02 -0700 Subject: [PATCH] Add handlers for delay and sleep callbacks. --- Core/HLE/sceKernelThread.cpp | 86 ++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 4ec222173d..ef728c6282 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -820,6 +820,9 @@ MipsCallManager mipsCalls; int actionAfterCallback; int actionAfterMipsCall; +// When inside a callback, delays are "paused", and rechecked after the callback returns. +std::map pausedDelays; + // Doesn't need state saving. WaitTypeFuncs waitTypeFuncs[NUM_WAITTYPES]; @@ -892,16 +895,85 @@ Thread *__GetCurrentThread() { return NULL; } -u32 __KernelMipsCallReturnAddress() -{ +u32 __KernelMipsCallReturnAddress() { return cbReturnHackAddr; } -u32 __KernelInterruptReturnAddress() -{ +u32 __KernelInterruptReturnAddress() { return intReturnHackAddr; } +void __KernelDelayBeginCallback(SceUID threadID, SceUID prevCallbackId) { + SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; + + u32 error; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_DELAY, error); + if (waitID == threadID) { + // This means two callbacks in a row. PSP crashes if the same callback runs inside itself. + // TODO: Handle this better? + if (pausedDelays.find(pauseKey) != pausedDelays.end()) + return; + + s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventScheduledWakeup, threadID); + pausedDelays[pauseKey] = CoreTiming::GetTicks() + cyclesLeft; + + DEBUG_LOG(HLE, "sceKernelDelayThreadCB: Suspending delay for callback"); + } + else + WARN_LOG_REPORT(HLE, "sceKernelDelayThreadCB: beginning callback with bad wait?"); +} + +void __KernelDelayEndCallback(SceUID threadID, SceUID prevCallbackId, u32 &returnValue) { + SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; + + if (pausedDelays.find(pauseKey) == pausedDelays.end()) + { + // This probably should not happen. + WARN_LOG_REPORT(HLE, "sceKernelDelayThreadCB: cannot find delay deadline"); + __KernelResumeThreadFromWait(threadID, 0); + return; + } + + u64 delayDeadline = pausedDelays[pauseKey]; + pausedDelays.erase(pauseKey); + + // TODO: Don't wake up if __KernelCurHasReadyCallbacks()? + + s64 cyclesLeft = delayDeadline - CoreTiming::GetTicks(); + if (cyclesLeft < 0) + __KernelResumeThreadFromWait(threadID, 0); + else + { + CoreTiming::ScheduleEvent(cyclesLeft, eventScheduledWakeup, __KernelGetCurThread()); + DEBUG_LOG(HLE, "sceKernelDelayThreadCB: Resuming delay after callback"); + } +} + +void __KernelSleepBeginCallback(SceUID threadID, SceUID prevCallbackId) { + DEBUG_LOG(HLE, "sceKernelSleepThreadCB: Suspending sleep for callback"); +} + +void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId, u32 &returnValue) { + u32 error; + Thread *thread = kernelObjects.Get(threadID, error); + if (!thread) + { + // This probably should not happen. + WARN_LOG_REPORT(HLE, "sceKernelSleepThreadCB: thread deleted?"); + return; + } + + // TODO: Don't wake up if __KernelCurHasReadyCallbacks()? + + if (thread->nt.wakeupCount > 0) { + thread->nt.wakeupCount--; + DEBUG_LOG(HLE, "sceKernelSleepThreadCB: resume from callback, wakeupCount decremented to %i", thread->nt.wakeupCount); + __KernelResumeThreadFromWait(threadID, 0); + } else { + DEBUG_LOG(HLE, "sceKernelDelayThreadCB: Resuming sleep after callback"); + } +} + u32 __KernelSetThreadRA(SceUID threadID, u32 nid) { u32 newRA; @@ -998,6 +1070,9 @@ void __KernelThreadingInit() __KernelListenThreadEnd(__KernelCancelWakeup); __KernelListenThreadEnd(__KernelCancelThreadEndTimeout); + + __KernelRegisterWaitTypeFuncs(WAITTYPE_DELAY, __KernelDelayBeginCallback, __KernelDelayEndCallback); + __KernelRegisterWaitTypeFuncs(WAITTYPE_SLEEP, __KernelSleepBeginCallback, __KernelSleepEndCallback); } void __KernelThreadingDoState(PointerWrap &p) @@ -1029,6 +1104,8 @@ void __KernelThreadingDoState(PointerWrap &p) p.Do(actionAfterCallback); __KernelRestoreActionType(actionAfterCallback, ActionAfterCallback::Create); + p.Do(pausedDelays); + hleCurrentThreadName = __KernelGetThreadName(currentThread); lastSwitchCycles = CoreTiming::GetTicks(); @@ -1214,6 +1291,7 @@ void __KernelThreadingShutdown() currentThread = 0; intReturnHackAddr = 0; hleCurrentThreadName = NULL; + pausedDelays.clear(); } const char *__KernelGetThreadName(SceUID threadID)