diff --git a/Core/HLE/KernelWaitHelpers.h b/Core/HLE/KernelWaitHelpers.h index e5edb005df..fa01f331c5 100644 --- a/Core/HLE/KernelWaitHelpers.h +++ b/Core/HLE/KernelWaitHelpers.h @@ -25,6 +25,9 @@ namespace HLEKernel { +// 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. template inline bool WaitPauseHelperUpdate(SceUID pauseKey, SceUID threadID, std::vector &waitingThreads, std::map &pausedWaits, u64 pauseTimeout) { WaitInfoType waitData = {0}; @@ -47,6 +50,9 @@ inline bool WaitPauseHelperUpdate(SceUID pauseKey, SceUID threadID, std::vector< return true; } +// Move a thread from the waiting thread list to the paused thread list. +// This version is for a simpler list of SceUIDs. The paused list is a std::map. +// Should not be called directly. template <> inline bool WaitPauseHelperUpdate(SceUID pauseKey, SceUID threadID, std::vector &waitingThreads, std::map &pausedWaits, u64 pauseTimeout) { // TODO: Hmm, what about priority/fifo order? Does it lose its place in line? @@ -55,6 +61,9 @@ inline bool WaitPauseHelperUpdate(SceUID pauseKey, SceUID threadID, return true; } +// Retrieve the paused wait info from the list, and pop it. +// Returns the pausedTimeout value. +// Should not be called directly. template inline u64 WaitPauseHelperGet(SceUID pauseKey, SceUID threadID, std::map &pausedWaits, WaitInfoType &waitData) { waitData = pausedWaits[pauseKey]; @@ -63,6 +72,9 @@ inline u64 WaitPauseHelperGet(SceUID pauseKey, SceUID threadID, std::map inline u64 WaitPauseHelperGet(SceUID pauseKey, SceUID threadID, std::map &pausedWaits, SceUID &waitData) { waitData = threadID; @@ -72,12 +84,26 @@ inline u64 WaitPauseHelperGet(SceUID pauseKey, SceUID threadID, std } enum WaitBeginEndCallbackResult { + // Returned when the thread cannot be found in the waiting threads list. + // Only returned for struct types, which have other data than the threadID. WAIT_CB_BAD_WAIT_DATA = -2, + // Returned when the wait ID of the thread no longer matches the kernel object. WAIT_CB_BAD_WAIT_ID = -1, + // Success, whether that means the wait was paused, deleted, etc. WAIT_CB_SUCCESS = 0, + // Success, and resumed waiting. Useful for logging. WAIT_CB_RESUMED_WAIT = 1, }; +// Meant to be called in a registered begin callback function for a wait type. +// +// The goal of this function is to pause the wait. While inside a callback, waits are released. +// Once the callback returns, the wait should be resumed (see WaitEndCallback.) +// +// This assumes the object has been validated already. The primary purpose is if you need +// to use a specific pausedWaits list (for example, sceMsgPipe has two types of waiting per object.) +// +// In most cases, use the other, simpler version of WaitBeginCallback(). template WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbackId, int waitTimer, std::vector &waitingThreads, std::map &pausedWaits, bool doTimeout = true) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; @@ -101,6 +127,12 @@ WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbac return WAIT_CB_SUCCESS; } +// Meant to be called in a registered begin callback function for a wait type. +// +// The goal of this function is to pause the wait. While inside a callback, waits are released. +// Once the callback returns, the wait should be resumed (see WaitEndCallback.) +// +// In the majority of cases, calling this function is sufficient for the BeginCallback handler. template WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbackId, int waitTimer) { u32 error; @@ -114,6 +146,15 @@ WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbac } } +// 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. +// +// This version allows you to specify the pausedWaits and waitingThreads vectors, primarily for +// MsgPipes which have two waiting thread lists. Unlike the matching WaitBeginCallback() function, +// this still validates the wait (since it needs other data from the object.) +// +// In most cases, use the other, simpler version of WaitEndCallback(). template WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackId, int waitTimer, TryUnlockFunc TryUnlock, std::vector &waitingThreads, std::map &pausedWaits) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; @@ -165,12 +206,19 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI } } +// 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. +// +// The TryUnlockFunc signature should be (choosen due to similarity to existing funcitons): +// bool TryUnlock(KO *ko, WaitInfoType waitingThreadInfo, u32 &error, int result, bool &wokeThreads) template WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackId, int waitTimer, TryUnlockFunc TryUnlock) { u32 error; SceUID uid = __KernelGetWaitID(threadID, waitType, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); KO *ko = uid == 0 ? NULL : kernelObjects.Get(uid, error); + // We need the ko for the vectors, but to avoid a null check we validate it here too. if (!ko) { // TODO: Since it was deleted, we don't know how long was actually left. // For now, we just say the full time was taken.