From 4d71e32193a3ac3ae9d9df2e8779ef9f6eee06cb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 18 Nov 2012 19:13:39 -0800 Subject: [PATCH] Update the value when mutexes timeout. --- Core/CoreTiming.cpp | 14 +++++++++++--- Core/CoreTiming.h | 6 +++++- Core/HLE/sceKernelMutex.cpp | 37 +++++++++++++++++++++++------------- Core/HLE/sceKernelThread.cpp | 14 ++++++++++++++ Core/HLE/sceKernelThread.h | 1 + 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index cca5f1f51d..eea6b3b4a9 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -249,14 +249,18 @@ void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata) AddEventToQueue(ne); } -void UnscheduleEvent(int event_type, u64 userdata) +// Returns cycles left in timer. +int UnscheduleEvent(int event_type, u64 userdata) { + int result = 0; if (!first) - return; + return result; while(first) { if (first->type == event_type && first->userdata == userdata) { + result = (int)(first->time - globalTimer); + Event *next = first->next; FreeEvent(first); first = next; @@ -267,13 +271,15 @@ void UnscheduleEvent(int event_type, u64 userdata) } } if (!first) - return; + return result; Event *prev = first; Event *ptr = prev->next; while (ptr) { if (ptr->type == event_type && ptr->userdata == userdata) { + result = (int)(ptr->time - globalTimer); + prev->next = ptr->next; FreeEvent(ptr); ptr = prev->next; @@ -284,6 +290,8 @@ void UnscheduleEvent(int event_type, u64 userdata) ptr = ptr->next; } } + + return result; } void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted)) diff --git a/Core/CoreTiming.h b/Core/CoreTiming.h index bd8605b8d1..dcb9f75e8a 100644 --- a/Core/CoreTiming.h +++ b/Core/CoreTiming.h @@ -58,6 +58,10 @@ inline int usToCycles(int us) { return (int)(CPU_HZ / 1000000 * us); } +inline int cyclesToUs(int cycles) { + return cycles / (CPU_HZ / 1000000); +} + namespace CoreTiming { void Init(); @@ -77,7 +81,7 @@ namespace CoreTiming void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata=0); void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata=0); void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata=0); - void UnscheduleEvent(int event_type, u64 userdata); + int UnscheduleEvent(int event_type, u64 userdata); void RemoveEvent(int event_type); void RemoveThreadsafeEvent(int event_type); diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 36b41aa981..5ad3929218 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -116,22 +116,25 @@ void sceKernelDeleteMutex(SceUID id) Mutex *mutex = kernelObjects.Get(id, error); if (mutex) { - // Kill the timer, they're waking up now. - if (mutex->waitTimer != 0) - { - CoreTiming::RemoveEvent(mutex->waitTimer); - mutex->waitTimer = 0; - } - std::vector::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + if (timeoutPtr != 0 && mutex->waitTimer != 0) + { + // Remove any event for this thread. + int cyclesLeft = CoreTiming::UnscheduleEvent(mutex->waitTimer, threadID); + Memory::Write_U32(cyclesToUs(cyclesLeft), timeoutPtr); + } + __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); - // TODO: set timeoutPtr. } mutex->waitingThreads.empty(); + // TODO: Any way to erase the CoreTiming event type? We leak. + RETURN(kernelObjects.Destroy(id)); __KernelReSchedule("mutex deleted"); } @@ -184,7 +187,12 @@ bool __KernelLockMutex(Mutex *mutex, int count, u32 &error) void __KernelMutexTimeout(u64 userdata, int cyclesLate) { SceUID threadID = (SceUID)userdata; - // TODO: set timeoutPtr. + + u32 error; + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + if (timeoutPtr != 0) + Memory::Write_U32(0, timeoutPtr); + __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); } @@ -310,14 +318,17 @@ void sceKernelUnlockMutex(SceUID id, int count) SceUID threadID = *iter; int wVal = (int)__KernelGetWaitValue(threadID, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); mutex->nm.lockThread = threadID; mutex->nm.lockLevel = wVal; - // Remove any event for this thread. - // TODO: Only if timeoutPtr? - if (mutex->waitTimer != 0) - CoreTiming::UnscheduleEvent(mutex->waitTimer, threadID); + if (timeoutPtr != 0 && mutex->waitTimer != 0) + { + // Remove any event for this thread. + int cyclesLeft = CoreTiming::UnscheduleEvent(mutex->waitTimer, threadID); + Memory::Write_U32(cyclesToUs(cyclesLeft), timeoutPtr); + } __KernelResumeThreadFromWait(threadID, 0); wokeThreads = true; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index a2c5e82220..49d645e25c 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -393,6 +393,20 @@ u32 __KernelGetWaitValue(SceUID threadID, u32 &error) } } +u32 __KernelGetWaitTimeoutPtr(SceUID threadID, u32 &error) +{ + Thread *t = kernelObjects.Get(threadID, error); + if (t) + { + return t->waitInfo.timeoutPtr; + } + else + { + ERROR_LOG(HLE, "__KernelGetWaitValue ERROR: thread %i", threadID); + return 0; + } +} + void sceKernelReferThreadStatus() { SceUID threadID = PARAM(0); diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index a84a75d685..57f07b8e11 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -106,6 +106,7 @@ u32 __KernelResumeThreadFromWait(SceUID threadID); // can return an error value u32 __KernelResumeThreadFromWait(SceUID threadID, int retval); u32 __KernelGetWaitValue(SceUID threadID, u32 &error); +u32 __KernelGetWaitTimeoutPtr(SceUID threadID, u32 &error); void __KernelWaitCurThread(WaitType type, SceUID waitId, u32 waitValue, u32 timeoutPtr, bool processCallbacks); void __KernelReSchedule(const char *reason = "no reason"); void __KernelReSchedule(bool doCallbacks, const char *reason);