Repository navigation
Conversation
libkernel's InitThread, which _InitSys runs before main, creates a semaphore and a priority-zero topThread that waits on it, then lowers its caller to priority one. The runtime handler did neither and returned the main thread's id. A game whose InitThread is bound to it keeps its bootstrap thread at priority zero, so RotateThreadReadyQueue yields to its priority-one workers never let them run: King's Field IV's opening movie stalls with its decoder thread starved. topThread only replays requests the libkernel i* wrappers post to it. The runtime binds those wrappers (iWakeupThread, iRotateThreadReadyQueue) to handlers that act on the scheduler directly, so its stand-in never has to run. It still takes the semaphore and thread ids the real one holds and waits on its semaphore, so later ids, and the status and priorities ReferThreadStatus reports, match the hardware. The handler lowers the caller to priority one, returns the new thread's id, and returns -1 if called again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The runtime's
InitThreadhandler returned the main thread's id and nothingelse. libkernel's
InitThread, which_InitSysruns beforemain, creates asemaphore and a priority-0
topThreadwaiting on it, then lowers its callerto priority 1. A game bound to the handler kept its bootstrap at priority 0,
so
RotateThreadReadyQueue(1)never let its priority-1 workers run. King'sField IV's opening movie stalled on its first frame with the decoder starved.
EeScheduler::initThread()now:waiting on it, so later semaphore/thread ids, and the status and
priorities
ReferThreadStatusreports, match the hardware (its entry,stack and gp read as 0);
changePriority(the handler thencalls
transferIfRequested, likeChangeThreadPriority);The stand-in never runs. topThread exists only to replay requests that
libkernel's
i*wrappers post to it, and the runtime bindsiWakeupThreadand
iRotateThreadReadyQueueto handlers that act on the scheduler directly.For this reason, bind
InitThreadtogether with those wrappers, never alone:with the handler the game's own topThread never exists, so a recompiled
wrapper that posts to it fails (returns −1).
iSuspendThreadhas no handlerand is not in the exporter's list; a game that suspends the current thread
from an interrupt through it would need one.
Not in this PR:
createThreadstill rejects priority 0, so a recompiled(non-stubbed) libkernel
InitThreadfails the same way. That is aseparate one-line change (
priority < 0).Tests: a ps2xTest kernel case runs
InitThreadfrom a main thread, checks thereturned id, topThread's wait state and priority, the caller's priority, the
−1 repeat call and the next thread id, then shows
RotateThreadReadyQueue(1)yielding to a priority-1 worker (with the old handler the trace is
{1, 2, 3}: the worker never runs).The ps2xTest case and its control were run on main 2c5fbb9 (437/438 pass;
the one failure, "VU0 macro mappings cover all S1/S2 enums", reads
instructions.hfrom the working directory and fails without this changetoo). The game check below ran on the holyland patch series (which also
includes Vulkan GS and accepts priority 0 in
createThread) with thiscommit applied.
Verified on King's Field IV with
InitThreadbound to the handler: theopening movie plays to its natural end and gameplay is reached by tick 12000.
The movie frames (ticks 500–7500) are pixel-identical to a build that
recompiles the game's own
InitThread, over two runs of each. Later 3D framesshow the same scenes but vary from run to run in both builds, so they do not
compare. The old handler stalls at tick ~2200 (0 flips/s).
🤖 Generated with Claude Code