From 94e88943d814a8adf90eb5923ca083d391ad5c1a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Sep 2013 01:05:55 -0700 Subject: [PATCH 1/7] Keep a single list of pending callbacks. Doing it per type only meant that we'd incorrectly call a callback twice if it was notified by e.g. scePowerRegisterCallback() and sceKernelNotifyThread(), which isn't what's supposed to happen. --- Core/HLE/sceKernelThread.cpp | 51 +++++++++++++++--------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 2a26309494..b8e6f38fb9 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -510,8 +510,8 @@ public: for (size_t i = 0; i < THREAD_CALLBACK_NUM_TYPES; ++i) { p.Do(registeredCallbacks[i]); - p.Do(readyCallbacks[i]); } + p.Do(readyCallbacks); p.Do(pendingMipsCalls); p.Do(pushedStacks); @@ -532,7 +532,7 @@ public: ThreadContext context; std::set registeredCallbacks[THREAD_CALLBACK_NUM_TYPES]; - std::list readyCallbacks[THREAD_CALLBACK_NUM_TYPES]; + std::list readyCallbacks; std::list pendingMipsCalls; @@ -1764,11 +1764,7 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason) u32 error; Thread *t = kernelObjects.Get(threadID, error); if (t) - { - // TODO: Unless they should be run before deletion? - for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) - readyCallbacksCount -= (int)t->readyCallbacks[i].size(); - } + readyCallbacksCount -= (int)t->readyCallbacks.size(); return kernelObjects.Destroy(threadID); } @@ -3444,10 +3440,8 @@ bool __KernelCurHasReadyCallbacks() { return false; Thread *thread = __GetCurrentThread(); - for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) { - if (thread->readyCallbacks[i].size()) { - return true; - } + if (thread->readyCallbacks.size()) { + return true; } return false; @@ -3460,22 +3454,20 @@ bool __KernelCheckThreadCallbacks(Thread *thread, bool force) if (!thread || (!thread->isProcessingCallbacks && !force)) return false; - for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) { - if (thread->readyCallbacks[i].size()) { - SceUID readyCallback = thread->readyCallbacks[i].front(); - thread->readyCallbacks[i].pop_front(); - readyCallbacksCount--; + if (thread->readyCallbacks.size()) { + SceUID readyCallback = thread->readyCallbacks.front(); + thread->readyCallbacks.pop_front(); + readyCallbacksCount--; - // If the callback was deleted, we're good. Just skip it. - if (kernelObjects.IsValid(readyCallback)) - { - __KernelRunCallbackOnThread(readyCallback, thread, !force); // makes pending - return true; - } - else - { - WARN_LOG(SCEKERNEL, "Ignoring deleted callback %08x", readyCallback); - } + // If the callback was deleted, we're good. Just skip it. + if (kernelObjects.IsValid(readyCallback)) + { + __KernelRunCallbackOnThread(readyCallback, thread, !force); // makes pending + return true; + } + else + { + WARN_LOG(SCEKERNEL, "Ignoring deleted callback %08x", readyCallback); } } return false; @@ -3586,11 +3578,10 @@ void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notify cb->nc.notifyArg = notifyArg; Thread *t = kernelObjects.Get(cb->nc.threadId, error); - std::list &readyCallbacks = t->readyCallbacks[type]; - auto iter = std::find(readyCallbacks.begin(), readyCallbacks.end(), cbId); - if (iter == readyCallbacks.end()) + auto iter = std::find(t->readyCallbacks.begin(), t->readyCallbacks.end(), cbId); + if (iter == t->readyCallbacks.end()) { - t->readyCallbacks[type].push_back(cbId); + t->readyCallbacks.push_back(cbId); readyCallbacksCount++; } } From 64b75ed3ffaa15291412bce259029d7ac7c0435e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Sep 2013 01:25:41 -0700 Subject: [PATCH 2/7] Decentralize callback registration. Callbacks are always tied to THEIR thread, and the registration was all based on the current thread which is just not the right way. --- Core/HLE/sceIo.cpp | 30 +++++++++++++---- Core/HLE/sceKernel.cpp | 7 ++-- Core/HLE/sceKernelThread.cpp | 62 ++---------------------------------- Core/HLE/sceKernelThread.h | 23 +------------ Core/HLE/scePower.cpp | 5 +-- Core/HLE/sceUmd.cpp | 15 +++------ 6 files changed, 35 insertions(+), 107 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 12fe6ac838..e253a2e924 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include "native/thread/thread.h" #include "native/thread/threadutil.h" #include "Core/Config.h" @@ -108,6 +109,8 @@ const int PSP_MIN_FD = 4; static int asyncNotifyEvent = -1; static int syncNotifyEvent = -1; static SceUID fds[PSP_COUNT_FDS]; +static std::set memStickCallbacks; +static std::set memStickFatCallbacks; static AsyncIOManager ioManager; static bool ioManagerThreadEnabled = false; static std::thread *ioManagerThread; @@ -466,6 +469,8 @@ void __IoDoState(PointerWrap &p) { CoreTiming::RestoreRegisterEvent(asyncNotifyEvent, "IoAsyncNotify", __IoAsyncNotify); p.Do(syncNotifyEvent); CoreTiming::RestoreRegisterEvent(syncNotifyEvent, "IoSyncNotify", __IoSyncNotify); + p.Do(memStickCallbacks); + p.Do(memStickFatCallbacks); p.DoMarker("sceIo"); } @@ -487,6 +492,9 @@ void __IoShutdown() { memstickSystem = NULL; delete flash0System; flash0System = NULL; + + memStickCallbacks.clear(); + memStickFatCallbacks.clear(); } u32 __IoGetFileHandleFromId(u32 id, u32 &outError) @@ -552,7 +560,7 @@ void __IoCompleteAsyncIO(int fd) { // It's okay, not all operations are deferred. } if (f->callbackID) { - __KernelNotifyCallback(THREAD_CALLBACK_IO, f->callbackID, f->callbackArg); + __KernelNotifyCallback(f->callbackID, f->callbackArg); } f->pendingAsyncResult = false; f->hasAsyncResult = true; @@ -1262,10 +1270,12 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, case 0x02015804: // Register MemoryStick's insert/eject callback (mscmhc0) if (Memory::IsValidAddress(argAddr) && argLen == 4) { + // TODO: Verify how duplicates work / how many are allowed. u32 cbId = Memory::Read_U32(argAddr); - if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) { + if (memStickCallbacks.find(cbId) == memStickCallbacks.end()) { + memStickCallbacks.insert(cbId); DEBUG_LOG(SCEIO, "sceIoDevCtl: Memstick callback %i registered, notifying immediately.", cbId); - __KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK, cbId, MemoryStick_State()); + __KernelNotifyCallback(cbId, MemoryStick_State()); return 0; } else { return ERROR_MEMSTICK_DEVCTL_TOO_MANY_CALLBACKS; @@ -1277,8 +1287,10 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, case 0x02025805: // Unregister MemoryStick's insert/eject callback (mscmhc0) if (Memory::IsValidAddress(argAddr) && argLen == 4) { + // TODO: Verify how duplicates work / how many are allowed. u32 cbId = Memory::Read_U32(argAddr); - if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) { + if (memStickCallbacks.find(cbId) != memStickCallbacks.end()) { + memStickCallbacks.erase(cbId); DEBUG_LOG(SCEIO, "sceIoDevCtl: Unregistered memstick callback %i", cbId); return 0; } else { @@ -1337,10 +1349,12 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, switch (cmd) { case 0x02415821: // MScmRegisterMSInsertEjectCallback { + // TODO: Verify how duplicates work / how many are allowed. u32 cbId = Memory::Read_U32(argAddr); - if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) { + if (memStickFatCallbacks.find(cbId) == memStickFatCallbacks.end()) { + memStickFatCallbacks.insert(cbId); DEBUG_LOG(SCEIO, "sceIoDevCtl: Memstick FAT callback %i registered, notifying immediately.", cbId); - __KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId, MemoryStick_FatState()); + __KernelNotifyCallback(cbId, MemoryStick_FatState()); return 0; } else { return -1; @@ -1350,8 +1364,10 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, case 0x02415822: { // MScmUnregisterMSInsertEjectCallback + // TODO: Verify how duplicates work / how many are allowed. u32 cbId = Memory::Read_U32(argAddr); - if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) { + if (memStickFatCallbacks.find(cbId) != memStickFatCallbacks.end()) { + memStickFatCallbacks.erase(cbId); DEBUG_LOG(SCEIO, "sceIoDevCtl: Unregistered memstick FAT callback %i", cbId); return 0; } else { diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 8696cb5229..6038c70725 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -86,6 +86,7 @@ static bool kernelRunning = false; KernelObjectPool kernelObjects; KernelStats kernelStats; +// TODO: Savestate this? u32 registeredExitCbId; void __KernelInit() @@ -261,10 +262,8 @@ int LoadExecForUser_362A956B() u32 sceKernelRegisterExitCallback(u32 cbId) { - DEBUG_LOG(SCEKERNEL, "sceKernelRegisterExitCallback(%i)", cbId); - if (__KernelRegisterCallback(THREAD_CALLBACK_EXIT, cbId) == 0) { - registeredExitCbId = cbId; - } + DEBUG_LOG(SCEKERNEL,"sceKernelRegisterExitCallback(%i)", cbId); + registeredExitCbId = cbId; return 0; } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index b8e6f38fb9..3a19953083 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -498,19 +498,6 @@ public: p.Do(currentCallbackId); p.Do(context); - u32 numCallbacks = THREAD_CALLBACK_NUM_TYPES; - p.Do(numCallbacks); - if (numCallbacks != THREAD_CALLBACK_NUM_TYPES) - { - p.SetError(p.ERROR_FAILURE); - ERROR_LOG(SCEKERNEL, "Unable to load state: different thread callback storage."); - return; - } - - for (size_t i = 0; i < THREAD_CALLBACK_NUM_TYPES; ++i) - { - p.Do(registeredCallbacks[i]); - } p.Do(readyCallbacks); p.Do(pendingMipsCalls); @@ -531,7 +518,6 @@ public: ThreadContext context; - std::set registeredCallbacks[THREAD_CALLBACK_NUM_TYPES]; std::list readyCallbacks; std::list pendingMipsCalls; @@ -2845,8 +2831,7 @@ int sceKernelNotifyCallback(SceUID cbId, int notifyArg) u32 error; Callback *cb = kernelObjects.Get(cbId, error); if (cb) { - // TODO: Should this notify other existing callbacks too? - __KernelNotifyCallback(THREAD_CALLBACK_USER_DEFINED, cbId, notifyArg); + __KernelNotifyCallback(cbId, notifyArg); return 0; } else { ERROR_LOG(SCEKERNEL, "sceKernelCancelCallback(%i) - bad cbId", cbId); @@ -3541,30 +3526,7 @@ bool __KernelInCallback() return (g_inCbCount != 0); } - -u32 __KernelRegisterCallback(RegisteredCallbackType type, SceUID cbId) -{ - Thread *t = __GetCurrentThread(); - if (cbId > 0 && t->registeredCallbacks[type].find(cbId) == t->registeredCallbacks[type].end()) { - t->registeredCallbacks[type].insert(cbId); - return 0; - } else { - return SCE_KERNEL_ERROR_INVAL; - } -} - -u32 __KernelUnregisterCallback(RegisteredCallbackType type, SceUID cbId) -{ - Thread *t = __GetCurrentThread(); - if (t->registeredCallbacks[type].find(cbId) != t->registeredCallbacks[type].end()) { - t->registeredCallbacks[type].erase(cbId); - return 0; - } else { - return 0x80010016; - } -} - -void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notifyArg) +void __KernelNotifyCallback(SceUID cbId, int notifyArg) { u32 error; @@ -3586,26 +3548,6 @@ void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notify } } -// TODO: If cbId == -1, notify the callback ID on all threads that have it. -u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int notifyArg) -{ - u32 error; - for (std::vector::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) { - Thread *t = kernelObjects.Get(*iter, error); - if (!t) - continue; - - for (std::set::iterator citer = t->registeredCallbacks[type].begin(); citer != t->registeredCallbacks[type].end(); citer++) { - if (cbId == -1 || cbId == *citer) { - __KernelNotifyCallback(type, *citer, notifyArg); - } - } - } - - // checkCallbacks on other threads? - return 0; -} - void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc) { waitTypeFuncs[type].beginFunc = beginFunc; diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index ce452d9fd5..e409dc9cab 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -173,27 +173,6 @@ void __KernelWaitCallbacksCurThread(WaitType type, SceUID waitID, u32 waitValue, void __KernelReSchedule(const char *reason = "no reason"); void __KernelReSchedule(bool doCallbacks, const char *reason); -// Registered callback types -enum RegisteredCallbackType { - THREAD_CALLBACK_UMD = 0, - THREAD_CALLBACK_IO = 1, - THREAD_CALLBACK_MEMORYSTICK = 2, - THREAD_CALLBACK_MEMORYSTICK_FAT = 3, - THREAD_CALLBACK_POWER = 4, - THREAD_CALLBACK_EXIT = 5, - THREAD_CALLBACK_USER_DEFINED = 6, - THREAD_CALLBACK_SIZE = 7, - THREAD_CALLBACK_NUM_TYPES = 8, -}; - -// These operate on the current thread -u32 __KernelRegisterCallback(RegisteredCallbackType type, SceUID cbId); -u32 __KernelUnregisterCallback(RegisteredCallbackType type, SceUID cbId); - -// If cbId == -1, all the callbacks of the type on all the threads get notified. -// If not, only this particular callback gets notified. -u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int notifyArg); - SceUID __KernelGetCurThread(); SceUID __KernelGetCurThreadModuleId(); SceUID __KernelSetupRootThread(SceUID moduleId, int args, const char *argp, int prio, int stacksize, int attr); //represents the real PSP elf loader, run before execution @@ -232,7 +211,7 @@ bool __KernelCurHasReadyCallbacks(); class Thread; void __KernelSwitchContext(Thread *target, const char *reason); bool __KernelExecutePendingMipsCalls(Thread *currentThread, bool reschedAfter); -void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notifyArg); +void __KernelNotifyCallback(SceUID cbId, int notifyArg); // Switch to an idle / non-user thread, if not already on one. // Returns whether a switch occurred. diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index c619574b23..7465b7b4ef 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -154,10 +154,8 @@ int scePowerRegisterCallback(int slot, int cbId) { } } if (retval >= 0) { - __KernelRegisterCallback(THREAD_CALLBACK_POWER, cbId); - int arg = PSP_POWER_CB_AC_POWER | PSP_POWER_CB_BATTERY_EXIST | PSP_POWER_CB_BATTERY_FULL; - __KernelNotifyCallbackType(THREAD_CALLBACK_POWER, cbId, arg); + __KernelNotifyCallback(cbId, arg); } return retval; } @@ -175,7 +173,6 @@ int scePowerUnregisterCallback(int slotId) { if (powerCbSlots[slotId] != 0) { int cbId = powerCbSlots[slotId]; DEBUG_LOG(HLE, "0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId); - __KernelUnregisterCallback(THREAD_CALLBACK_POWER, cbId); powerCbSlots[slotId] = 0; } else { return PSP_POWER_ERROR_EMPTY_SLOT; diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 804bfcbb8c..27da50810b 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -114,7 +114,7 @@ void __UmdStatChange(u64 userdata, int cyclesLate) void __KernelUmdActivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE; - __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); + __KernelNotifyCallback(driveCBId, notifyArg); // Don't activate immediately, take time to "spin up." CoreTiming::RemoveAllEvents(umdStatChangeEvent); @@ -124,7 +124,7 @@ void __KernelUmdActivate() void __KernelUmdDeactivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READY; - __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); + __KernelNotifyCallback(driveCBId, notifyArg); CoreTiming::RemoveAllEvents(umdStatChangeEvent); __UmdStatChange(0, 0); @@ -259,14 +259,10 @@ u32 sceUmdRegisterUMDCallBack(u32 cbId) int retVal; // TODO: If the callback is invalid, return PSP_ERROR_UMD_INVALID_PARAM. - if (cbId == 0) + if (!kernelObjects.IsValid(cbId)) { retVal = PSP_ERROR_UMD_INVALID_PARAM; - else { - // Remove the old one, we're replacing. - if (driveCBId != -1) - __KernelUnregisterCallback(THREAD_CALLBACK_UMD, driveCBId); - - retVal = __KernelRegisterCallback(THREAD_CALLBACK_UMD, cbId); + } else { + // There's only ever one. driveCBId = cbId; } @@ -283,7 +279,6 @@ int sceUmdUnRegisterUMDCallBack(int cbId) else { retVal = cbId; driveCBId = -1; - __KernelUnregisterCallback(THREAD_CALLBACK_UMD, cbId); } DEBUG_LOG(SCEIO, "%08x=sceUmdUnRegisterUMDCallBack(id=%08x)", retVal, cbId); From 87bd8d59e2134843773d2572db93f361771a281e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Sep 2013 03:02:48 -0700 Subject: [PATCH 3/7] Clean up umd bad callback id errors, oops. --- Core/HLE/sceKernelThread.cpp | 2 +- Core/HLE/sceUmd.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 3a19953083..4fcd1545e5 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -2969,7 +2969,7 @@ void ActionAfterMipsCall::run(MipsCall &call) { ActionAfterMipsCall *Thread::getRunningCallbackAction() { - if (this->GetUID() == currentThread && g_inCbCount > 0) { + if (this->GetUID() == currentThread && g_inCbCount > 0) { MipsCall *call = mipsCalls.get(this->currentMipscallId); ActionAfterMipsCall *action = 0; if (call) diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 27da50810b..fe4448b809 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -114,7 +114,8 @@ void __UmdStatChange(u64 userdata, int cyclesLate) void __KernelUmdActivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE; - __KernelNotifyCallback(driveCBId, notifyArg); + if (driveCBId != -1) + __KernelNotifyCallback(driveCBId, notifyArg); // Don't activate immediately, take time to "spin up." CoreTiming::RemoveAllEvents(umdStatChangeEvent); @@ -124,7 +125,8 @@ void __KernelUmdActivate() void __KernelUmdDeactivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READY; - __KernelNotifyCallback(driveCBId, notifyArg); + if (driveCBId != -1) + __KernelNotifyCallback(driveCBId, notifyArg); CoreTiming::RemoveAllEvents(umdStatChangeEvent); __UmdStatChange(0, 0); @@ -256,7 +258,7 @@ int sceUmdDeactivate(u32 mode, const char *name) u32 sceUmdRegisterUMDCallBack(u32 cbId) { - int retVal; + int retVal = 0; // TODO: If the callback is invalid, return PSP_ERROR_UMD_INVALID_PARAM. if (!kernelObjects.IsValid(cbId)) { From 4bba27669693f59cce48d99e476dd84de32ff283 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 8 Sep 2013 18:42:40 -0700 Subject: [PATCH 4/7] Run callbacks in creation order, not notify order. --- Core/HLE/sceKernelThread.cpp | 108 +++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 48 deletions(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 4fcd1545e5..a783ae996b 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -498,7 +498,7 @@ public: p.Do(currentCallbackId); p.Do(context); - p.Do(readyCallbacks); + p.Do(callbacks); p.Do(pendingMipsCalls); p.Do(pushedStacks); @@ -518,7 +518,7 @@ public: ThreadContext context; - std::list readyCallbacks; + std::vector callbacks; std::list pendingMipsCalls; @@ -1750,7 +1750,14 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason) u32 error; Thread *t = kernelObjects.Get(threadID, error); if (t) - readyCallbacksCount -= (int)t->readyCallbacks.size(); + { + for (auto it = t->callbacks.begin(), end = t->callbacks.end(); it != end; ++it) + { + Callback *callback = kernelObjects.Get(*it, error); + if (callback && callback->nc.notifyCount != 0) + readyCallbacksCount--; + } + } return kernelObjects.Destroy(threadID); } @@ -2810,6 +2817,10 @@ SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg) cb->nc.notifyCount = 0; cb->nc.notifyArg = 0; + Thread *thread = __GetCurrentThread(); + if (thread) + thread->callbacks.push_back(id); + DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateCallback(name=%s, entry=%08x, callbackArg=%08x)", id, name, entrypoint, signalArg); return id; @@ -2819,9 +2830,19 @@ int sceKernelDeleteCallback(SceUID cbId) { DEBUG_LOG(SCEKERNEL, "sceKernelDeleteCallback(%i)", cbId); - // TODO: Make sure it's gone from all threads first! + u32 error; + Callback *cb = kernelObjects.Get(cbId, error); + if (cb) + { + Thread *thread = kernelObjects.Get(cb->nc.threadId, error); + if (thread) + thread->callbacks.erase(std::find(thread->callbacks.begin(), thread->callbacks.end(), cbId), thread->callbacks.end()); + if (cb->nc.notifyCount != 0) + readyCallbacksCount--; - return kernelObjects.Destroy(cbId); + return kernelObjects.Destroy(cbId); + } + return error; } // Generally very rarely used, but Numblast uses it like candy. @@ -3421,38 +3442,37 @@ void ActionAfterCallback::run(MipsCall &call) { } bool __KernelCurHasReadyCallbacks() { - if (readyCallbacksCount == 0) + if (readyCallbacksCount == 0) { return false; - - Thread *thread = __GetCurrentThread(); - if (thread->readyCallbacks.size()) { - return true; } + Thread *thread = __GetCurrentThread(); + u32 error; + for (auto it = thread->callbacks.begin(), end = thread->callbacks.end(); it != end; ++it) { + Callback *callback = kernelObjects.Get(*it, error); + if (callback && callback->nc.notifyCount != 0) { + return true; + } + } return false; } // Check callbacks on the current thread only. // Returns true if any callbacks were processed on the current thread. -bool __KernelCheckThreadCallbacks(Thread *thread, bool force) -{ - if (!thread || (!thread->isProcessingCallbacks && !force)) +bool __KernelCheckThreadCallbacks(Thread *thread, bool force) { + if (!thread || (!thread->isProcessingCallbacks && !force)) { return false; + } - if (thread->readyCallbacks.size()) { - SceUID readyCallback = thread->readyCallbacks.front(); - thread->readyCallbacks.pop_front(); - readyCallbacksCount--; - - // If the callback was deleted, we're good. Just skip it. - if (kernelObjects.IsValid(readyCallback)) - { - __KernelRunCallbackOnThread(readyCallback, thread, !force); // makes pending - return true; - } - else - { - WARN_LOG(SCEKERNEL, "Ignoring deleted callback %08x", readyCallback); + if (!thread->callbacks.empty()) { + u32 error; + for (auto it = thread->callbacks.begin(), end = thread->callbacks.end(); it != end; ++it) { + Callback *callback = kernelObjects.Get(*it, error); + if (callback && callback->nc.notifyCount != 0) { + __KernelRunCallbackOnThread(callback->GetUID(), thread, !force); + readyCallbacksCount--; + return true; + } } } return false; @@ -3468,23 +3488,20 @@ bool __KernelCheckCallbacks() { ERROR_LOG_REPORT(SCEKERNEL, "readyCallbacksCount became negative: %i", readyCallbacksCount); } - // SceUID currentThread = __KernelGetCurThread(); - // __GetCurrentThread()->isProcessingCallbacks = true; - // do { - bool processed = false; + bool processed = false; - u32 error; - for (std::vector::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) { - Thread *thread = kernelObjects.Get(*iter, error); - if (thread && __KernelCheckThreadCallbacks(thread, false)) { - processed = true; - } + u32 error; + for (std::vector::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) { + Thread *thread = kernelObjects.Get(*iter, error); + if (thread && __KernelCheckThreadCallbacks(thread, false)) { + processed = true; } - // } while (processed && currentThread == __KernelGetCurThread()); + } - if (processed) + if (processed) { return __KernelExecutePendingMipsCalls(__GetCurrentThread(), true); - return processed; + } + return false; } bool __KernelForceCallbacks() @@ -3536,16 +3553,11 @@ void __KernelNotifyCallback(SceUID cbId, int notifyArg) ERROR_LOG(SCEKERNEL, "__KernelNotifyCallback - invalid callback %08x", cbId); return; } - cb->nc.notifyCount++; - cb->nc.notifyArg = notifyArg; - - Thread *t = kernelObjects.Get(cb->nc.threadId, error); - auto iter = std::find(t->readyCallbacks.begin(), t->readyCallbacks.end(), cbId); - if (iter == t->readyCallbacks.end()) - { - t->readyCallbacks.push_back(cbId); + if (cb->nc.notifyCount == 0) { readyCallbacksCount++; } + cb->nc.notifyCount++; + cb->nc.notifyArg = notifyArg; } void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc) From 1040123a97a706205c17bacf009ff947c404a956 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 8 Sep 2013 18:46:01 -0700 Subject: [PATCH 5/7] Delete callbacks when their thread is deleted. --- Core/HLE/sceKernelThread.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index a783ae996b..c6ab762bcc 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -464,6 +464,10 @@ public: ~Thread() { + // Callbacks are automatically deleted when their owning thread is deleted. + for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it) + kernelObjects.Destroy(*it); + if (pushedStacks.size() != 0) { WARN_LOG_REPORT(SCEKERNEL, "Thread ended within an extended stack"); From 4bd391b0984c3d9f5bec501c17b41174f582683f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 8 Sep 2013 21:29:39 -0700 Subject: [PATCH 6/7] Refactor waiting thread cleanup. --- Core/HLE/KernelWaitHelpers.h | 29 ++++++++++++++++++++++++++++- Core/HLE/sceKernelEventFlag.cpp | 7 +------ Core/HLE/sceKernelMbx.cpp | 7 +------ Core/HLE/sceKernelMemory.cpp | 18 ++---------------- Core/HLE/sceKernelMsgPipe.cpp | 13 +------------ Core/HLE/sceKernelMutex.cpp | 21 +++------------------ Core/HLE/sceKernelSemaphore.cpp | 7 +------ 7 files changed, 37 insertions(+), 65 deletions(-) diff --git a/Core/HLE/KernelWaitHelpers.h b/Core/HLE/KernelWaitHelpers.h index d7bf3ddb41..87bf34df63 100644 --- a/Core/HLE/KernelWaitHelpers.h +++ b/Core/HLE/KernelWaitHelpers.h @@ -259,7 +259,17 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI } // Verify that a thread has not been released from waiting, e.g. by sceKernelReleaseWaitThread(). -inline bool VerifyWait(SceUID threadID, WaitType waitType, SceUID uid) { +// For a waiting thread info struct. +template +inline bool VerifyWait(const T &waitInfo, WaitType waitType, SceUID uid) { + u32 error; + SceUID waitID = __KernelGetWaitID(waitInfo.threadID, waitType, error); + return waitID == uid && error == 0; +} + +// Verify that a thread has not been released from waiting, e.g. by sceKernelReleaseWaitThread(). +template <> +inline bool VerifyWait(const SceUID &threadID, WaitType waitType, SceUID uid) { u32 error; SceUID waitID = __KernelGetWaitID(threadID, waitType, error); return waitID == uid && error == 0; @@ -275,4 +285,21 @@ inline bool ResumeFromWait(SceUID threadID, WaitType waitType, SceUID uid, T res return false; } +// Removes threads that are not waiting anymore from a waitingThreads list. +template +inline void CleanupWaitingThreads(WaitType waitType, SceUID uid, std::vector &waitingThreads) { + size_t size = waitingThreads.size(); + for (size_t i = 0; i < size; ++i) { + if (!VerifyWait(waitingThreads[i], waitType, uid)) { + // Decrement size and swap what was there with i. + if (--size != i) { + std::swap(waitingThreads[i], waitingThreads[size]); + } + // Now we haven't checked the new i, so go back and do i again. + --i; + } + } + waitingThreads.resize(size); +} + }; diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index 32072cc8f5..91e25dd44c 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -622,12 +622,7 @@ u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr) if (!Memory::IsValidAddress(statusPtr)) return -1; - for (auto iter = e->waitingThreads.begin(); iter != e->waitingThreads.end(); ++iter) - { - // The thread is no longer waiting for this, clean it up. - if (!HLEKernel::VerifyWait(iter->threadID, WAITTYPE_EVENTFLAG, id)) - e->waitingThreads.erase(iter--); - } + HLEKernel::CleanupWaitingThreads(WAITTYPE_EVENTFLAG, id, e->waitingThreads); e->nef.numWaitThreads = (int) e->waitingThreads.size(); if (Memory::Read_U32(statusPtr) != 0) diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 5716803e5f..8b4c16d9a2 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -583,12 +583,7 @@ int sceKernelReferMbxStatus(SceUID id, u32 infoAddr) for (int i = 0, n = m->nmb.numMessages; i < n; ++i) m->nmb.packetListHead = Memory::Read_U32(m->nmb.packetListHead); - for (auto iter = m->waitingThreads.begin(); iter != m->waitingThreads.end(); ++iter) - { - // The thread is no longer waiting for this, clean it up. - if (!HLEKernel::VerifyWait(iter->threadID, WAITTYPE_MBX, id)) - m->waitingThreads.erase(iter--); - } + HLEKernel::CleanupWaitingThreads(WAITTYPE_MBX, id, m->waitingThreads); // For whatever reason, it won't write if the size (first member) is 0. if (Memory::Read_U32(infoAddr) != 0) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index bcabba4273..2f937931e7 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -325,14 +325,7 @@ void __KernelSortFplThreads(FPL *fpl) { // Remove any that are no longer waiting. SceUID uid = fpl->GetUID(); - for (size_t i = 0; i < fpl->waitingThreads.size(); i++) - { - if (!HLEKernel::VerifyWait(fpl->waitingThreads[i].threadID, WAITTYPE_FPL, uid)) - { - fpl->waitingThreads.erase(fpl->waitingThreads.begin() + i); - --i; - } - } + HLEKernel::CleanupWaitingThreads(WAITTYPE_FPL, uid, fpl->waitingThreads); if ((fpl->nf.attr & PSP_FPL_ATTR_PRIORITY) != 0) std::stable_sort(fpl->waitingThreads.begin(), fpl->waitingThreads.end(), __FplThreadSortPriority); @@ -1212,14 +1205,7 @@ void __KernelSortFplThreads(VPL *vpl) { // Remove any that are no longer waiting. SceUID uid = vpl->GetUID(); - for (size_t i = 0; i < vpl->waitingThreads.size(); i++) - { - if (!HLEKernel::VerifyWait(vpl->waitingThreads[i].threadID, WAITTYPE_VPL, uid)) - { - vpl->waitingThreads.erase(vpl->waitingThreads.begin() + i); - --i; - } - } + HLEKernel::CleanupWaitingThreads(WAITTYPE_VPL, uid, vpl->waitingThreads); if ((vpl->nv.attr & PSP_VPL_ATTR_PRIORITY) != 0) std::stable_sort(vpl->waitingThreads.begin(), vpl->waitingThreads.end(), __VplThreadSortPriority); diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index eec9cc7176..d72a1bc091 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -241,18 +241,7 @@ struct MsgPipe : public KernelObject void SortThreads(std::vector &waitingThreads, bool usePrio) { // Clean up any not waiting at the same time. - size_t size = waitingThreads.size(); - for (size_t i = 0; i < size; ++i) - { - if (!waitingThreads[i].IsStillWaiting(GetUID())) - { - // Decrement size and swap what was there with i. - std::swap(waitingThreads[i], waitingThreads[--size]); - // Now we haven't checked the new i, so go back and do i again. - --i; - } - } - waitingThreads.resize(size); + HLEKernel::CleanupWaitingThreads(WAITTYPE_MSGPIPE, GetUID(), waitingThreads); if (usePrio) std::stable_sort(waitingThreads.begin(), waitingThreads.end(), __KernelMsgPipeThreadSortPriority); diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 7275c793cc..7ab9d5493b 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -517,12 +517,7 @@ int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) DEBUG_LOG(SCEKERNEL, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr); // Remove threads no longer waiting on this first (so the numWaitThreads value is correct.) - for (auto iter = mutex->waitingThreads.begin(); iter != mutex->waitingThreads.end(); ++iter) - { - // The thread is no longer waiting for this, clean it up. - if (!HLEKernel::VerifyWait(*iter, WAITTYPE_MUTEX, uid)) - mutex->waitingThreads.erase(iter--); - } + HLEKernel::CleanupWaitingThreads(WAITTYPE_MUTEX, uid, mutex->waitingThreads); if (Memory::IsValidAddress(numWaitThreadsPtr)) Memory::Write_U32((u32)mutex->waitingThreads.size(), numWaitThreadsPtr); @@ -682,12 +677,7 @@ int sceKernelReferMutexStatus(SceUID id, u32 infoAddr) // Don't write if the size is 0. Anything else is A-OK, though, apparently. if (Memory::Read_U32(infoAddr) != 0) { - for (auto iter = m->waitingThreads.begin(); iter != m->waitingThreads.end(); ++iter) - { - // The thread is no longer waiting for this, clean it up. - if (!HLEKernel::VerifyWait(*iter, WAITTYPE_MUTEX, id)) - m->waitingThreads.erase(iter--); - } + HLEKernel::CleanupWaitingThreads(WAITTYPE_MUTEX, id, m->waitingThreads); m->nm.numWaitThreads = (int) m->waitingThreads.size(); Memory::WriteStruct(infoAddr, &m->nm); @@ -1065,12 +1055,7 @@ int __KernelReferLwMutexStatus(SceUID uid, u32 infoPtr) { auto workarea = m->nm.workarea; - for (auto iter = m->waitingThreads.begin(); iter != m->waitingThreads.end(); ++iter) - { - // The thread is no longer waiting for this, clean it up. - if (!HLEKernel::VerifyWait(*iter, WAITTYPE_LWMUTEX, uid)) - m->waitingThreads.erase(iter--); - } + HLEKernel::CleanupWaitingThreads(WAITTYPE_LWMUTEX, uid, m->waitingThreads); // Refresh and write m->nm.currentCount = workarea->lockLevel; diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 5884aa9cee..152de6a44e 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -266,12 +266,7 @@ int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) if (!Memory::IsValidAddress(infoPtr)) return -1; - for (auto iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) - { - // The thread is no longer waiting for this, clean it up. - if (!HLEKernel::VerifyWait(*iter, WAITTYPE_SEMA, id)) - s->waitingThreads.erase(iter--); - } + HLEKernel::CleanupWaitingThreads(WAITTYPE_SEMA, id, s->waitingThreads); s->ns.numWaitThreads = (int) s->waitingThreads.size(); if (Memory::Read_U32(infoPtr) != 0) From be468af52d497c71ec01e3306cff45e26c339d9c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 8 Sep 2013 21:41:54 -0700 Subject: [PATCH 7/7] Refactor waiting thread removal. --- Core/HLE/KernelWaitHelpers.h | 5 ++++ Core/HLE/sceKernelEventFlag.cpp | 22 ++++++----------- Core/HLE/sceKernelMbx.cpp | 22 ++++++----------- Core/HLE/sceKernelMemory.cpp | 44 +++++++++++---------------------- Core/HLE/sceKernelMsgPipe.cpp | 9 ++----- Core/HLE/sceKernelMutex.cpp | 2 +- Core/HLE/sceUmd.cpp | 11 ++------- 7 files changed, 38 insertions(+), 77 deletions(-) diff --git a/Core/HLE/KernelWaitHelpers.h b/Core/HLE/KernelWaitHelpers.h index 87bf34df63..db7257110f 100644 --- a/Core/HLE/KernelWaitHelpers.h +++ b/Core/HLE/KernelWaitHelpers.h @@ -302,4 +302,9 @@ inline void CleanupWaitingThreads(WaitType waitType, SceUID uid, std::vector waitingThreads.resize(size); } +template +inline void RemoveWaitingThread(std::vector &waitingThreads, const SceUID threadID) { + waitingThreads.erase(std::remove(waitingThreads.begin(), waitingThreads.end(), threadID), waitingThreads.end()); +} + }; diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index 91e25dd44c..b48f7f2acb 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -47,6 +47,11 @@ struct EventFlagTh u32 wait; u32 outAddr; u64 pausedTimeout; + + bool operator ==(const SceUID &otherThreadID) const + { + return threadID == otherThreadID; + } }; class EventFlag : public KernelObject @@ -397,19 +402,6 @@ void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr) CoreTiming::ScheduleEvent(usToCycles(micro), eventFlagWaitTimer, __KernelGetCurThread()); } -void __KernelEventFlagRemoveThread(EventFlag *e, SceUID threadID) -{ - for (size_t i = 0; i < e->waitingThreads.size(); i++) - { - EventFlagTh *t = &e->waitingThreads[i]; - if (t->threadID == threadID) - { - e->waitingThreads.erase(e->waitingThreads.begin() + i); - break; - } - } -} - int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) { if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) @@ -439,7 +431,7 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti { // If this thread was left in waitingThreads after a timeout, remove it. // Otherwise we might write the outBitsPtr in the wrong place. - __KernelEventFlagRemoveThread(e, __KernelGetCurThread()); + HLEKernel::RemoveWaitingThread(e->waitingThreads, __KernelGetCurThread()); u32 timeout = 0xFFFFFFFF; if (Memory::IsValidAddress(timeoutPtr)) @@ -514,7 +506,7 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 { // If this thread was left in waitingThreads after a timeout, remove it. // Otherwise we might write the outBitsPtr in the wrong place. - __KernelEventFlagRemoveThread(e, __KernelGetCurThread()); + HLEKernel::RemoveWaitingThread(e->waitingThreads, __KernelGetCurThread()); u32 timeout = 0xFFFFFFFF; if (Memory::IsValidAddress(timeoutPtr)) diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 8b4c16d9a2..e8e3e57cc8 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -37,6 +37,11 @@ struct MbxWaitingThread SceUID threadID; u32 packetAddr; u64 pausedTimeout; + + bool operator ==(const SceUID &otherThreadID) const + { + return threadID == otherThreadID; + } }; void __KernelMbxTimeout(u64 userdata, int cyclesLate); @@ -274,19 +279,6 @@ void __KernelWaitMbx(Mbx *m, u32 timeoutPtr) CoreTiming::ScheduleEvent(usToCycles(micro), mbxWaitTimer, __KernelGetCurThread()); } -void __KernelMbxRemoveThread(Mbx *m, SceUID threadID) -{ - for (size_t i = 0; i < m->waitingThreads.size(); i++) - { - MbxWaitingThread *t = &m->waitingThreads[i]; - if (t->threadID == threadID) - { - m->waitingThreads.erase(m->waitingThreads.begin() + i); - break; - } - } -} - std::vector::iterator __KernelMbxFindPriority(std::vector &waiting) { _dbg_assert_msg_(SCEKERNEL, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads."); @@ -480,7 +472,7 @@ int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) else { DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbx(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); - __KernelMbxRemoveThread(m, __KernelGetCurThread()); + HLEKernel::RemoveWaitingThread(m->waitingThreads, __KernelGetCurThread()); m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); __KernelWaitMbx(m, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, false, "mbx waited"); @@ -508,7 +500,7 @@ int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) else { DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); - __KernelMbxRemoveThread(m, __KernelGetCurThread()); + HLEKernel::RemoveWaitingThread(m->waitingThreads, __KernelGetCurThread()); m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); __KernelWaitMbx(m, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, true, "mbx waited"); diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 2f937931e7..e08e126598 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -57,6 +57,11 @@ struct FplWaitingThread SceUID threadID; u32 addrPtr; u64 pausedTimeout; + + bool operator ==(const SceUID &otherThreadID) const + { + return threadID == otherThreadID; + } }; struct NativeFPL @@ -141,6 +146,11 @@ struct VplWaitingThread SceUID threadID; u32 addrPtr; u64 pausedTimeout; + + bool operator ==(const SceUID &otherThreadID) const + { + return threadID == otherThreadID; + } }; struct SceKernelVplInfo @@ -292,19 +302,6 @@ void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId) DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Resuming mbx wait from callback"); } -void __KernelFplRemoveThread(FPL *fpl, SceUID threadID) -{ - for (size_t i = 0; i < fpl->waitingThreads.size(); i++) - { - FplWaitingThread *t = &fpl->waitingThreads[i]; - if (t->threadID == threadID) - { - fpl->waitingThreads.erase(fpl->waitingThreads.begin() + i); - break; - } - } -} - bool __FplThreadSortPriority(FplWaitingThread thread1, FplWaitingThread thread2) { return __KernelThreadSortPriority(thread1.threadID, thread2.threadID); @@ -482,7 +479,7 @@ int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) Memory::Write_U32(blockPtr, blockPtrAddr); } else { SceUID threadID = __KernelGetCurThread(); - __KernelFplRemoveThread(fpl, threadID); + HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID); FplWaitingThread waiting = {threadID, blockPtrAddr}; fpl->waitingThreads.push_back(waiting); @@ -513,7 +510,7 @@ int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) Memory::Write_U32(blockPtr, blockPtrAddr); } else { SceUID threadID = __KernelGetCurThread(); - __KernelFplRemoveThread(fpl, threadID); + HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID); FplWaitingThread waiting = {threadID, blockPtrAddr}; fpl->waitingThreads.push_back(waiting); @@ -1172,19 +1169,6 @@ void __KernelVplEndCallback(SceUID threadID, SceUID prevCallbackId) DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Resuming mbx wait from callback"); } -void __KernelVplRemoveThread(VPL *vpl, SceUID threadID) -{ - for (size_t i = 0; i < vpl->waitingThreads.size(); i++) - { - VplWaitingThread *t = &vpl->waitingThreads[i]; - if (t->threadID == threadID) - { - vpl->waitingThreads.erase(vpl->waitingThreads.begin() + i); - break; - } - } -} - bool __VplThreadSortPriority(VplWaitingThread thread1, VplWaitingThread thread2) { return __KernelThreadSortPriority(thread1.threadID, thread2.threadID); @@ -1377,7 +1361,7 @@ int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) if (vpl) { SceUID threadID = __KernelGetCurThread(); - __KernelVplRemoveThread(vpl, threadID); + HLEKernel::RemoveWaitingThread(vpl->waitingThreads, threadID); VplWaitingThread waiting = {threadID, addrPtr}; vpl->waitingThreads.push_back(waiting); } @@ -1402,7 +1386,7 @@ int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) if (vpl) { SceUID threadID = __KernelGetCurThread(); - __KernelVplRemoveThread(vpl, threadID); + HLEKernel::RemoveWaitingThread(vpl->waitingThreads, threadID); VplWaitingThread waiting = {threadID, addrPtr}; vpl->waitingThreads.push_back(waiting); } diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index d72a1bc091..8eff9b277f 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -259,19 +259,14 @@ struct MsgPipe : public KernelObject SortThreads(sendWaitingThreads, usePrio); } - void RemoveWaitingThread(std::vector &waitingThreads, SceUID threadID) - { - waitingThreads.erase(std::remove(waitingThreads.begin(), waitingThreads.end(), threadID), waitingThreads.end()); - } - void RemoveReceiveWaitingThread(SceUID threadID) { - RemoveWaitingThread(receiveWaitingThreads, threadID); + HLEKernel::RemoveWaitingThread(receiveWaitingThreads, threadID); } void RemoveSendWaitingThread(SceUID threadID) { - RemoveWaitingThread(sendWaitingThreads, threadID); + HLEKernel::RemoveWaitingThread(sendWaitingThreads, threadID); } virtual void DoState(PointerWrap &p) diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 7ab9d5493b..b90efe2c56 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -461,7 +461,7 @@ void __KernelMutexThreadEnd(SceUID threadID) { Mutex *mutex = kernelObjects.Get(waitingMutexID, error); if (mutex) - mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end()); + HLEKernel::RemoveWaitingThread(mutex->waitingThreads, threadID); } // Unlock all mutexes the thread had locked. diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index fe4448b809..2dd8bbe634 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -150,11 +150,7 @@ void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId) else umdPausedWaits[pauseKey] = 0; - for (auto it = umdWaitingThreads.begin(); it < umdWaitingThreads.end(); ++it) - { - if (*it == threadID) - umdWaitingThreads.erase(it--); - } + HLEKernel::RemoveWaitingThread(umdWaitingThreads, threadID); DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB: Suspending lock wait for callback"); } @@ -305,10 +301,7 @@ void __UmdStatTimeout(u64 userdata, int cyclesLate) if (waitID == 1) __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT); - for (size_t i = 0; i < umdWaitingThreads.size(); ++i) { - if (umdWaitingThreads[i] == threadID) - umdWaitingThreads.erase(umdWaitingThreads.begin() + i--); - } + HLEKernel::RemoveWaitingThread(umdWaitingThreads, threadID); } void __UmdWaitStat(u32 timeout)