diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 8a0224cb7d..bf024fbd44 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -215,6 +215,10 @@ void sceKernelDeleteMutex(SceUID id) for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); + // The waitID may be different after a timeout. + if (waitID != id) + continue; u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); if (timeoutPtr != 0 && mutexWaitTimer != 0) @@ -288,9 +292,17 @@ bool __KernelUnlockMutex(Mutex *mutex, u32 &error) // TODO: PSP_MUTEX_ATTR_PRIORITY bool wokeThreads = false; std::vector::iterator iter, end; +retry: for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + { + mutex->waitingThreads.erase(iter); + goto retry; + } int wVal = (int)__KernelGetWaitValue(threadID, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); @@ -325,14 +337,6 @@ void __KernelMutexTimeout(u64 userdata, int cyclesLate) if (timeoutPtr != 0) Memory::Write_U32(0, timeoutPtr); - SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); - Mutex *mutex = kernelObjects.Get(mutexID, error); - if (mutex) - { - // This thread isn't waiting anymore. - mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end()); - } - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); } @@ -543,6 +547,10 @@ void sceKernelDeleteLwMutex(u32 workareaPtr) for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + continue; u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); if (timeoutPtr != 0 && lwMutexWaitTimer != 0) @@ -631,9 +639,17 @@ bool __KernelUnlockLwMutex(NativeLwMutexWorkarea &workarea, u32 &error) // TODO: PSP_MUTEX_ATTR_PRIORITY bool wokeThreads = false; std::vector::iterator iter, end; +retry: for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + { + mutex->waitingThreads.erase(iter); + goto retry; + } int wVal = (int)__KernelGetWaitValue(threadID, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); @@ -669,14 +685,6 @@ void __KernelLwMutexTimeout(u64 userdata, int cyclesLate) if (timeoutPtr != 0) Memory::Write_U32(0, timeoutPtr); - SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); - LwMutex *mutex = kernelObjects.Get(mutexID, error); - if (mutex) - { - // This thread isn't waiting anymore. - mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end()); - } - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); } diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index ccbc46c035..b82f9f8efe 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -80,9 +80,13 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason) std::vector::iterator iter; for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) { - SceUID threadID = *iter; - u32 error; + SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); + // The waitID may be different after a timeout. + if (waitID != s->GetUID()) + continue; + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); if (timeoutPtr != 0 && semaWaitTimer != 0) { @@ -242,6 +246,13 @@ retry: for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) { SceUID threadID = *iter; + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); + // The waitID may be different after a timeout. + if (waitID != s->GetUID()) + { + s->waitingThreads.erase(iter); + goto retry; + } int wVal = (int)__KernelGetWaitValue(threadID, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); @@ -288,8 +299,7 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate) Semaphore *s = kernelObjects.Get(semaID, error); if (s) { - // This thread isn't waiting anymore. - s->waitingThreads.erase(std::remove(s->waitingThreads.begin(), s->waitingThreads.end(), threadID), s->waitingThreads.end()); + // This thread isn't waiting anymore, but we'll remove it from waitingThreads later. s->ns.numWaitThreads--; } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index c6bee53c8f..c20a70c951 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1545,6 +1545,10 @@ void __KernelSwitchContext(Thread *target, const char *reason) __KernelLoadContext(¤tThread->context); DEBUG_LOG(HLE,"Context loaded (%s): %i - %s - pc: %08x", reason, currentThread->GetUID(), currentThread->GetName(), currentMIPS->pc); + // No longer waiting. + currentThread->nt.waitType = WAITTYPE_NONE; + currentThread->nt.waitID = 0; + __KernelExecutePendingMipsCalls(); }