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,