From 305c41c932d399e1897c3743243f27aa4bdf260e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 31 Dec 2012 23:23:52 -0800 Subject: [PATCH] Prevent duplicate waiting threads in sema/mutex. If something did a tight loop of a short wait/timeout, it might end up getting on the waitingThreads list multiple times. Eventually this caused a massive performance problem. --- Core/HLE/sceKernelMutex.cpp | 20 ++++++++++++++++---- Core/HLE/sceKernelSemaphore.cpp | 6 +++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index a591e4ce6d..4469dc0601 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -456,7 +456,10 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) return error; else { - mutex->waitingThreads.push_back(__KernelGetCurThread()); + SceUID threadID = __KernelGetCurThread(); + // 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); @@ -481,7 +484,10 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) return error; else { - mutex->waitingThreads.push_back(__KernelGetCurThread()); + SceUID threadID = __KernelGetCurThread(); + // 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); @@ -813,7 +819,10 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) LwMutex *mutex = kernelObjects.Get(workarea.uid, error); if (mutex) { - mutex->waitingThreads.push_back(__KernelGetCurThread()); + SceUID threadID = __KernelGetCurThread(); + // 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); @@ -846,7 +855,10 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) LwMutex *mutex = kernelObjects.Get(workarea.uid, error); if (mutex) { - mutex->waitingThreads.push_back(__KernelGetCurThread()); + SceUID threadID = __KernelGetCurThread(); + // 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); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index f9e5cd4e0b..8fbeb4e674 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -360,7 +360,11 @@ int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *bad else { s->ns.numWaitThreads++; - s->waitingThreads.push_back(__KernelGetCurThread()); + + SceUID threadID = __KernelGetCurThread(); + // 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); }