From f9b561ee42f0df883678d89e7126ba930cd3f984 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 7 Dec 2012 19:01:31 -0800 Subject: [PATCH] Implement priority unlocking for mutexes. --- Core/HLE/sceKernelMutex.cpp | 180 ++++++++++++++++++------------------ test.py | 5 +- 2 files changed, 93 insertions(+), 92 deletions(-) diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 23232590ae..5c30aad005 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -161,6 +161,26 @@ void __KernelMutexEraseLock(Mutex *mutex) mutex->nm.lockThread = -1; } +std::vector::iterator __KernelMutexFindPriority(std::vector &waiting) +{ + _dbg_assert_msg_(HLE, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads."); + + std::vector::iterator iter, end, best = waiting.end(); + u32 best_prio = 0xFFFFFFFF; + for (iter = waiting.begin(), end = waiting.end(); iter != end; ++iter) + { + u32 iter_prio = __KernelGetThreadPrio(*iter); + if (iter_prio < best_prio) + { + best = iter; + best_prio = iter_prio; + } + } + + _dbg_assert_msg_(HLE, best != waiting.end(), "__KernelMutexFindPriority: Returning invalid best thread."); + return best; +} + void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!mutexInitComplete) @@ -203,6 +223,33 @@ void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 opti RETURN(id); } +bool __KernelUnlockMutexForThread(Mutex *mutex, SceUID threadID, u32 &error, int result) +{ + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + return false; + + // If result is an error code, we're just letting it go. + if (result == 0) + { + int wVal = (int)__KernelGetWaitValue(threadID, error); + __KernelMutexAcquireLock(mutex, wVal, threadID); + } + + if (timeoutPtr != 0 && mutexWaitTimer != 0) + { + // Remove any event for this thread. + u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); + Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + } + + __KernelResumeThreadFromWait(threadID, result); + return true; +} + void sceKernelDeleteMutex(SceUID id) { DEBUG_LOG(HLE,"sceKernelDeleteMutex(%i)", id); @@ -213,24 +260,8 @@ void sceKernelDeleteMutex(SceUID id) bool wokeThreads = false; std::vector::iterator iter, end; 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; + wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE); - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0 && mutexWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); - wokeThreads = true; - } if (mutex->nm.lockThread != -1) __KernelMutexEraseLock(mutex); mutex->waitingThreads.clear(); @@ -289,37 +320,17 @@ bool __KernelUnlockMutex(Mutex *mutex, u32 &error) { __KernelMutexEraseLock(mutex); - // 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) + std::vector::iterator iter; + while (!wokeThreads && !mutex->waitingThreads.empty()) { - 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; - } + if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0) + iter = __KernelMutexFindPriority(mutex->waitingThreads); + else + iter = mutex->waitingThreads.begin(); - int wVal = (int)__KernelGetWaitValue(threadID, error); - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - - __KernelMutexAcquireLock(mutex, wVal, threadID); - - if (timeoutPtr != 0 && mutexWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, 0); - wokeThreads = true; + wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, 0); mutex->waitingThreads.erase(iter); - break; } if (!wokeThreads) @@ -530,6 +541,33 @@ void sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int ini RETURN(0); } +bool __KernelUnlockLwMutexForThread(LwMutex *mutex, NativeLwMutexWorkarea &workarea, SceUID threadID, u32 &error, int result) +{ + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + return false; + + // If result is an error code, we're just letting it go. + if (result == 0) + { + workarea.lockLevel = (int) __KernelGetWaitValue(threadID, error); + workarea.lockThread = threadID; + } + + if (timeoutPtr != 0 && lwMutexWaitTimer != 0) + { + // Remove any event for this thread. + u64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID); + Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + } + + __KernelResumeThreadFromWait(threadID, result); + return true; +} + void sceKernelDeleteLwMutex(u32 workareaPtr) { DEBUG_LOG(HLE,"sceKernelDeleteLwMutex(%08x)", workareaPtr); @@ -550,24 +588,7 @@ void sceKernelDeleteLwMutex(u32 workareaPtr) bool wokeThreads = false; std::vector::iterator iter, end; 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) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); - wokeThreads = true; - } + wokeThreads |= __KernelUnlockLwMutexForThread(mutex, workarea, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE); mutex->waitingThreads.clear(); RETURN(kernelObjects.Destroy(workarea.uid)); @@ -641,38 +662,17 @@ bool __KernelUnlockLwMutex(NativeLwMutexWorkarea &workarea, u32 &error) return false; } - // 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) + std::vector::iterator iter; + while (!wokeThreads && !mutex->waitingThreads.empty()) { - 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; - } + if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0) + iter = __KernelMutexFindPriority(mutex->waitingThreads); + else + iter = mutex->waitingThreads.begin(); - int wVal = (int)__KernelGetWaitValue(threadID, error); - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - - workarea.lockLevel = wVal; - workarea.lockThread = threadID; - - if (timeoutPtr != 0 && lwMutexWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, 0); - wokeThreads = true; + wokeThreads |= __KernelUnlockLwMutexForThread(mutex, workarea, *iter, error, 0); mutex->waitingThreads.erase(iter); - break; } if (!wokeThreads) diff --git a/test.py b/test.py index e6b53b375f..e35edb93bc 100755 --- a/test.py +++ b/test.py @@ -60,13 +60,16 @@ tests_good = [ "threads/lwmutex/create/create", "threads/lwmutex/delete/delete", "threads/lwmutex/lock/lock", + "threads/lwmutex/priority/priority", "threads/lwmutex/try/try", "threads/lwmutex/try600/try600", "threads/lwmutex/unlock/unlock", "threads/mbx/mbx", + "threads/mutex/mutex", "threads/mutex/create/create", "threads/mutex/delete/delete", "threads/mutex/lock/lock", + "threads/mutex/priority/priority", "threads/mutex/try/try", "threads/mutex/unlock/unlock", "threads/semaphores/semaphores", @@ -89,8 +92,6 @@ tests_next = [ "threads/fpl/fpl", "threads/k0/k0", "threads/msgpipe/msgpipe", - "threads/mutex/mutex", - "threads/mutex/priority/priority", "threads/scheduling/scheduling", "threads/semaphores/priority/priority", "threads/threads/threads",