diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index ab65d0238..c79c219c6 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; }; @@ -1489,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) @@ -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 };