diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 3b54699ebe..5685edb474 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -99,7 +99,7 @@ enum ThreadEventType { THREADEVENT_SUPPORTED = THREADEVENT_CREATE | THREADEVENT_START | THREADEVENT_EXIT | THREADEVENT_DELETE, }; -void __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type); +bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type); enum { PSP_THREAD_ATTR_KERNEL = 0x00001000, @@ -639,6 +639,7 @@ std::vector threadEndListeners; typedef std::vector ThreadEventHandlerList; static std::map threadEventHandlers; +static std::vector pendingDeleteThreads; // Lists all thread ids that aren't deleted/etc. std::vector threadqueue; @@ -952,7 +953,7 @@ void __KernelThreadingInit() void __KernelThreadingDoState(PointerWrap &p) { - auto s = p.Section("sceKernelThread", 1, 2); + auto s = p.Section("sceKernelThread", 1, 3); if (!s) return; @@ -990,6 +991,8 @@ void __KernelThreadingDoState(PointerWrap &p) if (s >= 2) p.Do(threadEventHandlers); + if (s >= 3) + p.Do(pendingDeleteThreads); } void __KernelThreadingDoStateLate(PointerWrap &p) @@ -1159,6 +1162,7 @@ void __KernelThreadingShutdown() intReturnHackAddr = 0; pausedDelays.clear(); threadEventHandlers.clear(); + pendingDeleteThreads.clear(); } const char *__KernelGetThreadName(SceUID threadID) @@ -1646,12 +1650,17 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason) t->Cleanup(); } - // TODO: Thread should not be deleted yet... // Before triggering, set v0. It'll be restored if one is called. RETURN(error); - __KernelThreadTriggerEvent((t->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0, threadID, THREADEVENT_DELETE); + t->nt.status = THREADSTATUS_DEAD; - return kernelObjects.Destroy(threadID); + if (__KernelThreadTriggerEvent((t->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0, threadID, THREADEVENT_DELETE)) { + // Don't delete it yet. We'll delete later. + pendingDeleteThreads.push_back(threadID); + return 0; + } else { + return kernelObjects.Destroy(threadID); + } } static void __ReportThreadQueueEmpty() { @@ -3235,12 +3244,17 @@ void __KernelReturnFromMipsCall() } // yeah! back in the real world, let's keep going. Should we process more callbacks? - if (!__KernelExecutePendingMipsCalls(cur, call->reschedAfter)) - { + if (!__KernelExecutePendingMipsCalls(cur, call->reschedAfter)) { // Sometimes, we want to stay on the thread. int threadReady = cur->nt.status & (THREADSTATUS_READY | THREADSTATUS_RUNNING); if (call->reschedAfter || threadReady == 0) __KernelReSchedule("return from callback"); + + // Now seems like a good time to clear out any pending deletes. + for (SceUID delThread : pendingDeleteThreads) { + kernelObjects.Destroy(delThread); + } + pendingDeleteThreads.clear(); } delete call; @@ -3583,13 +3597,14 @@ KernelObject *__KernelThreadEventHandlerObject() { return new ThreadEventHandler; } -void __KernelThreadTriggerEvent(const ThreadEventHandlerList &handlers, SceUID threadID, ThreadEventType type) { +bool __KernelThreadTriggerEvent(const ThreadEventHandlerList &handlers, SceUID threadID, ThreadEventType type) { Thread *thread = __GetCurrentThread(); if (!thread || thread->isStopped()) { SceUID nextThreadID = threadReadyQueue.peek_first(); thread = kernelObjects.GetFast(nextThreadID); } + bool hadHandlers = false; for (auto it = handlers.begin(), end = handlers.end(); it != end; ++it) { u32 error; const auto teh = kernelObjects.Get(*it, error); @@ -3599,25 +3614,33 @@ void __KernelThreadTriggerEvent(const ThreadEventHandlerList &handlers, SceUID t const u32 args[] = {(u32)type, (u32)threadID, teh->nteh.commonArg}; __KernelCallAddress(thread, teh->nteh.handlerPtr, nullptr, args, ARRAY_SIZE(args), true, 0); + hadHandlers = true; } + + return hadHandlers; } -void __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type) { +bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type) { + bool hadExactHandlers = false; auto exactHandlers = threadEventHandlers.find(threadID); if (exactHandlers != threadEventHandlers.end()) { - __KernelThreadTriggerEvent(exactHandlers->second, threadID, type); + hadExactHandlers = __KernelThreadTriggerEvent(exactHandlers->second, threadID, type); } + + bool hadKindHandlers = false; if (isKernel) { auto kernelHandlers = threadEventHandlers.find(SCE_TE_THREADID_ALL_USER); if (kernelHandlers != threadEventHandlers.end()) { - __KernelThreadTriggerEvent(kernelHandlers->second, threadID, type); + hadKindHandlers = __KernelThreadTriggerEvent(kernelHandlers->second, threadID, type); } } else { auto userHandlers = threadEventHandlers.find(SCE_TE_THREADID_ALL_USER); if (userHandlers != threadEventHandlers.end()) { - __KernelThreadTriggerEvent(userHandlers->second, threadID, type); + hadKindHandlers = __KernelThreadTriggerEvent(userHandlers->second, threadID, type); } } + + return hadKindHandlers || hadExactHandlers; } SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u32 mask, u32 handlerPtr, u32 commonArg) {