From 4bba27669693f59cce48d99e476dd84de32ff283 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 8 Sep 2013 18:42:40 -0700 Subject: [PATCH] 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)