diff --git a/Core/HLE/KernelWaitHelpers.h b/Core/HLE/KernelWaitHelpers.h index 0c02b74d10..ae7db7815a 100644 --- a/Core/HLE/KernelWaitHelpers.h +++ b/Core/HLE/KernelWaitHelpers.h @@ -44,6 +44,11 @@ inline void WriteRemainingTimeout(int waitTimer, SceUID threadID, u32 timeoutPtr Memory::WriteOrException_U32((u32)cyclesToUs(cyclesLeft), timeoutPtr); } +// For kernel object waits, which all time out on the same event (see __KernelWaitCurThreadWithTimeout). +inline void WriteRemainingTimeout(SceUID threadID, u32 timeoutPtr) { + WriteRemainingTimeout(__KernelWaitTimeoutEvent(), threadID, timeoutPtr); +} + // Should be called from the CoreTiming handler for the wait func. template inline void WaitExecTimeout(SceUID threadID) { @@ -188,6 +193,12 @@ WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbac } } +// The same, for a kernel object wait timing out on the shared event. +template +WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbackId) { + return WaitBeginCallback(threadID, prevCallbackId, __KernelWaitTimeoutEvent()); +} + // Meant to be called in a registered end callback function for a wait type. // // The goal of this function is to resume the wait, or to complete it if a wait is no longer needed. @@ -284,6 +295,12 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI return result; } +// The same, for a kernel object wait timing out on the shared event. +template +WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackId, TryUnlockFunc TryUnlock) { + return WaitEndCallback(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), TryUnlock); +} + // Verify that a thread has not been released from waiting, e.g. by sceKernelReleaseWaitThread(). // For a waiting thread info struct. template diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index 0fa0e6f954..d318078385 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -66,23 +66,23 @@ enum PspEventFlagWaitTypes { PSP_EVENT_WAITKNOWN = PSP_EVENT_WAITCLEAR | PSP_EVENT_WAITCLEARALL | PSP_EVENT_WAITOR, }; -static int eventFlagWaitTimer = -1; - void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId); void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId); void __KernelEventFlagInit() { - eventFlagWaitTimer = CoreTiming::RegisterEvent("EventFlagTimeout", __KernelEventFlagTimeout); - __KernelRegisterWaitTypeFuncs(WAITTYPE_EVENTFLAG, __KernelEventFlagBeginCallback, __KernelEventFlagEndCallback); + __KernelRegisterWaitTypeFuncs(WAITTYPE_EVENTFLAG, __KernelEventFlagBeginCallback, __KernelEventFlagEndCallback, __KernelEventFlagTimeout); } void __KernelEventFlagDoState(PointerWrap &p) { - auto s = p.Section("sceKernelEventFlag", 1); + auto s = p.Section("sceKernelEventFlag", 1, 2); if (!s) return; - Do(p, eventFlagWaitTimer); - CoreTiming::RestoreRegisterEvent(eventFlagWaitTimer, "EventFlagTimeout", __KernelEventFlagTimeout); + if (s < 2) { + int oldTimeoutEvent = -1; + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "EventFlagTimeout"); + } } KernelObject *__KernelEventFlagObject() { @@ -128,7 +128,7 @@ static bool __KernelUnlockEventFlagForThread(EventFlag *e, EventFlagTh &th, u32 } u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.threadID, error); - HLEKernel::WriteRemainingTimeout(eventFlagWaitTimer, th.threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(th.threadID, timeoutPtr); __KernelResumeThreadFromWait(th.threadID, result); wokeThreads = true; @@ -146,7 +146,7 @@ static bool __KernelClearEventFlagThreads(EventFlag *e, int reason) { } void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, eventFlagWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelWaitEventFlagCB: Suspending lock wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) @@ -156,7 +156,7 @@ void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) { } void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, eventFlagWaitTimer, __KernelUnlockEventFlagForThread); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelUnlockEventFlagForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(Log::sceKernel, "sceKernelWaitEventFlagCB: Resuming lock wait from callback"); } @@ -298,14 +298,6 @@ void __KernelEventFlagTimeout(u64 userdata, int cycleslate) { } } -static void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr) { - if (timeoutPtr == 0 || eventFlagWaitTimer == -1) - return; - - u32 micro = Memory::ReadOrException_U32(timeoutPtr); - CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), eventFlagWaitTimer, __KernelGetCurThread()); -} - int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) { if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); @@ -349,8 +341,7 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti th.outAddr = timeout == 0 ? 0 : outBitsPtr; e->waitingThreads.push_back(th); - __KernelSetEventFlagTimeout(e, timeoutPtr); - __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false, "event flag waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false, "event flag waited"); } else { (void)hleLogDebug(Log::sceKernel, 0); } @@ -414,7 +405,7 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 th.outAddr = timeout == 0 ? 0 : outBitsPtr; e->waitingThreads.push_back(th); - __KernelSetEventFlagTimeout(e, timeoutPtr); + __KernelScheduleWaitTimeout(__KernelGetCurThread(), timeoutPtr); if (doCallbackWait) __KernelWaitCallbacksCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr); else diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 51f6782cac..469bc0813f 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -47,7 +47,6 @@ struct MbxWaitingThread { }; void __KernelMbxTimeout(u64 userdata, int cyclesLate); -static int mbxWaitTimer = -1; struct NativeMbx { SceSize_le size; @@ -182,18 +181,20 @@ void __KernelMbxEndCallback(SceUID threadID, SceUID prevCallbackId); void __KernelMbxInit() { - mbxWaitTimer = CoreTiming::RegisterEvent("MbxTimeout", __KernelMbxTimeout); - __KernelRegisterWaitTypeFuncs(WAITTYPE_MBX, __KernelMbxBeginCallback, __KernelMbxEndCallback); + __KernelRegisterWaitTypeFuncs(WAITTYPE_MBX, __KernelMbxBeginCallback, __KernelMbxEndCallback, __KernelMbxTimeout); } void __KernelMbxDoState(PointerWrap &p) { - auto s = p.Section("sceKernelMbx", 1); + auto s = p.Section("sceKernelMbx", 1, 2); if (!s) return; - Do(p, mbxWaitTimer); - CoreTiming::RestoreRegisterEvent(mbxWaitTimer, "MbxTimeout", __KernelMbxTimeout); + if (s < 2) { + int oldTimeoutEvent = -1; + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "MbxTimeout"); + } } KernelObject *__KernelMbxObject() @@ -207,7 +208,7 @@ static bool __KernelUnlockMbxForThread(Mbx *m, MbxWaitingThread &th, u32 &error, return true; u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.threadID, error); - HLEKernel::WriteRemainingTimeout(mbxWaitTimer, th.threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(th.threadID, timeoutPtr); __KernelResumeThreadFromWait(th.threadID, result); wokeThreads = true; @@ -226,7 +227,7 @@ static bool __KernelUnlockMbxForThreadCheck(Mbx *m, MbxWaitingThread &waitData, void __KernelMbxBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, mbxWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB: Suspending mbx wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) @@ -237,7 +238,7 @@ void __KernelMbxBeginCallback(SceUID threadID, SceUID prevCallbackId) void __KernelMbxEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, mbxWaitTimer, __KernelUnlockMbxForThreadCheck); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelUnlockMbxForThreadCheck); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB: Resuming mbx wait from callback"); } @@ -248,15 +249,6 @@ void __KernelMbxTimeout(u64 userdata, int cyclesLate) HLEKernel::WaitExecTimeout(threadID); } -static void __KernelWaitMbx(Mbx *m, u32 timeoutPtr) -{ - if (timeoutPtr == 0 || mbxWaitTimer == -1) - return; - - u32 micro = Memory::ReadOrException_U32(timeoutPtr); - CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), mbxWaitTimer, __KernelGetCurThread()); -} - static std::vector::iterator __KernelMbxFindPriority(std::vector &waiting) { _dbg_assert_msg_(!waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads."); @@ -436,8 +428,7 @@ int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) { if (__KernelWaitTimesOutAtOnce(timeoutPtr)) return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT, "timed out at once"); m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); - __KernelWaitMbx(m, timeoutPtr); - __KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, false, "mbx waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_MBX, id, 0, timeoutPtr, false, "mbx waited"); return hleLogDebug(Log::sceKernel, 0, "no message in queue, waiting"); } } @@ -457,8 +448,7 @@ int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) { if (__KernelWaitTimesOutAtOnce(timeoutPtr)) return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT, "timed out at once"); m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); - __KernelWaitMbx(m, timeoutPtr); - __KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, true, "mbx waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_MBX, id, 0, timeoutPtr, true, "mbx waited"); return hleLogDebug(Log::sceKernel, 0, "no message in queue, waiting"); } } diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 2eaa43ba37..c0d0bca000 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -52,9 +52,6 @@ BlockAllocator userMemory(256); BlockAllocator kernelMemory(256); BlockAllocator volatileMemory(256); -static int vplWaitTimer = -1; -static int fplWaitTimer = -1; -static int tlsplWaitTimer = -1; static bool tlsplUsedIndexes[TLSPL_NUM_INDEXES]; // Thread -> TLSPL uids for thread end. @@ -332,9 +329,6 @@ void __KernelMemoryInit() INFO_LOG(Log::sceKernel, "Kernel and user memory pools initialized"); - vplWaitTimer = CoreTiming::RegisterEvent("VplTimeout", __KernelVplTimeout); - fplWaitTimer = CoreTiming::RegisterEvent("FplTimeout", __KernelFplTimeout); - tlsplWaitTimer = CoreTiming::RegisterEvent("TlsplTimeout", __KernelTlsplTimeout); flags_ = 0; sdkVersion_ = 0; @@ -343,8 +337,9 @@ void __KernelMemoryInit() __KernelListenThreadEnd(&__KernelTlsplThreadEnd); - __KernelRegisterWaitTypeFuncs(WAITTYPE_VPL, __KernelVplBeginCallback, __KernelVplEndCallback); - __KernelRegisterWaitTypeFuncs(WAITTYPE_FPL, __KernelFplBeginCallback, __KernelFplEndCallback); + __KernelRegisterWaitTypeFuncs(WAITTYPE_VPL, __KernelVplBeginCallback, __KernelVplEndCallback, __KernelVplTimeout); + __KernelRegisterWaitTypeFuncs(WAITTYPE_FPL, __KernelFplBeginCallback, __KernelFplEndCallback, __KernelFplTimeout); + __KernelRegisterWaitTypeFuncs(WAITTYPE_TLSPL, nullptr, nullptr, __KernelTlsplTimeout); // The kernel statically allocates this memory, which has some code in it. // It appears this is used for some common funcs in Kernel_Library (memcpy, lwmutex, suspend intr, etc.) @@ -354,7 +349,7 @@ void __KernelMemoryInit() void __KernelMemoryDoState(PointerWrap &p) { - auto s = p.Section("sceKernelMemory", 1, 4); + auto s = p.Section("sceKernelMemory", 1, 5); if (!s) return; @@ -363,10 +358,13 @@ void __KernelMemoryDoState(PointerWrap &p) if (s >= 3) volatileMemory.DoState(p); - Do(p, vplWaitTimer); - CoreTiming::RestoreRegisterEvent(vplWaitTimer, "VplTimeout", __KernelVplTimeout); - Do(p, fplWaitTimer); - CoreTiming::RestoreRegisterEvent(fplWaitTimer, "FplTimeout", __KernelFplTimeout); + if (s < 5) { + int oldTimeoutEvent = -1; + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "VplTimeout"); + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "FplTimeout"); + } Do(p, flags_); Do(p, sdkVersion_); Do(p, compilerVersion_); @@ -374,12 +372,11 @@ void __KernelMemoryDoState(PointerWrap &p) if (s >= 2) { Do(p, tlsplThreadEndChecks); } - if (s >= 4) { - Do(p, tlsplWaitTimer); - } else { - tlsplWaitTimer = -1; + if (s == 4) { + int oldTimeoutEvent = -1; + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "TlsplTimeout"); } - CoreTiming::RestoreRegisterEvent(tlsplWaitTimer, "TlsplTimeout", __KernelTlsplTimeout); MemBlockInfoDoState(p); } @@ -487,7 +484,7 @@ static bool __KernelUnlockFplForThread(FPL *fpl, FplWaitingThread &threadInfo, u } u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - HLEKernel::WriteRemainingTimeout(fplWaitTimer, threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr); __KernelResumeThreadFromWait(threadID, result); wokeThreads = true; @@ -496,7 +493,7 @@ static bool __KernelUnlockFplForThread(FPL *fpl, FplWaitingThread &threadInfo, u void __KernelFplBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, fplWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB: Suspending fpl wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) @@ -507,7 +504,7 @@ void __KernelFplBeginCallback(SceUID threadID, SceUID prevCallbackId) void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, fplWaitTimer, __KernelUnlockFplForThread); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelUnlockFplForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB: Resuming mbx wait from callback"); } @@ -636,15 +633,6 @@ void __KernelFplTimeout(u64 userdata, int cyclesLate) HLEKernel::WaitExecTimeout(threadID); } -static void __KernelSetFplTimeout(u32 timeoutPtr) -{ - if (timeoutPtr == 0 || fplWaitTimer == -1) - return; - - u32 micro = Memory::ReadOrException_U32(timeoutPtr); - CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), fplWaitTimer, __KernelGetCurThread()); -} - int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) { u32 error; FPL *fpl = kernelObjects.Get(uid, error); @@ -665,8 +653,7 @@ int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) { FplWaitingThread waiting = {threadID, blockPtrAddr}; fpl->waitingThreads.push_back(waiting); - __KernelSetFplTimeout(timeoutPtr); - __KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, false, "fpl waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_FPL, uid, 0, timeoutPtr, false, "fpl waited"); } return hleLogDebug(Log::sceKernel, 0); @@ -692,8 +679,7 @@ int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) { FplWaitingThread waiting = {threadID, blockPtrAddr}; fpl->waitingThreads.push_back(waiting); - __KernelSetFplTimeout(timeoutPtr); - __KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, true, "fpl waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_FPL, uid, 0, timeoutPtr, true, "fpl waited"); } return hleLogDebug(Log::sceKernel, 0); @@ -1275,7 +1261,7 @@ static bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u } u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - HLEKernel::WriteRemainingTimeout(vplWaitTimer, threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr); __KernelResumeThreadFromWait(threadID, result); wokeThreads = true; @@ -1284,7 +1270,7 @@ static bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u void __KernelVplBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, vplWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelAllocateVplCB: Suspending vpl wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) @@ -1295,7 +1281,7 @@ void __KernelVplBeginCallback(SceUID threadID, SceUID prevCallbackId) void __KernelVplEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, vplWaitTimer, __KernelUnlockVplForThread); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelUnlockVplForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(Log::sceKernel, "sceKernelAllocateVplCB: Resuming mbx wait from callback"); } @@ -1480,15 +1466,6 @@ void __KernelVplTimeout(u64 userdata, int cyclesLate) { } } -static void __KernelSetVplTimeout(u32 timeoutPtr) -{ - if (timeoutPtr == 0 || vplWaitTimer == -1) - return; - - u32 micro = Memory::ReadOrException_U32(timeoutPtr); - CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), vplWaitTimer, __KernelGetCurThread()); -} - int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) { u32 error, ignore; @@ -1508,8 +1485,7 @@ int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) vpl->waitingThreads.push_back(waiting); } - __KernelSetVplTimeout(timeoutPtr); - __KernelWaitCurThread(WAITTYPE_VPL, uid, size, timeoutPtr, false, "vpl waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_VPL, uid, size, timeoutPtr, false, "vpl waited"); } // If anyone else was waiting, the allocation causes a delay. else if (error == 0 && !vpl->waitingThreads.empty()) @@ -1540,8 +1516,7 @@ int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) vpl->waitingThreads.push_back(waiting); } - __KernelSetVplTimeout(timeoutPtr); - __KernelWaitCurThread(WAITTYPE_VPL, uid, size, timeoutPtr, true, "vpl waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_VPL, uid, size, timeoutPtr, true, "vpl waited"); } // If anyone else was waiting, the allocation causes a delay. else if (error == 0 && !vpl->waitingThreads.empty()) @@ -1828,7 +1803,7 @@ int __KernelFreeTls(TLSPL *tls, SceUID threadID) // _sceKernelAllocateTlspl waits with its address pointer as the wait value, sceKernelGetTlsAddr with 1. u32 error; u32 timeoutPtr = __KernelGetWaitTimeoutPtr(waitingThreadID, error); - HLEKernel::WriteRemainingTimeout(tlsplWaitTimer, waitingThreadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(waitingThreadID, timeoutPtr); u32 addrPtr = __KernelGetWaitValue(waitingThreadID, error); if (addrPtr != TLSPL_WAITVALUE_RETURN_ADDR) { Memory::WriteOrException_U32(freedAddress, addrPtr); @@ -2003,7 +1978,7 @@ int sceKernelDeleteTlspl(SceUID uid) // sceKernelGetTlsAddr returns a null address, _sceKernelAllocateTlspl an error. u32 error; u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - HLEKernel::WriteRemainingTimeout(tlsplWaitTimer, threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr); u32 result = __KernelGetWaitValue(threadID, error) != TLSPL_WAITVALUE_RETURN_ADDR ? SCE_KERNEL_ERROR_WAIT_DELETE : 0; HLEKernel::ResumeFromWait(threadID, WAITTYPE_TLSPL, uid, result); } @@ -2146,11 +2121,7 @@ int _sceKernelAllocateTlspl(SceUID uid, u32 addrPtr, u32 timeoutPtr) { if (allocAddress == 0) { SceUID threadID = __KernelGetCurThread(); tls->waitingThreads.push_back(threadID); - if (timeoutPtr != 0 && tlsplWaitTimer != -1) { - int micro = (int)Memory::ReadOrException_U32(timeoutPtr); - CoreTiming::ScheduleEvent(usToCycles(micro), tlsplWaitTimer, threadID); - } - __KernelWaitCurThread(WAITTYPE_TLSPL, uid, addrPtr, timeoutPtr, false, "allocate tls"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_TLSPL, uid, addrPtr, timeoutPtr, false, "allocate tls"); return hleLogDebug(Log::sceKernel, 0, "waiting for tls alloc"); } diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index f045a20718..375b404dfa 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -46,7 +46,6 @@ static const u32 MSGPIPE_WAIT_VALUE_SEND = 0; static const u32 MSGPIPE_WAIT_VALUE_RECV = 1; // State: the timer for MsgPipe timeouts. -static int waitTimer = -1; // NativeMsgPipe/MsgPipeWaitingThread/MsgPipe itself now live in sceKernelMsgPipe.h - see the // comment on the class there for why. @@ -67,7 +66,7 @@ void MsgPipeWaitingThread::WriteCurrentTimeout(SceUID waitID) const if (IsStillWaiting(waitID)) { u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - HLEKernel::WriteRemainingTimeout(waitTimer, threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr); } } @@ -266,7 +265,7 @@ static void __KernelMsgPipeTimeout(u64 userdata, int cyclesLate) } static bool __KernelSetMsgPipeTimeout(u32 timeoutPtr) { - if (timeoutPtr == 0 || waitTimer == -1) + if (timeoutPtr == 0) return true; // Always at once up to 2us, never from 3us: what threads/msgpipe/send and receive record, where @@ -277,8 +276,7 @@ static bool __KernelSetMsgPipeTimeout(u32 timeoutPtr) { return false; } - const u32 micro = Memory::ReadOrException_U32(timeoutPtr); - CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), waitTimer, __KernelGetCurThread()); + __KernelScheduleWaitTimeout(__KernelGetCurThread(), timeoutPtr); return true; } @@ -489,7 +487,7 @@ static void __KernelMsgPipeBeginCallback(SceUID threadID, SceUID prevCallbackId) case MSGPIPE_WAIT_VALUE_SEND: if (ko) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, waitTimer, ko->sendWaitingThreads, ko->pausedSendWaits, timeoutPtr != 0); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), ko->sendWaitingThreads, ko->pausedSendWaits, timeoutPtr != 0); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelSendMsgPipeCB: Suspending wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) @@ -502,7 +500,7 @@ static void __KernelMsgPipeBeginCallback(SceUID threadID, SceUID prevCallbackId) case MSGPIPE_WAIT_VALUE_RECV: if (ko) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, waitTimer, ko->receiveWaitingThreads, ko->pausedReceiveWaits, timeoutPtr != 0); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), ko->receiveWaitingThreads, ko->pausedReceiveWaits, timeoutPtr != 0); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMsgPipeCB: Suspending wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) @@ -569,7 +567,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) { if (ko == NULL) { // Deleted during the callback. u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0 && waitTimer != -1) + if (timeoutPtr != 0) Memory::WriteOrException_U32(0, timeoutPtr); __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); return; @@ -579,7 +577,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) { case MSGPIPE_WAIT_VALUE_SEND: { MsgPipeWaitingThread dummy; - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, waitTimer, __KernelCheckResumeMsgPipeSend, dummy, ko->sendWaitingThreads, ko->pausedSendWaits); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), __KernelCheckResumeMsgPipeSend, dummy, ko->sendWaitingThreads, ko->pausedSendWaits); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) { DEBUG_LOG(Log::sceKernel, "sceKernelSendMsgPipeCB: Resuming wait from callback"); } else if (result == HLEKernel::WAIT_CB_TIMED_OUT) { @@ -592,7 +590,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) { case MSGPIPE_WAIT_VALUE_RECV: { MsgPipeWaitingThread dummy; - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, waitTimer, __KernelCheckResumeMsgPipeReceive, dummy, ko->receiveWaitingThreads, ko->pausedReceiveWaits); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), __KernelCheckResumeMsgPipeReceive, dummy, ko->receiveWaitingThreads, ko->pausedReceiveWaits); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) { DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMsgPipeCB: Resuming wait from callback"); } else if (result == HLEKernel::WAIT_CB_TIMED_OUT) { @@ -609,19 +607,21 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) { void __KernelMsgPipeInit() { - waitTimer = CoreTiming::RegisterEvent("MsgPipeTimeout", __KernelMsgPipeTimeout); - __KernelRegisterWaitTypeFuncs(WAITTYPE_MSGPIPE, __KernelMsgPipeBeginCallback, __KernelMsgPipeEndCallback); + __KernelRegisterWaitTypeFuncs(WAITTYPE_MSGPIPE, __KernelMsgPipeBeginCallback, __KernelMsgPipeEndCallback, __KernelMsgPipeTimeout); } void __KernelMsgPipeDoState(PointerWrap &p) { - auto s = p.Section("sceKernelMsgPipe", 1); + auto s = p.Section("sceKernelMsgPipe", 1, 2); if (!s) return; - Do(p, waitTimer); - CoreTiming::RestoreRegisterEvent(waitTimer, "MsgPipeTimeout", __KernelMsgPipeTimeout); + if (s < 2) { + int oldTimeoutEvent = -1; + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "MsgPipeTimeout"); + } } int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, u32 optionsPtr) { diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 26367bc09d..39ffc834b9 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -117,8 +117,6 @@ struct LwMutex : public KernelObject std::map pausedWaits; }; -static int mutexWaitTimer = -1; -static int lwMutexWaitTimer = -1; // Thread -> Mutex locks for thread end. typedef std::unordered_multimap MutexMap; static MutexMap mutexHeldLocks; @@ -130,24 +128,25 @@ void __KernelLwMutexEndCallback(SceUID threadID, SceUID prevCallbackId); void __KernelMutexInit() { - mutexWaitTimer = CoreTiming::RegisterEvent("MutexTimeout", __KernelMutexTimeout); - lwMutexWaitTimer = CoreTiming::RegisterEvent("LwMutexTimeout", __KernelLwMutexTimeout); __KernelListenThreadEnd(&__KernelMutexThreadEnd); - __KernelRegisterWaitTypeFuncs(WAITTYPE_MUTEX, __KernelMutexBeginCallback, __KernelMutexEndCallback); - __KernelRegisterWaitTypeFuncs(WAITTYPE_LWMUTEX, __KernelLwMutexBeginCallback, __KernelLwMutexEndCallback); + __KernelRegisterWaitTypeFuncs(WAITTYPE_MUTEX, __KernelMutexBeginCallback, __KernelMutexEndCallback, __KernelMutexTimeout); + __KernelRegisterWaitTypeFuncs(WAITTYPE_LWMUTEX, __KernelLwMutexBeginCallback, __KernelLwMutexEndCallback, __KernelLwMutexTimeout); } void __KernelMutexDoState(PointerWrap &p) { - auto s = p.Section("sceKernelMutex", 1); + auto s = p.Section("sceKernelMutex", 1, 2); if (!s) return; - Do(p, mutexWaitTimer); - CoreTiming::RestoreRegisterEvent(mutexWaitTimer, "MutexTimeout", __KernelMutexTimeout); - Do(p, lwMutexWaitTimer); - CoreTiming::RestoreRegisterEvent(lwMutexWaitTimer, "LwMutexTimeout", __KernelLwMutexTimeout); + if (s < 2) { + int oldTimeoutEvent = -1; + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "MutexTimeout"); + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "LwMutexTimeout"); + } Do(p, mutexHeldLocks); } @@ -232,7 +231,7 @@ static bool __KernelUnlockMutexForThread(PSPMutex *mutex, SceUID threadID, u32 & } u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - HLEKernel::WriteRemainingTimeout(mutexWaitTimer, threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr); __KernelResumeThreadFromWait(threadID, result); return true; @@ -246,7 +245,7 @@ static bool __KernelUnlockMutexForThreadCheck(PSPMutex *mutex, SceUID threadID, void __KernelMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, mutexWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelLockMutexCB: Suspending lock wait for callback"); else @@ -255,7 +254,7 @@ void __KernelMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) void __KernelMutexEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, mutexWaitTimer, __KernelUnlockMutexForThreadCheck); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelUnlockMutexForThreadCheck); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(Log::sceKernel, "sceKernelLockMutexCB: Resuming lock wait for callback"); } @@ -428,18 +427,6 @@ void __KernelMutexThreadEnd(SceUID threadID) { } // The timeoutPtr is assumed to be checked by the caller to either be 0 or valid. -static void __KernelWaitMutex(PSPMutex *mutex, u32 timeoutPtr) { - _dbg_assert_(mutexWaitTimer != -1); // this could only come from extremely old savestates. - - if (timeoutPtr == 0 || mutexWaitTimer == -1) - return; - - u32 micro = Memory::ReadUnchecked_U32(timeoutPtr); - - // This should call __KernelMutexTimeout() later, unless we cancel it. - CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), mutexWaitTimer, __KernelGetCurThread()); -} - int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) { u32 error; PSPMutex *mutex = kernelObjects.Get(uid, error); @@ -513,8 +500,7 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) { // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end()) mutex->waitingThreads.push_back(threadID); - __KernelWaitMutex(mutex, timeoutPtr); - __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false, "mutex waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_MUTEX, id, count, timeoutPtr, false, "mutex waited"); // Return value will be overwritten by wait. return hleLogDebug(Log::sceKernel, 0); @@ -535,8 +521,7 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) { // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end()) mutex->waitingThreads.push_back(threadID); - __KernelWaitMutex(mutex, timeoutPtr); - __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, true, "mutex waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_MUTEX, id, count, timeoutPtr, true, "mutex waited"); // Return value will be overwritten by wait. return hleLogDebug(Log::sceKernel, 0); @@ -546,7 +531,7 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) { if (__KernelCurHasReadyCallbacks()) { // Might actually end up having to wait, so set the timeout. - __KernelWaitMutex(mutex, timeoutPtr); + __KernelScheduleWaitTimeout(__KernelGetCurThread(), timeoutPtr); __KernelWaitCallbacksCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr); // Return value will be written to callback's v0, but... that's probably fine? @@ -688,7 +673,7 @@ bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID, } const u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - HLEKernel::WriteRemainingTimeout(lwMutexWaitTimer, threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr); __KernelResumeThreadFromWait(threadID, result); return true; @@ -806,16 +791,6 @@ void __KernelLwMutexTimeout(u64 userdata, int cyclesLate) } // timeoutPtr is assumed to be checked by the caller to either be 0 or valid. -static void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr) { - if (timeoutPtr == 0 || lwMutexWaitTimer == -1) - return; - - u32 micro = Memory::ReadUnchecked_U32(timeoutPtr); - - // This should call __KernelLwMutexTimeout() later, unless we cancel it. - CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), lwMutexWaitTimer, __KernelGetCurThread()); -} - static bool __KernelUnlockLwMutexForThreadCheck(LwMutex *mutex, SceUID threadID, u32 &error, int result, bool &wokeThreads) { // The lock state lives in the workarea, nm.lockThread is only refreshed when referred. @@ -826,7 +801,7 @@ static bool __KernelUnlockLwMutexForThreadCheck(LwMutex *mutex, SceUID threadID, void __KernelLwMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, lwMutexWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelLockLwMutexCB: Suspending lock wait for callback"); else @@ -835,7 +810,7 @@ void __KernelLwMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) void __KernelLwMutexEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, lwMutexWaitTimer, __KernelUnlockLwMutexForThreadCheck); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelUnlockLwMutexForThreadCheck); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(Log::sceKernel, "sceKernelLockLwMutexCB: Resuming lock wait for callback"); } @@ -899,8 +874,7 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) { // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end()) mutex->waitingThreads.push_back(threadID); - __KernelWaitLwMutex(mutex, timeoutPtr); - __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea->uid, count, timeoutPtr, false, "lwmutex waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_LWMUTEX, workarea->uid, count, timeoutPtr, false, "lwmutex waited"); // Return value will be overwritten by wait. return hleLogVerbose(Log::sceKernel, 0); @@ -932,8 +906,7 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) { // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end()) mutex->waitingThreads.push_back(threadID); - __KernelWaitLwMutex(mutex, timeoutPtr); - __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea->uid, count, timeoutPtr, true, "lwmutex cb waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_LWMUTEX, workarea->uid, count, timeoutPtr, true, "lwmutex cb waited"); // Return value will be overwritten by wait. return hleLogVerbose(Log::sceKernel, 0); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index b4278a7d05..3e814d03d0 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -51,25 +51,26 @@ void PSPSemaphore::DoState(PointerWrap &p) { Do(p, pausedWaits); } -static int semaWaitTimer = -1; void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId); void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId); void __KernelSemaInit() { - semaWaitTimer = CoreTiming::RegisterEvent("SemaphoreTimeout", __KernelSemaTimeout); - __KernelRegisterWaitTypeFuncs(WAITTYPE_SEMA, __KernelSemaBeginCallback, __KernelSemaEndCallback); + __KernelRegisterWaitTypeFuncs(WAITTYPE_SEMA, __KernelSemaBeginCallback, __KernelSemaEndCallback, __KernelSemaTimeout); } void __KernelSemaDoState(PointerWrap &p) { - auto s = p.Section("sceKernelSema", 1); + auto s = p.Section("sceKernelSema", 1, 2); if (!s) return; - Do(p, semaWaitTimer); - CoreTiming::RestoreRegisterEvent(semaWaitTimer, "SemaphoreTimeout", __KernelSemaTimeout); + if (s < 2) { + int oldTimeoutEvent = -1; + Do(p, oldTimeoutEvent); + __KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "SemaphoreTimeout"); + } } KernelObject *__KernelSemaphoreObject() @@ -93,7 +94,7 @@ static bool __KernelUnlockSemaForThread(PSPSemaphore *s, SceUID threadID, u32 &e } u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - HLEKernel::WriteRemainingTimeout(semaWaitTimer, threadID, timeoutPtr); + HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr); __KernelResumeThreadFromWait(threadID, result); wokeThreads = true; @@ -102,7 +103,7 @@ static bool __KernelUnlockSemaForThread(PSPSemaphore *s, SceUID threadID, u32 &e void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, semaWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelWaitSemaCB: Suspending sema wait for callback"); else @@ -111,7 +112,7 @@ void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId) void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, semaWaitTimer, __KernelUnlockSemaForThread); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, __KernelUnlockSemaForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(Log::sceKernel, "sceKernelWaitSemaCB: Resuming sema wait for callback"); } @@ -290,15 +291,6 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate) { } } -static void __KernelSetSemaTimeout(PSPSemaphore *s, u32 timeoutPtr) { - if (timeoutPtr == 0 || semaWaitTimer == -1) - return; - - u32 micro = Memory::ReadOrException_U32(timeoutPtr); - // This should call __KernelSemaTimeout() later, unless we cancel it. - CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), semaWaitTimer, __KernelGetCurThread()); -} - static int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool processCallbacks) { hleEatCycles(900); @@ -326,8 +318,7 @@ static int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool pro // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. if (std::find(s->waitingThreads.begin(), s->waitingThreads.end(), threadID) == s->waitingThreads.end()) s->waitingThreads.push_back(threadID); - __KernelSetSemaTimeout(s, timeoutPtr); - __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks, "sema waited"); + __KernelWaitCurThreadWithTimeout(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks, "sema waited"); } return 0; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 921daca042..938a770ddd 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -477,6 +477,7 @@ struct WaitTypeFuncs { WaitBeginCallbackFunc beginFunc; WaitEndCallbackFunc endFunc; + WaitTimeoutFunc timeoutFunc; }; bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter); @@ -534,7 +535,7 @@ static ThreadQueueList threadReadyQueue; static SceUID threadIdleID[2]; static int eventScheduledWakeup; -static int eventThreadEndTimeout; +static int eventWaitTimeout; static bool dispatchEnabled = true; @@ -697,7 +698,7 @@ static void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId) { } static void __KernelThreadEndBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, eventThreadEndTimeout); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, eventWaitTimeout); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB: Suspending wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) @@ -713,7 +714,7 @@ static bool __KernelCheckResumeThreadEnd(PSPThread *t, SceUID waitingThreadID, u if (t->nt.status == THREADSTATUS_DORMANT) { u32 timeoutPtr = __KernelGetWaitTimeoutPtr(waitingThreadID, error); // Note: unlike the helper in KernelWaitHelpers.h, we unschedule even without a timeout ptr. - s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventThreadEndTimeout, waitingThreadID); + s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventWaitTimeout, waitingThreadID); cyclesLeft -= usToCycles(WAIT_TIMEOUT_LATENCY_US); if (cyclesLeft < 0) cyclesLeft = 0; @@ -729,7 +730,7 @@ static bool __KernelCheckResumeThreadEnd(PSPThread *t, SceUID waitingThreadID, u static void __KernelThreadEndEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, eventThreadEndTimeout, __KernelCheckResumeThreadEnd); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, eventWaitTimeout, __KernelCheckResumeThreadEnd); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB: Resuming wait from callback"); } @@ -761,6 +762,7 @@ u32 __KernelSetThreadRA(SceUID threadID, u32 nid) { void hleScheduledWakeup(u64 userdata, int cyclesLate); void hleThreadEndTimeout(u64 userdata, int cyclesLate); +static void __KernelWaitTimeoutFired(u64 userdata, int cyclesLate); static void __KernelWriteFakeSysCall(u32 nid, u32 *ptr, u32 &pos) { *ptr = pos; @@ -824,7 +826,7 @@ void __KernelThreadingInit() { } eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup); - eventThreadEndTimeout = CoreTiming::RegisterEvent("ThreadEndTimeout", &hleThreadEndTimeout); + eventWaitTimeout = CoreTiming::RegisterEvent("WaitTimeout", &__KernelWaitTimeoutFired); eventBusySyscallDone = CoreTiming::RegisterEvent("BusySyscallDone", &__KernelBusySyscallDone); busySyscalls.clear(); actionAfterMipsCall = __KernelRegisterActionType(ActionAfterMipsCall::Create); @@ -843,7 +845,7 @@ void __KernelThreadingInit() { __KernelRegisterWaitTypeFuncs(WAITTYPE_DELAY, __KernelDelayBeginCallback, __KernelDelayEndCallback); __KernelRegisterWaitTypeFuncs(WAITTYPE_SLEEP, __KernelSleepBeginCallback, __KernelSleepEndCallback); - __KernelRegisterWaitTypeFuncs(WAITTYPE_THREADEND, __KernelThreadEndBeginCallback, __KernelThreadEndEndCallback); + __KernelRegisterWaitTypeFuncs(WAITTYPE_THREADEND, __KernelThreadEndBeginCallback, __KernelThreadEndEndCallback, &hleThreadEndTimeout); } void __KernelThreadingDoState(PointerWrap &p) @@ -883,8 +885,8 @@ void __KernelThreadingDoState(PointerWrap &p) Do(p, eventScheduledWakeup); CoreTiming::RestoreRegisterEvent(eventScheduledWakeup, "ScheduledWakeup", &hleScheduledWakeup); - Do(p, eventThreadEndTimeout); - CoreTiming::RestoreRegisterEvent(eventThreadEndTimeout, "ThreadEndTimeout", &hleThreadEndTimeout); + Do(p, eventWaitTimeout); + CoreTiming::RestoreRegisterEvent(eventWaitTimeout, "WaitTimeout", &__KernelWaitTimeoutFired); Do(p, actionAfterMipsCall); __KernelRestoreActionType(actionAfterMipsCall, ActionAfterMipsCall::Create); Do(p, actionAfterCallback); @@ -1560,15 +1562,44 @@ void hleThreadEndTimeout(u64 userdata, int cyclesLate) HLEKernel::WaitExecTimeout(threadID); } -static void __KernelScheduleThreadEndTimeout(SceUID threadID, SceUID waitForID, s64 usFromNow) -{ - s64 cycles = usToCycles(usFromNow); - CoreTiming::ScheduleEvent(cycles, eventThreadEndTimeout, threadID); +// One event times out every kernel object wait (the thread only has one wait at a time), and hands +// over to the timeout function registered for the thread's wait type. +static void __KernelWaitTimeoutFired(u64 userdata, int cyclesLate) { + u32 error; + const PSPThread *thread = kernelObjects.Get((SceUID)userdata, error); + if (!thread) { + return; + } + const WaitTimeoutFunc func = waitTypeFuncs[thread->nt.waitType].timeoutFunc; + if (func) { + func(userdata, cyclesLate); + } +} + +int __KernelWaitTimeoutEvent() { + return eventWaitTimeout; +} + +void __KernelScheduleWaitTimeout(SceUID threadID, u32 timeoutPtr) { + if (timeoutPtr == 0) { + return; + } + const u32 micro = Memory::ReadOrException_U32(timeoutPtr); + CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), eventWaitTimeout, threadID); +} + +void __KernelWaitCurThreadWithTimeout(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr, bool processCallbacks, const char *reason) { + __KernelScheduleWaitTimeout(__KernelGetCurThread(), timeoutPtr); + __KernelWaitCurThread(type, waitID, waitValue, timeoutPtr, processCallbacks, reason); +} + +void __KernelRestoreOldWaitTimeoutEvent(int &eventType, const char *name) { + CoreTiming::RestoreRegisterEvent(eventType, name, &__KernelWaitTimeoutFired); } void __KernelCancelThreadEndTimeout(SceUID threadID) { - CoreTiming::UnscheduleEvent(eventThreadEndTimeout, threadID); + CoreTiming::UnscheduleEvent(eventWaitTimeout, threadID); } static void __KernelRemoveFromThreadQueue(SceUID threadID) { @@ -1597,7 +1628,7 @@ void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason) u32 timeoutPtr = __KernelGetWaitTimeoutPtr(waitingThread, error); if (HLEKernel::VerifyWait(waitingThread, WAITTYPE_THREADEND, threadID)) { - s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventThreadEndTimeout, waitingThread) - usToCycles(WAIT_TIMEOUT_LATENCY_US); + s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventWaitTimeout, waitingThread) - usToCycles(WAIT_TIMEOUT_LATENCY_US); if (cyclesLeft < 0) cyclesLeft = 0; if (timeoutPtr != 0) @@ -2852,8 +2883,7 @@ int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr) { { if (__KernelWaitTimesOutAtOnce(timeoutPtr)) return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT, "timed out at once"); - if (Memory::IsValidAddress(timeoutPtr)) - __KernelScheduleThreadEndTimeout(currentThread, threadID, __KernelWaitTimeoutUs(Memory::ReadUnchecked_U32(timeoutPtr))); + __KernelScheduleWaitTimeout(currentThread, Memory::IsValidAddress(timeoutPtr) ? timeoutPtr : 0); if (std::find(t->waitingThreads.begin(), t->waitingThreads.end(), currentThread) == t->waitingThreads.end()) t->waitingThreads.push_back(currentThread); __KernelWaitCurThread(WAITTYPE_THREADEND, threadID, 0, timeoutPtr, false, "thread wait end"); @@ -2881,8 +2911,7 @@ int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr) { { if (__KernelWaitTimesOutAtOnce(timeoutPtr)) return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT, "timed out at once"); - if (Memory::IsValidAddress(timeoutPtr)) - __KernelScheduleThreadEndTimeout(currentThread, threadID, __KernelWaitTimeoutUs(Memory::ReadUnchecked_U32(timeoutPtr))); + __KernelScheduleWaitTimeout(currentThread, Memory::IsValidAddress(timeoutPtr) ? timeoutPtr : 0); if (std::find(t->waitingThreads.begin(), t->waitingThreads.end(), currentThread) == t->waitingThreads.end()) t->waitingThreads.push_back(currentThread); __KernelWaitCurThread(WAITTYPE_THREADEND, threadID, 0, timeoutPtr, true, "thread wait end"); @@ -3844,10 +3873,11 @@ void __KernelNotifyCallback(SceUID cbId, int notifyArg) } } -void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc) +void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc, WaitTimeoutFunc timeoutFunc) { waitTypeFuncs[type].beginFunc = beginFunc; waitTypeFuncs[type].endFunc = endFunc; + waitTypeFuncs[type].timeoutFunc = timeoutFunc; } std::vector GetThreadsInfo() { diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 904d4f2294..3f45b94988 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -137,7 +137,9 @@ typedef void (* WaitBeginCallbackFunc)(SceUID threadID, SceUID prevCallbackId); // Resume wait and timeout as a thread exits a callback. typedef void (* WaitEndCallbackFunc)(SceUID threadID, SceUID prevCallbackId); -void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc); +typedef void (*WaitTimeoutFunc)(u64 threadID, int cyclesLate); +// timeoutFunc runs when a wait of this type, started with __KernelWaitCurThreadWithTimeout(), times out. +void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc, WaitTimeoutFunc timeoutFunc = nullptr); #if COMMON_LITTLE_ENDIAN typedef WaitType WaitType_le; @@ -385,6 +387,14 @@ void __KernelWaitCurThread(WaitType type, SceUID waitId, u32 waitValue, u32 time // See the definition for how hardware times waits out. bool __KernelWaitTimesOutAtOnce(u32 timeoutPtr, int basePercent = 85, int stepPercent = 35); s64 __KernelWaitTimeoutUs(u32 micro); +// The one CoreTiming event every kernel object wait's timeout runs on, keyed by thread. +int __KernelWaitTimeoutEvent(); +// Schedules the timeout for a wait about to start, if timeoutPtr (0 or valid) gives one. +void __KernelScheduleWaitTimeout(SceUID threadID, u32 timeoutPtr); +// Starts a wait on a kernel object, with the timeout the hardware would use. +void __KernelWaitCurThreadWithTimeout(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr, bool processCallbacks, const char *reason); +// Old savestates had an event per kind of object. Points one at the shared handler. +void __KernelRestoreOldWaitTimeoutEvent(int &eventType, const char *name); // How long after its deadline a wait's timeout goes off. Not part of the time left written back. const int WAIT_TIMEOUT_LATENCY_US = 18; // The deadline is taken this far into the call, after what we already charge before scheduling.