From 4a4f07df8e4c031ad62b321b171a552791ad6b9e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 31 Jul 2013 00:18:04 -0700 Subject: [PATCH 1/2] Add waiting/resuming to TLS funcs. Nice and simple, no callbacks or timeouts. --- Core/HLE/sceKernelMemory.cpp | 30 ++++++++++++++++++++----- Core/HLE/sceKernelThread.cpp | 43 ++++++++++++++++++------------------ Core/HLE/sceKernelThread.h | 1 + 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index ab65d0238..90d75c88a 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -1343,6 +1343,7 @@ struct TLS : public KernelObject { p.Do(ntls); p.Do(address); + p.Do(waitingThreads); p.Do(next); p.Do(usage); p.DoMarker("TLS"); @@ -1350,7 +1351,7 @@ struct TLS : public KernelObject NativeTls ntls; u32 address; - // TODO: Waiting threads. + std::vector waitingThreads; int next; std::vector usage; }; @@ -1501,8 +1502,8 @@ int sceKernelAllocateTls(SceUID uid) if (allocBlock == -1) { - // TODO: Wait here, wake when one is free. - ERROR_LOG_REPORT(HLE, "sceKernelAllocateTls: should wait"); + tls->waitingThreads.push_back(threadID); + __KernelWaitCurThread(WAITTYPE_TLS, uid, 1, 0, false, "allocate tls"); return -1; } @@ -1522,7 +1523,7 @@ int sceKernelFreeTls(SceUID uid) { SceUID threadID = __KernelGetCurThread(); - // If the thread already has one, return it. + // Find the current thread's block. int freeBlock = -1; for (size_t i = 0; i < tls->ntls.totalBlocks; ++i) { @@ -1535,7 +1536,26 @@ int sceKernelFreeTls(SceUID uid) if (freeBlock != -1) { - // TODO: Free anyone waiting for a free block. + u32 error2; + while (!tls->waitingThreads.empty()) + { + // TODO: What order do they wake in? + SceUID waitingThreadID = tls->waitingThreads[0]; + tls->waitingThreads.erase(tls->waitingThreads.begin()); + + // This thread must've been woken up. + if (__KernelGetWaitID(waitingThreadID, WAITTYPE_TLS, error2) != uid) + continue; + + // Otherwise, if there was a thread waiting, we were full, so this newly freed one is theirs. + // TODO: Is the block wiped or anything? + tls->usage[freeBlock] = waitingThreadID; + __KernelResumeThreadFromWait(waitingThreadID, freeBlock); + // No need to continue or free it, we're done. + return 0; + } + + // No one was waiting, so now we can really free it. tls->usage[freeBlock] = 0; ++tls->ntls.freeBlocks; return 0; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 08109bc0d..6e2147cb4 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -46,27 +46,28 @@ typedef struct } WaitTypeNames; const WaitTypeNames waitTypeNames[] = { - { WAITTYPE_NONE, "None" }, - { WAITTYPE_SLEEP, "Sleep" }, - { WAITTYPE_DELAY, "Delay" }, - { WAITTYPE_SEMA, "Semaphore" }, - { WAITTYPE_EVENTFLAG, "Event flag", }, - { WAITTYPE_MBX, "MBX" }, - { WAITTYPE_VPL, "VPL" }, - { WAITTYPE_FPL, "FPL" }, - { WAITTYPE_MSGPIPE, "Message pipe" }, - { WAITTYPE_THREADEND, "Thread end" }, - { WAITTYPE_AUDIOCHANNEL, "Audio channel" }, - { WAITTYPE_UMD, "UMD" }, - { WAITTYPE_VBLANK, "VBlank" }, - { WAITTYPE_MUTEX, "Mutex" }, - { WAITTYPE_LWMUTEX, "LwMutex" }, - { WAITTYPE_CTRL, "Control" }, - { WAITTYPE_IO, "IO" }, - { WAITTYPE_GEDRAWSYNC, "GeDrawSync" }, - { WAITTYPE_GELISTSYNC, "GeListSync" }, - { WAITTYPE_MODULE, "Module" }, - { WAITTYPE_HLEDELAY, "HleDelay" } + { WAITTYPE_NONE, "None" }, + { WAITTYPE_SLEEP, "Sleep" }, + { WAITTYPE_DELAY, "Delay" }, + { WAITTYPE_SEMA, "Semaphore" }, + { WAITTYPE_EVENTFLAG, "Event flag", }, + { WAITTYPE_MBX, "MBX" }, + { WAITTYPE_VPL, "VPL" }, + { WAITTYPE_FPL, "FPL" }, + { WAITTYPE_MSGPIPE, "Message pipe" }, + { WAITTYPE_THREADEND, "Thread end" }, + { WAITTYPE_AUDIOCHANNEL, "Audio channel" }, + { WAITTYPE_UMD, "UMD" }, + { WAITTYPE_VBLANK, "VBlank" }, + { WAITTYPE_MUTEX, "Mutex" }, + { WAITTYPE_LWMUTEX, "LwMutex" }, + { WAITTYPE_CTRL, "Control" }, + { WAITTYPE_IO, "IO" }, + { WAITTYPE_GEDRAWSYNC, "GeDrawSync" }, + { WAITTYPE_GELISTSYNC, "GeListSync" }, + { WAITTYPE_MODULE, "Module" }, + { WAITTYPE_HLEDELAY, "HleDelay" }, + { WAITTYPE_TLS, "TLS" }, }; const char *getWaitTypeName(WaitType type) diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index e0e8e8d02..964812df1 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -92,6 +92,7 @@ enum WaitType WAITTYPE_GELISTSYNC = 18, WAITTYPE_MODULE = 19, WAITTYPE_HLEDELAY = 20, + WAITTYPE_TLS = 21, NUM_WAITTYPES }; From c2c9179406a5dd05f56c8d543e4d8be9af600cd3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 31 Jul 2013 08:15:07 -0700 Subject: [PATCH 2/2] Fix TLS allocation (been there a while...) This worked for the most common case, but was a typo. --- Core/HLE/sceKernelMemory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 90d75c88a..c79c219c6 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -1490,7 +1490,7 @@ int sceKernelAllocateTls(SceUID uid) // The PSP doesn't give the same block out twice in a row, even if freed. if (tls->usage[tls->next] == 0) allocBlock = tls->next; - tls->next = (tls->next + 1) % tls->ntls.blockSize; + tls->next = (tls->next + 1) % tls->ntls.totalBlocks; } if (allocBlock != -1)