diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index e57afafe66..4427c6bd6c 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -365,28 +365,30 @@ bool hleExecuteDebugBreak(const HLEFunction &func) return true; } -u32 hleDelayResult(u32 result, const char *reason, int usec) -{ - if (__KernelIsDispatchEnabled()) - { - CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, __KernelGetCurThread()); +u32 hleDelayResult(u32 result, const char *reason, int usec) { + if (!__KernelIsDispatchEnabled()) { + WARN_LOG(HLE, "%s: Dispatch disabled, not delaying HLE result (right thing to do?)", latestSyscall ? latestSyscall->name : "?"); + } else { + SceUID thread = __KernelGetCurThread(); + if (KernelIsThreadWaiting(thread)) + ERROR_LOG(HLE, "%s: Delaying a thread that's already waiting", latestSyscall ? latestSyscall->name : "?"); + CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, thread); __KernelWaitCurThread(WAITTYPE_HLEDELAY, 1, result, 0, false, reason); } - else - WARN_LOG(HLE, "Dispatch disabled, not delaying HLE result (right thing to do?)"); return result; } -u64 hleDelayResult(u64 result, const char *reason, int usec) -{ - if (__KernelIsDispatchEnabled()) - { - u64 param = (result & 0xFFFFFFFF00000000) | __KernelGetCurThread(); +u64 hleDelayResult(u64 result, const char *reason, int usec) { + if (!__KernelIsDispatchEnabled()) { + WARN_LOG(HLE, "%s: Dispatch disabled, not delaying HLE result (right thing to do?)", latestSyscall ? latestSyscall->name : "?"); + } else { + SceUID thread = __KernelGetCurThread(); + if (KernelIsThreadWaiting(thread)) + ERROR_LOG(HLE, "%s: Delaying a thread that's already waiting", latestSyscall ? latestSyscall->name : "?"); + u64 param = (result & 0xFFFFFFFF00000000) | thread; CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, param); - __KernelWaitCurThread(WAITTYPE_HLEDELAY, 1, (u32) result, 0, false, reason); + __KernelWaitCurThread(WAITTYPE_HLEDELAY, 1, (u32)result, 0, false, reason); } - else - WARN_LOG(HLE, "Dispatch disabled, not delaying HLE result (right thing to do?)"); return result; } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 47b4bb8b68..361a81824f 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1210,7 +1210,15 @@ bool KernelIsThreadDormant(SceUID threadID) { PSPThread *t = kernelObjects.Get(threadID, error); if (t) return (t->nt.status & (THREADSTATUS_DEAD | THREADSTATUS_DORMANT)) != 0; - return 0; + return false; +} + +bool KernelIsThreadWaiting(SceUID threadID) { + u32 error; + PSPThread *t = kernelObjects.Get(threadID, error); + if (t) + return (t->nt.status & (THREADSTATUS_WAITSUSPEND)) != 0; + return false; } u32 __KernelGetWaitValue(SceUID threadID, u32 &error) { @@ -1518,16 +1526,16 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval) } // makes the current thread wait for an event -void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr, bool processCallbacks, const char *reason) -{ - if (!dispatchEnabled) - { +void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr, bool processCallbacks, const char *reason) { + if (!dispatchEnabled) { WARN_LOG_REPORT(SCEKERNEL, "Ignoring wait, dispatching disabled... right thing to do?"); return; } PSPThread *thread = __GetCurrentThread(); _assert_(thread != nullptr); + if ((thread->nt.status & THREADSTATUS_WAIT) != 0) + WARN_LOG_REPORT(SCEKERNEL, "Waiting thread for %d that was already waiting for %d", type, thread->nt.waitType); thread->nt.waitID = waitID; thread->nt.waitType = type; __KernelChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->nt.status & THREADSTATUS_SUSPEND))); @@ -1535,22 +1543,21 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 time thread->waitInfo.waitValue = waitValue; thread->waitInfo.timeoutPtr = timeoutPtr; - // TODO: time waster if (!reason) reason = "started wait"; hleReSchedule(processCallbacks, reason); } -void __KernelWaitCallbacksCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr) -{ - if (!dispatchEnabled) - { +void __KernelWaitCallbacksCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr) { + if (!dispatchEnabled) { WARN_LOG_REPORT(SCEKERNEL, "Ignoring wait, dispatching disabled... right thing to do?"); return; } PSPThread *thread = __GetCurrentThread(); + if ((thread->nt.status & THREADSTATUS_WAIT) != 0) + WARN_LOG_REPORT(SCEKERNEL, "Waiting thread for %d that was already waiting for %d", type, thread->nt.waitType); thread->nt.waitID = waitID; thread->nt.waitType = type; __KernelChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->nt.status & THREADSTATUS_SUSPEND))); diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 3df1d70fc0..068d9f178f 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -173,6 +173,7 @@ u32 __KernelGetCurThreadStack(); u32 __KernelGetCurThreadStackStart(); const char *__KernelGetThreadName(SceUID threadID); bool KernelIsThreadDormant(SceUID threadID); +bool KernelIsThreadWaiting(SceUID threadID); void __KernelSaveContext(PSPThreadContext *ctx, bool vfpuEnabled); void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled);