Expose PSPThread in the same manner

This commit is contained in:
Henrik Rydgård 2025-03-31 10:24:03 +02:00
parent 644f5e4e6c
commit 2bfe327dbd
13 changed files with 360 additions and 345 deletions

View file

@ -2170,6 +2170,7 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/HLETables.cpp Core/HLE/HLETables.cpp
Core/HLE/HLETables.h Core/HLE/HLETables.h
Core/HLE/KernelWaitHelpers.h Core/HLE/KernelWaitHelpers.h
Core/HLE/PSPThreadContext.h
Core/HLE/KUBridge.h Core/HLE/KUBridge.h
Core/HLE/KUBridge.cpp Core/HLE/KUBridge.cpp
Core/HLE/Plugins.h Core/HLE/Plugins.h

View file

@ -1,21 +1,18 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <cstddef>
#include <string> #include <string>
#include <vector> #include <vector>
typedef std::pair<uint32_t, uint32_t> ExpressionPair; typedef std::pair<uint32_t, uint32_t> ExpressionPair;
typedef std::vector<ExpressionPair> PostfixExpression; typedef std::vector<ExpressionPair> PostfixExpression;
enum ExpressionType enum ExpressionType {
{
EXPR_TYPE_UINT = 0, EXPR_TYPE_UINT = 0,
EXPR_TYPE_FLOAT = 2, EXPR_TYPE_FLOAT = 2,
}; };
class IExpressionFunctions class IExpressionFunctions {
{
public: public:
virtual ~IExpressionFunctions() {} virtual ~IExpressionFunctions() {}
virtual bool parseReference(char* str, uint32_t& referenceIndex) = 0; virtual bool parseReference(char* str, uint32_t& referenceIndex) = 0;

View file

@ -1195,6 +1195,7 @@
<ClInclude Include="HLE\KUBridge.h" /> <ClInclude Include="HLE\KUBridge.h" />
<ClInclude Include="HLE\NetInetConstants.h" /> <ClInclude Include="HLE\NetInetConstants.h" />
<ClInclude Include="HLE\Plugins.h" /> <ClInclude Include="HLE\Plugins.h" />
<ClInclude Include="HLE\PSPThreadContext.h" />
<ClInclude Include="HLE\sceAac.h" /> <ClInclude Include="HLE\sceAac.h" />
<ClInclude Include="HLE\sceKernelHeap.h" /> <ClInclude Include="HLE\sceKernelHeap.h" />
<ClInclude Include="HLE\sceNetApctl.h" /> <ClInclude Include="HLE\sceNetApctl.h" />

View file

@ -2178,6 +2178,9 @@
<ClInclude Include="LuaContext.h"> <ClInclude Include="LuaContext.h">
<Filter>Core</Filter> <Filter>Core</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="HLE\PSPThreadContext.h">
<Filter>HLE\Kernel</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\LICENSE.TXT" /> <None Include="..\LICENSE.TXT" />

View file

@ -22,6 +22,7 @@
#include <mutex> #include <mutex>
#include "Core/MIPS/MIPSDebugInterface.h" #include "Core/MIPS/MIPSDebugInterface.h"
#include "Common/Math/expression_parser.h"
enum BreakAction : u32 { enum BreakAction : u32 {
BREAK_ACTION_IGNORE = 0x00, BREAK_ACTION_IGNORE = 0x00,

View file

@ -18,9 +18,11 @@
#pragma once #pragma once
#include <cstdio> #include <cstdio>
#include "Core/HLE/sceKernelThread.h" #include "Core/HLE/PSPThreadContext.h"
#include "Core/MIPS/MIPSDebugInterface.h" #include "Core/MIPS/MIPSDebugInterface.h"
struct PSPThreadContext;
class KernelThreadDebugInterface : public DebugInterface { class KernelThreadDebugInterface : public DebugInterface {
public: public:
KernelThreadDebugInterface(PSPThreadContext &t) : ctx(t) {} KernelThreadDebugInterface(PSPThreadContext &t) : ctx(t) {}

View file

@ -0,0 +1,35 @@
#pragma once
// Had to break this out into its own header to solve a circular include issue.
#include "Common/CommonTypes.h"
struct PSPThreadContext {
void reset();
// r must be followed by f.
u32 r[32];
union {
float f[32];
u32 fi[32];
int fs[32];
};
union {
float v[128];
u32 vi[128];
};
u32 vfpuCtrl[16];
union {
struct {
u32 pc;
u32 lo;
u32 hi;
u32 fcr31;
u32 fpcond;
};
u32 other[6];
};
};

View file

@ -74,11 +74,6 @@
#include "GPU/GPUCommon.h" #include "GPU/GPUCommon.h"
#include "GPU/GPUState.h" #include "GPU/GPUState.h"
enum {
PSP_THREAD_ATTR_KERNEL = 0x00001000,
PSP_THREAD_ATTR_USER = 0x80000000,
};
enum : u32 { enum : u32 {
// Function exports. // Function exports.
NID_MODULE_START = 0xD632ACDB, NID_MODULE_START = 0xD632ACDB,

View file

@ -105,23 +105,6 @@ enum ThreadEventType {
bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type); bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type);
enum {
PSP_THREAD_ATTR_KERNEL = 0x00001000,
PSP_THREAD_ATTR_VFPU = 0x00004000,
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000, // Save/restore scratch as part of context???
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000, // No filling of 0xff.
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000, // Clear thread stack when deleted.
PSP_THREAD_ATTR_LOW_STACK = 0x00400000, // Allocate stack from bottom not top.
PSP_THREAD_ATTR_USER = 0x80000000,
PSP_THREAD_ATTR_USBWLAN = 0xa0000000,
PSP_THREAD_ATTR_VSH = 0xc0000000,
// TODO: Support more, not even sure what all of these mean.
PSP_THREAD_ATTR_USER_MASK = 0xf8f060ff,
PSP_THREAD_ATTR_USER_ERASE = 0x78800000,
PSP_THREAD_ATTR_SUPPORTED = (PSP_THREAD_ATTR_KERNEL | PSP_THREAD_ATTR_VFPU | PSP_THREAD_ATTR_NO_FILLSTACK | PSP_THREAD_ATTR_CLEAR_STACK | PSP_THREAD_ATTR_LOW_STACK | PSP_THREAD_ATTR_USER)
};
struct NativeCallback struct NativeCallback
{ {
SceUInt_le size; SceUInt_le size;
@ -173,58 +156,6 @@ public:
NativeCallback nc; NativeCallback nc;
}; };
#if COMMON_LITTLE_ENDIAN
typedef WaitType WaitType_le;
#else
typedef swap_struct_t<WaitType, swap_32_t<WaitType> > WaitType_le;
#endif
// Real PSP struct, don't change the fields.
struct SceKernelThreadRunStatus
{
SceSize_le size;
u32_le status;
s32_le currentPriority;
WaitType_le waitType;
SceUID_le waitID;
s32_le wakeupCount;
SceKernelSysClock runForClocks;
s32_le numInterruptPreempts;
s32_le numThreadPreempts;
s32_le numReleases;
};
// Real PSP struct, don't change the fields.
struct NativeThread
{
u32_le nativeSize;
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
// Threading stuff
u32_le attr;
u32_le status;
u32_le entrypoint;
u32_le initialStack;
u32_le stackSize;
u32_le gpreg;
s32_le initialPriority;
s32_le currentPriority;
WaitType_le waitType;
SceUID_le waitID;
s32_le wakeupCount;
s32_le exitStatus;
SceKernelSysClock runForClocks;
s32_le numInterruptPreempts;
s32_le numThreadPreempts;
s32_le numReleases;
};
struct ThreadWaitInfo {
u32 waitValue;
u32 timeoutPtr;
};
// Owns outstanding MIPS calls and provides a way to get them by ID. // Owns outstanding MIPS calls and provides a way to get them by ID.
class MipsCallManager { class MipsCallManager {
public: public:
@ -344,8 +275,7 @@ public:
PSPAction *chainedAction; PSPAction *chainedAction;
}; };
class ActionAfterCallback : public PSPAction class ActionAfterCallback : public PSPAction {
{
public: public:
ActionAfterCallback() {} ActionAfterCallback() {}
void run(MipsCall &call) override; void run(MipsCall &call) override;
@ -354,13 +284,11 @@ public:
return new ActionAfterCallback; return new ActionAfterCallback;
} }
void setCallback(SceUID cbId_) void setCallback(SceUID cbId_) {
{
cbId = cbId_; cbId = cbId_;
} }
void DoState(PointerWrap &p) override void DoState(PointerWrap &p) override {
{
auto s = p.Section("ActionAfterCallback", 1); auto s = p.Section("ActionAfterCallback", 1);
if (!s) if (!s)
return; return;
@ -371,14 +299,11 @@ public:
SceUID cbId; SceUID cbId;
}; };
class PSPThread : public KernelObject { u32 PSPThread::GetMissingErrorCode() {
public: return SCE_KERNEL_ERROR_UNKNOWN_THID;
PSPThread() : debug(context) {} }
const char *GetName() override { return nt.name; } void PSPThread::GetQuickInfo(char *ptr, int size) {
const char *GetTypeName() override { return GetStaticTypeName(); }
static const char *GetStaticTypeName() { return "Thread"; }
void GetQuickInfo(char *ptr, int size) override {
snprintf(ptr, size, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )", snprintf(ptr, size, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
context.pc, context.r[MIPS_REG_SP], context.pc, context.r[MIPS_REG_SP],
(nt.status & THREADSTATUS_RUNNING) ? "RUN" : "", (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
@ -390,13 +315,16 @@ public:
(int)nt.waitType, (int)nt.waitType,
nt.waitID, nt.waitID,
waitInfo.waitValue); waitInfo.waitValue);
}
BlockAllocator &PSPThread::StackAllocator() {
if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
return kernelMemory;
} }
return userMemory;
}
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } bool PSPThread::AllocateStack(u32 &stackSize) {
static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; }
int GetIDType() const override { return SCE_KERNEL_TMID_Thread; }
bool AllocateStack(u32 &stackSize) {
_assert_msg_(stackSize >= 0x200, "thread stack should be 256 bytes or larger"); _assert_msg_(stackSize >= 0x200, "thread stack should be 256 bytes or larger");
FreeStack(); FreeStack();
@ -414,9 +342,9 @@ public:
nt.initialStack = currentStack.start; nt.initialStack = currentStack.start;
nt.stackSize = stackSize; nt.stackSize = stackSize;
return true; return true;
} }
bool FillStack() { bool PSPThread::FillStack() {
// Fill the stack. // Fill the stack.
if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) { if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadFillStack"); Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadFillStack");
@ -436,9 +364,9 @@ public:
Memory::Write_U32(GetUID(), nt.initialStack); Memory::Write_U32(GetUID(), nt.initialStack);
return true; return true;
} }
void FreeStack() { void PSPThread::FreeStack() {
if (currentStack.start != 0) { if (currentStack.start != 0) {
DEBUG_LOG(Log::sceKernel, "Freeing thread stack %s", nt.name); DEBUG_LOG(Log::sceKernel, "Freeing thread stack %s", nt.name);
@ -449,10 +377,9 @@ public:
StackAllocator().Free(currentStack.start); StackAllocator().Free(currentStack.start);
currentStack.start = 0; currentStack.start = 0;
} }
} }
bool PushExtendedStack(u32 size) bool PSPThread::PushExtendedStack(u32 size) {
{
u32 stack = userMemory.Alloc(size, true, StringFromFormat("extended/%s", nt.name).c_str()); u32 stack = userMemory.Alloc(size, true, StringFromFormat("extended/%s", nt.name).c_str());
if (stack == (u32)-1) if (stack == (u32)-1)
return false; return false;
@ -467,10 +394,9 @@ public:
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadExtendStack"); Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadExtendStack");
Memory::Write_U32(GetUID(), nt.initialStack); Memory::Write_U32(GetUID(), nt.initialStack);
return true; return true;
} }
bool PopExtendedStack() bool PSPThread::PopExtendedStack() {
{
if (pushedStacks.size() == 0) if (pushedStacks.size() == 0)
return false; return false;
@ -480,47 +406,22 @@ public:
nt.initialStack = currentStack.start; nt.initialStack = currentStack.start;
nt.stackSize = currentStack.end - currentStack.start; nt.stackSize = currentStack.end - currentStack.start;
return true; return true;
} }
// Can't use a destructor since savestates will call that too. void PSPThread::Cleanup() {
void Cleanup()
{
// Callbacks are automatically deleted when their owning thread is deleted. // Callbacks are automatically deleted when their owning thread is deleted.
for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it) for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
kernelObjects.Destroy<PSPCallback>(*it); kernelObjects.Destroy<PSPCallback>(*it);
if (pushedStacks.size() != 0) if (pushedStacks.size() != 0) {
{
WARN_LOG_REPORT(Log::sceKernel, "Thread ended within an extended stack"); WARN_LOG_REPORT(Log::sceKernel, "Thread ended within an extended stack");
for (size_t i = 0; i < pushedStacks.size(); ++i) for (size_t i = 0; i < pushedStacks.size(); ++i)
userMemory.Free(pushedStacks[i].start); userMemory.Free(pushedStacks[i].start);
} }
FreeStack(); FreeStack();
} }
BlockAllocator &StackAllocator() { void PSPThread::DoState(PointerWrap &p) {
if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
return kernelMemory;
}
return userMemory;
}
void setReturnValue(u32 retval);
void setReturnValue(u64 retval);
void resumeFromWait();
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; }
inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
void DoState(PointerWrap &p) override
{
auto s = p.Section("Thread", 1, 5); auto s = p.Section("Thread", 1, 5);
if (!s) if (!s)
return; return;
@ -535,8 +436,7 @@ public:
// TODO: If we want to "version" a DoState method here, we can just use minVer = 0. // TODO: If we want to "version" a DoState method here, we can just use minVer = 0.
Do(p, context); Do(p, context);
if (s <= 3) if (s <= 3) {
{
// We must have been loading an old state if we're here. // We must have been loading an old state if we're here.
// Reorder VFPU data to new order. // Reorder VFPU data to new order.
float temp[128]; float temp[128];
@ -546,8 +446,7 @@ public:
} }
} }
if (s <= 2) if (s <= 2) {
{
context.other[4] = context.other[5]; context.other[4] = context.other[5];
context.other[3] = context.other[4]; context.other[3] = context.other[4];
} }
@ -560,44 +459,12 @@ public:
Do(p, pushedStacks); Do(p, pushedStacks);
Do(p, currentStack); Do(p, currentStack);
if (s >= 2) if (s >= 2) {
{
Do(p, waitingThreads); Do(p, waitingThreads);
Do(p, pausedWaits); Do(p, pausedWaits);
} }
} }
NativeThread nt{};
ThreadWaitInfo waitInfo{};
SceUID moduleId = -1;
bool isProcessingCallbacks = false;
u32 currentMipscallId = -1;
SceUID currentCallbackId = -1;
PSPThreadContext context{};
KernelThreadDebugInterface debug;
std::vector<SceUID> callbacks;
std::list<u32> pendingMipsCalls;
struct StackInfo {
u32 start;
u32 end;
};
// This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
// These are stacks that aren't "active" right now, but will pop off once the func returns.
std::vector<StackInfo> pushedStacks;
StackInfo currentStack{};
// For thread end.
std::vector<SceUID> waitingThreads;
// Key is the callback id it was for, or if no callback, the thread id.
std::map<SceUID, u64> pausedWaits;
};
struct WaitTypeFuncs struct WaitTypeFuncs
{ {
@ -3104,7 +2971,20 @@ void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus) {
} }
} }
const char *ThreadStatusToString(ThreadStatus status) {
switch (status) {
case THREADSTATUS_RUNNING: return "Running";
case THREADSTATUS_READY: return "Ready";
case THREADSTATUS_WAIT: return "Wait";
case THREADSTATUS_SUSPEND: return "Suspended";
case THREADSTATUS_DORMANT: return "Dormant";
case THREADSTATUS_DEAD: return "Dead";
case THREADSTATUS_WAITSUSPEND: return "WaitSuspended";
default:
break;
}
return "(unk)";
}
static bool __CanExecuteCallbackNow(PSPThread *thread) { static bool __CanExecuteCallbackNow(PSPThread *thread) {
return currentCallbackThreadID == 0 && g_inCbCount == 0; return currentCallbackThreadID == 0 && g_inCbCount == 0;
@ -3540,7 +3420,7 @@ std::vector<DebugThreadInfo> GetThreadsInfo() {
info.id = uid; info.id = uid;
strncpy(info.name,t->GetName(),KERNELOBJECT_MAX_NAME_LENGTH); strncpy(info.name,t->GetName(),KERNELOBJECT_MAX_NAME_LENGTH);
info.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; info.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
info.status = t->nt.status; info.status = (ThreadStatus)t->nt.status;
info.entrypoint = t->nt.entrypoint; info.entrypoint = t->nt.entrypoint;
info.initialStack = t->nt.initialStack; info.initialStack = t->nt.initialStack;
info.stackSize = (u32)t->nt.stackSize; info.stackSize = (u32)t->nt.stackSize;

View file

@ -19,15 +19,20 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#include <list>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernel.h"
#include "Core/HLE/PSPThreadContext.h"
#include "Core/HLE/KernelThreadDebugInterface.h"
// There's a good description of the thread scheduling rules in: // There's a good description of the thread scheduling rules in:
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/ThreadManForUser.java // http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/ThreadManForUser.java
class PSPThread; class PSPThread;
class DebugInterface; class DebugInterface;
class BlockAllocator;
int sceKernelChangeThreadPriority(SceUID threadID, int priority); int sceKernelChangeThreadPriority(SceUID threadID, int priority);
SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr); SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr);
@ -82,8 +87,7 @@ struct SceKernelSysClock {
// TODO: Map these to PSP wait types. Most of these are wrong. // TODO: Map these to PSP wait types. Most of these are wrong.
// remember to update the waitTypeNames array in sceKernelThread.cpp when changing these // remember to update the waitTypeNames array in sceKernelThread.cpp when changing these
enum WaitType : int enum WaitType : int {
{
WAITTYPE_NONE = 0, WAITTYPE_NONE = 0,
WAITTYPE_SLEEP = 1, WAITTYPE_SLEEP = 1,
WAITTYPE_DELAY = 2, WAITTYPE_DELAY = 2,
@ -124,34 +128,156 @@ typedef void (* WaitEndCallbackFunc)(SceUID threadID, SceUID prevCallbackId);
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc); void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc);
struct PSPThreadContext { #if COMMON_LITTLE_ENDIAN
void reset(); typedef WaitType WaitType_le;
#else
typedef swap_struct_t<WaitType, swap_32_t<WaitType> > WaitType_le;
#endif
// r must be followed by f. // Real PSP struct, don't change the fields.
u32 r[32]; struct SceKernelThreadRunStatus {
union { SceSize_le size;
float f[32]; u32_le status;
u32 fi[32]; s32_le currentPriority;
int fs[32]; WaitType_le waitType;
}; SceUID_le waitID;
union { s32_le wakeupCount;
float v[128]; SceKernelSysClock runForClocks;
u32 vi[128]; s32_le numInterruptPreempts;
}; s32_le numThreadPreempts;
u32 vfpuCtrl[16]; s32_le numReleases;
};
union { // Real PSP struct, don't change the fields.
struct { struct NativeThread {
u32 pc; u32_le nativeSize;
char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
u32 lo; // Threading stuff
u32 hi; u32_le attr;
u32_le status;
u32_le entrypoint;
u32_le initialStack;
u32_le stackSize;
u32_le gpreg;
u32 fcr31; s32_le initialPriority;
u32 fpcond; s32_le currentPriority;
}; WaitType_le waitType;
u32 other[6]; SceUID_le waitID;
s32_le wakeupCount;
s32_le exitStatus;
SceKernelSysClock runForClocks;
s32_le numInterruptPreempts;
s32_le numThreadPreempts;
s32_le numReleases;
};
struct ThreadWaitInfo {
u32 waitValue;
u32 timeoutPtr;
};
enum {
PSP_THREAD_ATTR_KERNEL = 0x00001000,
PSP_THREAD_ATTR_VFPU = 0x00004000,
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000, // Save/restore scratch as part of context???
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000, // No filling of 0xff.
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000, // Clear thread stack when deleted.
PSP_THREAD_ATTR_LOW_STACK = 0x00400000, // Allocate stack from bottom not top.
PSP_THREAD_ATTR_USER = 0x80000000,
PSP_THREAD_ATTR_USBWLAN = 0xa0000000,
PSP_THREAD_ATTR_VSH = 0xc0000000,
// TODO: Support more, not even sure what all of these mean.
PSP_THREAD_ATTR_USER_MASK = 0xf8f060ff,
PSP_THREAD_ATTR_USER_ERASE = 0x78800000,
PSP_THREAD_ATTR_SUPPORTED = (PSP_THREAD_ATTR_KERNEL | PSP_THREAD_ATTR_VFPU | PSP_THREAD_ATTR_NO_FILLSTACK | PSP_THREAD_ATTR_CLEAR_STACK | PSP_THREAD_ATTR_LOW_STACK | PSP_THREAD_ATTR_USER)
};
enum ThreadStatus : u32 {
THREADSTATUS_RUNNING = 1,
THREADSTATUS_READY = 2,
THREADSTATUS_WAIT = 4,
THREADSTATUS_SUSPEND = 8,
THREADSTATUS_DORMANT = 16,
THREADSTATUS_DEAD = 32,
THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
};
const char *ThreadStatusToString(ThreadStatus status);
class PSPThread : public KernelObject {
public:
PSPThread() : debug(context) {}
const char *GetName() override { return nt.name; }
const char *GetTypeName() override { return GetStaticTypeName(); }
static const char *GetStaticTypeName() { return "Thread"; }
void GetQuickInfo(char *ptr, int size) override;
static u32 GetMissingErrorCode();
static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; }
int GetIDType() const override { return SCE_KERNEL_TMID_Thread; }
bool AllocateStack(u32 &stackSize);
bool FillStack();
void FreeStack();
bool PushExtendedStack(u32 size);
bool PopExtendedStack();
// Can't use a destructor since savestates will call that too.
void Cleanup();
BlockAllocator &StackAllocator();
void setReturnValue(u32 retval);
void setReturnValue(u64 retval);
void resumeFromWait();
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; }
inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
void DoState(PointerWrap &p) override;
NativeThread nt{};
ThreadWaitInfo waitInfo{};
SceUID moduleId = -1;
KernelThreadDebugInterface debug;
bool isProcessingCallbacks = false;
u32 currentMipscallId = -1;
SceUID currentCallbackId = -1;
PSPThreadContext context{};
std::vector<SceUID> callbacks;
// TODO: Should probably just be a vector.
std::list<u32> pendingMipsCalls;
struct StackInfo {
u32 start;
u32 end;
}; };
// This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
// These are stacks that aren't "active" right now, but will pop off once the func returns.
std::vector<StackInfo> pushedStacks;
StackInfo currentStack{};
// For thread end.
std::vector<SceUID> waitingThreads;
// Key is the callback id it was for, or if no callback, the thread id.
std::map<SceUID, u64> pausedWaits;
}; };
// Internal API, used by implementations of kernel functions // Internal API, used by implementations of kernel functions
@ -296,18 +422,6 @@ public:
int actionTypeID; int actionTypeID;
}; };
enum ThreadStatus
{
THREADSTATUS_RUNNING = 1,
THREADSTATUS_READY = 2,
THREADSTATUS_WAIT = 4,
THREADSTATUS_SUSPEND = 8,
THREADSTATUS_DORMANT = 16,
THREADSTATUS_DEAD = 32,
THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
};
void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus); void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus);
typedef void (*ThreadCallback)(SceUID threadID); typedef void (*ThreadCallback)(SceUID threadID);
@ -317,7 +431,7 @@ struct DebugThreadInfo
{ {
SceUID id; SceUID id;
char name[KERNELOBJECT_MAX_NAME_LENGTH+1]; char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
u32 status; ThreadStatus status;
u32 curPC; u32 curPC;
u32 entrypoint; u32 entrypoint;
u32 initialStack; u32 initialStack;

View file

@ -18,7 +18,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <cstdio>
#include "Common/Math/expression_parser.h" #include "Common/Math/expression_parser.h"
#include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPS.h"
#include "Core/Debugger/DebugInterface.h" #include "Core/Debugger/DebugInterface.h"

View file

@ -25,7 +25,6 @@
#include "Core/HLE/ErrorCodes.h" #include "Core/HLE/ErrorCodes.h"
#include "Core/HLE/sceKernelMemory.h" #include "Core/HLE/sceKernelMemory.h"
#include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceKernelInterrupt.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceGe.h" #include "Core/HLE/sceGe.h"
#include "Core/Util/PPGeDraw.h" #include "Core/Util/PPGeDraw.h"
#include "Core/MemMapHelpers.h" #include "Core/MemMapHelpers.h"
@ -37,6 +36,8 @@
#include "GPU/Debugger/Record.h" #include "GPU/Debugger/Record.h"
#include "GPU/Debugger/Stepping.h" #include "GPU/Debugger/Stepping.h"
bool __KernelIsDispatchEnabled();
void GPUCommon::Flush() { void GPUCommon::Flush() {
drawEngineCommon_->Flush(); drawEngineCommon_->Flush();
} }

View file

@ -306,21 +306,6 @@ static void DrawVFPU(ImConfig &config, ImControl &control, const MIPSDebugInterf
ImGui::End(); ImGui::End();
} }
static const char *ThreadStatusToString(u32 status) {
switch (status) {
case THREADSTATUS_RUNNING: return "Running";
case THREADSTATUS_READY: return "Ready";
case THREADSTATUS_WAIT: return "Wait";
case THREADSTATUS_SUSPEND: return "Suspended";
case THREADSTATUS_DORMANT: return "Dormant";
case THREADSTATUS_DEAD: return "Dead";
case THREADSTATUS_WAITSUSPEND: return "WaitSuspended";
default:
break;
}
return "(unk)";
}
void WaitIDToString(WaitType waitType, SceUID waitID, char *buffer, size_t bufSize) { void WaitIDToString(WaitType waitType, SceUID waitID, char *buffer, size_t bufSize) {
switch (waitType) { switch (waitType) {
case WAITTYPE_AUDIOCHANNEL: case WAITTYPE_AUDIOCHANNEL: