Skip to content

Commit

Permalink
Merge pull request #6675 from unknownbrackets/threadman
Browse files Browse the repository at this point in the history
Correct sceKernelThreadmanIdList behavior
  • Loading branch information
hrydgard committed Aug 19, 2014
2 parents e7a1761 + 909ac62 commit 72d5a55
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 27 deletions.
1 change: 1 addition & 0 deletions Core/HLE/sceKernel.cpp
Expand Up @@ -620,6 +620,7 @@ KernelObject *KernelObjectPool::CreateByIDType(int type)
case SCE_KERNEL_TMID_VTimer:
return __KernelVTimerObject();
case SCE_KERNEL_TMID_Tlspl:
case SCE_KERNEL_TMID_Tlspl_v0:
return __KernelTlsplObject();
case PPSSPP_KERNEL_TMID_File:
return __KernelFileNodeObject();
Expand Down
27 changes: 21 additions & 6 deletions Core/HLE/sceKernel.h
Expand Up @@ -327,12 +327,13 @@ enum TMIDPurpose
SCE_KERNEL_TMID_VTimer = 11,
SCE_KERNEL_TMID_Mutex = 12,
SCE_KERNEL_TMID_LwMutex = 13,
SCE_KERNEL_TMID_Tlspl = 14,
SCE_KERNEL_TMID_SleepThread = 64,
SCE_KERNEL_TMID_DelayThread = 65,
SCE_KERNEL_TMID_SuspendThread = 66,
SCE_KERNEL_TMID_DormantThread = 67,
// No idea what the correct value is here or how to find out.
SCE_KERNEL_TMID_Tlspl = 0x1001,
// This is kept for old savestates. Not the real value.
SCE_KERNEL_TMID_Tlspl_v0 = 0x1001,

// Not official, but need ids for save states.
PPSSPP_KERNEL_TMID_Module = 0x100001,
Expand Down Expand Up @@ -488,11 +489,9 @@ class KernelObjectPool {
}

template <class T, typename ArgT>
void Iterate(bool func(T *, ArgT), ArgT arg)
{
void Iterate(bool func(T *, ArgT), ArgT arg) {
int type = T::GetStaticIDType();
for (int i = 0; i < maxCount; i++)
{
for (int i = 0; i < maxCount; i++) {
if (!occupied[i])
continue;
T *t = static_cast<T *>(pool[i]);
Expand All @@ -503,6 +502,22 @@ class KernelObjectPool {
}
}

int ListIDType(int type, SceUID *uids, int count) const {
int total = 0;
for (int i = 0; i < maxCount; i++) {
if (!occupied[i]) {
continue;
}
if (pool[i]->GetIDType() == type) {
if (total < count) {
*uids++ = pool[i]->GetUID();
}
++total;
}
}
return total;
}

bool GetIDType(SceUID handle, int *type) const
{
if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset])
Expand Down
105 changes: 84 additions & 21 deletions Core/HLE/sceKernelThread.cpp
Expand Up @@ -507,9 +507,9 @@ class Thread : public KernelObject
void setReturnValue(u32 retval);
void setReturnValue(u64 retval);
void resumeFromWait();
bool isWaitingFor(WaitType type, int id);
int getWaitID(WaitType type);
ThreadWaitInfo getWaitInfo();
bool isWaitingFor(WaitType type, int id) const;
int getWaitID(WaitType type) const;
ThreadWaitInfo getWaitInfo() const;

// Utils
inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
Expand Down Expand Up @@ -1584,32 +1584,95 @@ int sceKernelGetThreadExitStatus(SceUID threadID)
u32 sceKernelGetThreadmanIdType(u32 uid) {
int type;
if (kernelObjects.GetIDType(uid, &type)) {
DEBUG_LOG(SCEKERNEL, "%i=sceKernelGetThreadmanIdType(%i)", type, uid);
return type;
if (type < 0x1000) {
DEBUG_LOG(SCEKERNEL, "%i=sceKernelGetThreadmanIdType(%i)", type, uid);
return type;
} else {
// This means a partition memory block or module, etc.
ERROR_LOG(SCEKERNEL, "sceKernelGetThreadmanIdType(%i): invalid object type %i", uid, type);
return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
}
} else {
ERROR_LOG(SCEKERNEL, "sceKernelGetThreadmanIdType(%i) - FAILED", uid);
return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
}
}

u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr)
{
DEBUG_LOG(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x)",
type, readBufPtr, readBufSize, idCountPtr);
if (!Memory::IsValidAddress(readBufPtr))
return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
bool __ThreadmanIdListIsSleeping(const Thread *t) {
return t->isWaitingFor(WAITTYPE_SLEEP, 0);
}

bool __ThreadmanIdListIsDelayed(const Thread *t) {
return t->isWaitingFor(WAITTYPE_DELAY, t->GetUID());
}

if (type != SCE_KERNEL_TMID_Thread) {
ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList only implemented for threads");
bool __ThreadmanIdListIsSuspended(const Thread *t) {
return t->isSuspended();
}

bool __ThreadmanIdListIsDormant(const Thread *t) {
return t->isStopped();
}

u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr) {
if (readBufSize >= 0x8000000) {
// Not exact, it's probably if the sum ends up negative or something.
ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid size", type, readBufPtr, readBufSize, idCountPtr);
return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
}
if (!Memory::IsValidAddress(readBufPtr) && readBufSize > 0) {
// Crashes on a PSP.
ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid pointer", type, readBufPtr, readBufSize, idCountPtr);
return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
}

for (size_t i = 0; i < std::min((size_t)readBufSize, threadqueue.size()); i++)
{
Memory::Write_U32(threadqueue[i], readBufPtr + (u32)i * 4);
u32 total = 0;
auto uids = PSPPointer<SceUID>::Create(readBufPtr);
u32 error;
if (type > 0 && type <= SCE_KERNEL_TMID_Tlspl) {
DEBUG_LOG(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x)", type, readBufPtr, readBufSize, idCountPtr);
total = kernelObjects.ListIDType(type, uids, readBufSize);
} else if (type >= SCE_KERNEL_TMID_SleepThread && type <= SCE_KERNEL_TMID_DormantThread) {
bool (*checkFunc)(const Thread *t) = NULL;
switch (type) {
case SCE_KERNEL_TMID_SleepThread:
checkFunc = &__ThreadmanIdListIsSleeping;
break;

case SCE_KERNEL_TMID_DelayThread:
checkFunc = &__ThreadmanIdListIsDelayed;
break;

case SCE_KERNEL_TMID_SuspendThread:
checkFunc = &__ThreadmanIdListIsSuspended;
break;

case SCE_KERNEL_TMID_DormantThread:
checkFunc = &__ThreadmanIdListIsDormant;
break;

default:
_dbg_assert_msg_(SCEKERNEL, false, "Unexpected type %d", type);
}

for (size_t i = 0; i < threadqueue.size(); i++) {
const Thread *t = kernelObjects.Get<Thread>(threadqueue[i], error);
if (checkFunc(t)) {
if (total < readBufSize) {
*uids++ = threadqueue[i];
}
++total;
}
}
} else {
ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid type", type, readBufPtr, readBufSize, idCountPtr);
return SCE_KERNEL_ERROR_ILLEGAL_TYPE;
}
Memory::Write_U32((u32)threadqueue.size(), idCountPtr);
return 0;

if (Memory::IsValidAddress(idCountPtr)) {
Memory::Write_U32(total, idCountPtr);
}
return total > readBufSize ? readBufSize : total;
}

// Saves the current CPU context
Expand Down Expand Up @@ -3132,21 +3195,21 @@ void Thread::resumeFromWait()
isProcessingCallbacks = false;
}

bool Thread::isWaitingFor(WaitType type, int id)
bool Thread::isWaitingFor(WaitType type, int id) const
{
if (nt.status & THREADSTATUS_WAIT)
return nt.waitType == type && nt.waitID == id;
return false;
}

int Thread::getWaitID(WaitType type)
int Thread::getWaitID(WaitType type) const
{
if (nt.waitType == type)
return nt.waitID;
return 0;
}

ThreadWaitInfo Thread::getWaitInfo()
ThreadWaitInfo Thread::getWaitInfo() const
{
return waitInfo;
}
Expand Down

0 comments on commit 72d5a55

Please sign in to comment.