From 593e48b865dcbd77a0fab4d854e152a4e3276dd2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Jan 2020 13:09:58 -0800 Subject: [PATCH] Io: Update async priority more correctly. When an operation finishes, whether it uses the priority from the first operation or the current thread's priority depends on sdk version, it seems. This also makes it resolve the default priority on open, so that changing the default afterward doesn't affect already open descriptors. --- Core/HLE/HLEHelperThread.cpp | 9 ++++++++ Core/HLE/HLEHelperThread.h | 6 +++++ Core/HLE/sceIo.cpp | 43 ++++++++++++++++++++++-------------- Core/HLE/sceKernelThread.h | 2 +- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/Core/HLE/HLEHelperThread.cpp b/Core/HLE/HLEHelperThread.cpp index 7f932c4a9c..36f9166813 100644 --- a/Core/HLE/HLEHelperThread.cpp +++ b/Core/HLE/HLEHelperThread.cpp @@ -16,9 +16,11 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/ChunkFile.h" +#include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/HLE/HLE.h" #include "Core/HLE/HLEHelperThread.h" +#include "Core/HLE/KernelWaitHelpers.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelMemory.h" #include "Core/MIPS/MIPSCodeUtils.h" @@ -91,6 +93,13 @@ void HLEHelperThread::ChangePriority(u32 prio) { KernelChangeThreadPriority(id_, prio); } +void HLEHelperThread::Resume(WaitType waitType, SceUID uid, int result) { + bool res = HLEKernel::ResumeFromWait(id_, waitType, uid, result); + if (!res) { + ERROR_LOG(HLE, "Failed to wake helper thread from wait"); + } +} + void HLEHelperThread::Forget() { id_ = 0; entry_ = 0; diff --git a/Core/HLE/HLEHelperThread.h b/Core/HLE/HLEHelperThread.h index 1868d309b0..39df4c7402 100644 --- a/Core/HLE/HLEHelperThread.h +++ b/Core/HLE/HLEHelperThread.h @@ -19,6 +19,7 @@ #include "Core/HLE/sceKernel.h" class PointerWrap; +enum WaitType : int; class HLEHelperThread { public: @@ -33,10 +34,15 @@ public: void Terminate(); bool Stopped(); void ChangePriority(u32 prio); + void Resume(WaitType waitType, SceUID uid, int result); // For savestates. void Forget(); + u32 Entry() { + return entry_; + } + private: void AllocEntry(u32 size); void Create(const char *threadName, u32 prio, int stacksize); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index f08d1d317b..1982eeab85 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -295,8 +295,11 @@ public: u64 __IoCompleteAsyncIO(FileNode *f); -static void IoAsyncCleanupThread(int fd, bool force = false) { - if (asyncThreads[fd] && (asyncThreads[fd]->Stopped() || force)) { +static void IoAsyncCleanupThread(int fd) { + if (asyncThreads[fd]) { + if (!asyncThreads[fd]->Stopped()) { + asyncThreads[fd]->Terminate(); + } delete asyncThreads[fd]; asyncThreads[fd] = nullptr; } @@ -438,8 +441,6 @@ static void __IoAsyncNotify(u64 userdata, int cyclesLate) { if (f->closePending) { __IoFreeFd(fd, error); } - - IoAsyncCleanupThread(fd); } } @@ -488,8 +489,6 @@ static void __IoSyncNotify(u64 userdata, int cyclesLate) { HLEKernel::ResumeFromWait(threadID, WAITTYPE_IO, fd, result); f->waitingSyncThreads.erase(std::remove(f->waitingSyncThreads.begin(), f->waitingSyncThreads.end(), threadID), f->waitingSyncThreads.end()); - - IoAsyncCleanupThread(fd); } static void __IoAsyncBeginCallback(SceUID threadID, SceUID prevCallbackId) { @@ -778,12 +777,20 @@ u32 __IoGetFileHandleFromId(u32 id, u32 &outError) } static void IoStartAsyncThread(int id, FileNode *f) { - IoAsyncCleanupThread(id, true); - int priority = asyncParams[id].priority == -1 ? asyncDefaultPriority : asyncParams[id].priority; - if (priority == -1) - priority = KernelCurThreadPriority(); - asyncThreads[id] = new HLEHelperThread("SceIoAsync", "IoFileMgrForUser", "__IoAsyncFinish", priority, 0x200); - asyncThreads[id]->Start(id, 0); + if (asyncThreads[id] && !asyncThreads[id]->Stopped()) { + // Wake the thread up. + if (asyncParams[id].priority == -1 && sceKernelGetCompiledSdkVersion() >= 0x04020000) { + asyncThreads[id]->ChangePriority(KernelCurThreadPriority()); + } + asyncThreads[id]->Resume(WAITTYPE_ASYNCIO, id, 0); + } else { + IoAsyncCleanupThread(id); + int priority = asyncParams[id].priority; + if (priority == -1) + priority = KernelCurThreadPriority(); + asyncThreads[id] = new HLEHelperThread("SceIoAsync", "IoFileMgrForUser", "__IoAsyncFinish", priority, 0x200); + asyncThreads[id]->Start(id, 0); + } f->pendingAsyncResult = true; } @@ -1491,7 +1498,7 @@ static u32 sceIoOpen(const char *filename, int flags, int mode) { return id; } else { DEBUG_LOG(SCEIO, "%i=sceIoOpen(%s, %08x, %08x)", id, filename, flags, mode); - asyncParams[id].priority = -1; + asyncParams[id].priority = asyncDefaultPriority; // Timing is not accurate, aiming low for now. return hleDelayResult(id, "file opened", 100); } @@ -1984,6 +1991,9 @@ static int sceIoChangeAsyncPriority(int id, int priority) { } if (asyncThreads[id] && !asyncThreads[id]->Stopped()) { + if (priority == -1) { + priority = KernelCurThreadPriority(); + } asyncThreads[id]->ChangePriority(priority); } @@ -2101,7 +2111,6 @@ static u32 sceIoGetAsyncStat(int id, u32 poll, u32 address) { DEBUG_LOG(SCEIO, "%lli = sceIoGetAsyncStat(%i, %i, %08x)", f->asyncResult, id, poll, address); Memory::Write_U64((u64) f->asyncResult, address); f->hasAsyncResult = false; - IoAsyncCleanupThread(id); if (f->closePending) { __IoFreeFd(id, error); @@ -2139,7 +2148,6 @@ static int sceIoWaitAsync(int id, u32 address) { } Memory::Write_U64((u64) f->asyncResult, address); f->hasAsyncResult = false; - IoAsyncCleanupThread(id); if (f->closePending) { __IoFreeFd(id, error); @@ -2173,7 +2181,6 @@ static int sceIoWaitAsyncCB(int id, u32 address) { } else if (f->hasAsyncResult) { Memory::Write_U64((u64) f->asyncResult, address); f->hasAsyncResult = false; - IoAsyncCleanupThread(id); if (f->closePending) { __IoFreeFd(id, error); @@ -2197,7 +2204,6 @@ static u32 sceIoPollAsync(int id, u32 address) { } else if (f->hasAsyncResult) { Memory::Write_U64((u64) f->asyncResult, address); f->hasAsyncResult = false; - IoAsyncCleanupThread(id); if (f->closePending) { __IoFreeFd(id, error); @@ -2671,6 +2677,8 @@ static int IoAsyncFinish(int id) { if (f) { // Reset this so the Io funcs don't reject the request. f->pendingAsyncResult = false; + // Reset the PC back so we will run again on resume. + currentMIPS->pc = asyncThreads[id]->Entry(); auto ¶ms = asyncParams[id]; @@ -2732,6 +2740,7 @@ static int IoAsyncFinish(int id) { __IoSchedAsync(f, id, us); __KernelWaitCurThread(WAITTYPE_ASYNCIO, id, 0, 0, false, "async io"); + hleSkipDeadbeef(); params.op = IoAsyncOp::NONE; return 0; diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index c89a373ee9..8b95396b97 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -80,7 +80,7 @@ struct SceKernelSysClock { // TODO: Map these to PSP wait types. Most of these are wrong. // remember to update the waitTypeNames array in sceKernelThread.cpp when changing these -enum WaitType +enum WaitType : int { WAITTYPE_NONE = 0, WAITTYPE_SLEEP = 1,