diff --git a/Core/HLE/KernelWaitHelpers.h b/Core/HLE/KernelWaitHelpers.h index fa01f331c5..7cad397f61 100644 --- a/Core/HLE/KernelWaitHelpers.h +++ b/Core/HLE/KernelWaitHelpers.h @@ -25,6 +25,26 @@ namespace HLEKernel { +// Should be called from the CoreTiming handler for the wait func. +template +inline void WaitExecTimeout(SceUID threadID) { + u32 error; + SceUID uid = __KernelGetWaitID(threadID, waitType, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + KO *ko = uid == 0 ? NULL : kernelObjects.Get(uid, error); + if (ko) + { + if (timeoutPtr != 0) + Memory::Write_U32(0, timeoutPtr); + + // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. + // The reason is, if it times out, but what it was waiting on is DELETED prior to it + // actually running, it will get a DELETE result instead of a TIMEOUT. + // So, we need to remember it or we won't be able to mark it DELETE instead later. + __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); + } +} + // Move a thead from the waiting thread list to the paused thread list. // This version is for vectors which contain structs, which must have SceUID threadID and u64 pausedTimeout. // Should not be called directly. diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index bf2cd26fdc..99dec5d254 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -355,15 +355,16 @@ void __KernelEventFlagTimeout(u64 userdata, int cycleslate) { SceUID threadID = (SceUID)userdata; + // This still needs to set the result pointer from the wait. u32 error; - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0) - Memory::Write_U32(0, timeoutPtr); - SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); EventFlag *e = kernelObjects.Get(flagID, error); if (e) { + if (timeoutPtr != 0) + Memory::Write_U32(0, timeoutPtr); + for (size_t i = 0; i < e->waitingThreads.size(); i++) { EventFlagTh *t = &e->waitingThreads[i]; diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 986eef63ff..5528409854 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -257,24 +257,7 @@ void __KernelMbxEndCallback(SceUID threadID, SceUID prevCallbackId) void __KernelMbxTimeout(u64 userdata, int cyclesLate) { SceUID threadID = (SceUID)userdata; - - u32 error; - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0) - Memory::Write_U32(0, timeoutPtr); - - SceUID mbxID = __KernelGetWaitID(threadID, WAITTYPE_MBX, error); - Mbx *m = kernelObjects.Get(mbxID, error); - if (m) - { - // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. - // The reason is, if it times out, but what it was waiting on is DELETED prior to it - // actually running, it will get a DELETE result instead of a TIMEOUT. - // So, we need to remember it or we won't be able to mark it DELETE instead later. - - // TODO: Should numWaitThreads be decreased yet? - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); - } + HLEKernel::WaitExecTimeout(threadID); } void __KernelWaitMbx(Mbx *m, u32 timeoutPtr) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index ac7e5e24b0..0f17140aae 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -457,22 +457,7 @@ int sceKernelDeleteFpl(SceUID uid) void __KernelFplTimeout(u64 userdata, int cyclesLate) { SceUID threadID = (SceUID) userdata; - - u32 error; - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0) - Memory::Write_U32(0, timeoutPtr); - - SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_FPL, error); - FPL *fpl = kernelObjects.Get(uid, error); - if (fpl) - { - // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. - // The reason is, if it times out, but while it was waiting on is DELETED prior to it - // actually running, it will get a DELETE result instead of a TIMEOUT. - // So, we need to remember it or we won't be able to mark it DELETE instead later. - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); - } + HLEKernel::WaitExecTimeout(threadID); } void __KernelSetFplTimeout(u32 timeoutPtr) @@ -1383,22 +1368,7 @@ bool __KernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 &error, const ch void __KernelVplTimeout(u64 userdata, int cyclesLate) { SceUID threadID = (SceUID) userdata; - - u32 error; - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0) - Memory::Write_U32(0, timeoutPtr); - - SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_VPL, error); - VPL *vpl = kernelObjects.Get(uid, error); - if (vpl) - { - // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. - // The reason is, if it times out, but while it was waiting on is DELETED prior to it - // actually running, it will get a DELETE result instead of a TIMEOUT. - // So, we need to remember it or we won't be able to mark it DELETE instead later. - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); - } + HLEKernel::WaitExecTimeout(threadID); } void __KernelSetVplTimeout(u32 timeoutPtr) diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index 36434606e3..34e2e4a8e2 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -25,6 +25,7 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceKernelThread.h" +#include "Core/HLE/KernelWaitHelpers.h" #include "Common/ChunkFile.h" #define SCE_KERNEL_MPA_THFIFO_S 0x0000 @@ -297,23 +298,8 @@ KernelObject *__KernelMsgPipeObject() void __KernelMsgPipeTimeout(u64 userdata, int cyclesLate) { - SceUID threadID = (SceUID) (userdata & 0xFFFFFFFF); - - u32 error; - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0) - Memory::Write_U32(0, timeoutPtr); - - SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_MSGPIPE, error); - MsgPipe *m = kernelObjects.Get(uid, error); - if (m) - { - // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. - // The reason is, if it times out, but whhile it was waiting on is DELETED prior to it - // actually running, it will get a DELETE result instead of a TIMEOUT. - // So, we need to remember it or we won't be able to mark it DELETE instead later. - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); - } + SceUID threadID = (SceUID) userdata; + HLEKernel::WaitExecTimeout(threadID); } bool __KernelSetMsgPipeTimeout(u32 timeoutPtr) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 307b11c79b..e24859d46a 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -334,22 +334,7 @@ retry: void __KernelSemaTimeout(u64 userdata, int cycleslate) { SceUID threadID = (SceUID)userdata; - - u32 error; - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0) - Memory::Write_U32(0, timeoutPtr); - - SceUID semaID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); - Semaphore *s = kernelObjects.Get(semaID, error); - if (s) - { - // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. - // The reason is, if it times out, but what it was waiting on is DELETED prior to it - // actually running, it will get a DELETE result instead of a TIMEOUT. - // So, we need to remember it or we won't be able to mark it DELETE instead later. - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); - } + HLEKernel::WaitExecTimeout(threadID); } void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr)