Threads: sceKernelStartThread hands the CPU straight to a better thread

When the new thread outranks the caller, the firmware switches to it
directly, even if a thread of still better priority is ready but hasn't
been dispatched (one that a sceKernelTerminateThread woke, say). Verified
against the new pspautotests threads/threads/termsuspended.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-09-29 09:19:32 -06:00
1 parent 23fc0cd422
commit 638da935ea
2 files changed
+23 -2

No files matched your search

+22 -1
View File
@@ -1629,8 +1629,17 @@ static PSPThread *__KernelNextThread() {
return 0;
}
// Set by sceKernelStartThread when the new thread outranks the caller, for the reschedule right
// after it. The firmware hands the CPU straight to the new thread, even when a thread of better
// priority is ready but hasn't been dispatched (say, one that a sceKernelTerminateThread woke.)
// See tests/threads/threads/termsuspended.
static SceUID g_startThreadHandoff = 0;
void __KernelReSchedule(const char *reason)
{
const SceUID handoff = g_startThreadHandoff;
g_startThreadHandoff = 0;
// First, let's check if there are any pending callbacks to trigger.
// TODO: Could probably take this out of __KernelReSchedule() which is a bit hot.
__KernelCheckCallbacks();
@@ -1643,6 +1652,16 @@ void __KernelReSchedule(const char *reason)
return;
}
if (handoff != 0) {
u32 error;
PSPThread *started = kernelObjects.Get<PSPThread>(handoff, error);
if (started && started->nt.status == THREADSTATUS_READY) {
threadReadyQueue.remove(started->nt.currentPriority, handoff);
__KernelSwitchContext(started, reason);
return;
}
}
PSPThread *nextThread = __KernelNextThread();
if (nextThread) {
__KernelSwitchContext(nextThread, reason);
@@ -1971,8 +1990,10 @@ int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bo
if (cur && cur->nt.currentPriority > startThread->nt.currentPriority) {
KernelValidateThreadTarget(startThread->context.pc);
__KernelChangeReadyState(cur, currentThread, true);
if (__InterruptsEnabled())
if (__InterruptsEnabled()) {
g_startThreadHandoff = threadToStartID;
hleReSchedule("thread started");
}
}
// Starting a thread automatically resumes the dispatch thread if the new thread has worse priority.