Skip to content

feat(libkernel): implement rtprio_thread and the pthread concurrency controls - #5556

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
Nixitov:feat/rtprio-thread
Oct 15, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
Nixitov:feat/rtprio-thread

Conversation

@Nixitov

@Nixitov Nixitov commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What

Implement the thread-scheduling controls the Morrowind port (mshivam019/morrowind-ps5) imports and stops at start-up on main:

FAIL: unresolved ELF import 2I2RV6LyNng from libkernel.prx
  • rtprio_thread (2I2RV6LyNng) follows FreeBSD 11.4's rtprio_thread(2). Every guest thread here runs under SCHED_FIFO/SCHED_RR (priority 256-767), whose rtprio class is real-time; the console's mapping from that priority to the rtprio prio range (RTP_PRIO_MIN..RTP_PRIO_MAX, 0-31) is unmeasured, so RTP_LOOKUP and RTP_SET throw for such a thread rather than report an impossible priority. A thread that is not real-time reports RTP_PRIO_NORMAL (3) with 0, and RTP_SET accepts only that value. Another function fails with EINVAL, a null rtprio with EFAULT, a thread other than the calling one throws, and an id that is not a live guest thread with ESRCH.
  • pthread_setconcurrency (fBG1gHx1RlI) stores a level of 0 or more (EINVAL when negative) and pthread_getconcurrency (s+QHU9RLHS4) returns it; the level is a hint and nothing about the host's concurrency changes.

The models are recorded in docs/dev/debt/libkernel.md.

Tested

Windows 11, MinGW-w64 GCC 15.2.0 (WinLibs r7), Release.

  • guest_sched_priority is extended with the three functions: the rtprio_thread lookup and set throw for the calling (real-time) thread, the unchanged errno on the failing cases, the EINVAL/EFAULT/ESRCH cases, and the concurrency set/get round trip with its EINVAL; it passes.
  • Morrowind (mshivam019/morrowind-ps5, v1.0.1 windows asset), eboot.bin unwrapped and relinked with the built relinker --windows, on this head rebased onto main (which now carries feat(libc): export tzname #5009's tzname): on main it fails at load with 2I2RV6LyNng; with this change it relinks, loads and transfers control to the ELF entry point.
  • The title does not call any of the three controls: with the three exports temporarily writing to stderr on entry (traces discarded afterwards), the run logs no such line before the title exits, ~1.7 s after entry. The throwing real-time path is therefore not exercised by this title; the start-up import stop is removed either way.
  • python tools/check_conventions.py --base origin/main passes.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: Morrowind (mshivam019/morrowind-ps5) — removes its start-up import stop (2I2RV6LyNng)
  • GPUs tested: n/a
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Progress report (066b58f → 4091519)

📉 System libraries: 88.65% (-0.02%, +2 implemented, +1 declared functions)

✅ 2 implemented
Library Name
libkernel pthread_getconcurrency_nid_postfix
libkernel pthread_setconcurrency_nid_postfix
🆕 1 declared as stubs
Library Name
libkernel rtprio_thread_nid_postfix

@CnRJay CnRJay left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two problems with rtprio_thread:

1. RTP_PRIO_NORMAL isn't 0. In FreeBSD's sys/rtprio.h the types are the scheduler classes from sys/priority.h: RTP_PRIO_ITHD 1, RTP_PRIO_REALTIME 2, RTP_PRIO_NORMAL 3 (PRI_TIMESHARE), RTP_PRIO_IDLE 4, and RTP_PRIO_FIFO 10 (PRI_REALTIME | PRI_FIFO_BIT). Type 0 isn't a defined class. A caller that compares type == RTP_PRIO_NORMAL or switches on it gets an unknown value from RTP_LOOKUP.

2. Set-then-lookup is inconsistent. RTP_SET returns 0 without storing anything, so a following RTP_LOOKUP returns the old answer, not the value just set. Under the exact-or-throw rule that is a silent stub. A setter that succeeds should be observable through its getter.

There's also a semantic question. Guest threads here already carry a console scheduling policy and priority (SCHED_FIFO/SCHED_RR, 256–767, measured on hardware in #5230), so "every thread is RTP_PRIO_NORMAL at 0" contradicts what scePthreadGetschedparam reports for the same thread. On FreeBSD, rtprio_thread is a view of the same per-thread scheduling state (pri_to_rtp from the thread's class and priority). It would be more consistent to derive the lookup from the thread's stored policy and priority, and either map RTP_SET onto them or throw NotImplemented for values that would change them, until the console's mapping from rtprio to its 256–767 range is measured.

Which call does the Morrowind port make? If it only does RTP_LOOKUP, or RTP_SET with what it just read, a narrower exact version would unblock it.

pthread_setconcurrency / pthread_getconcurrency look right: the level is stored and returned, which is all POSIX requires.

@Nixitov

Nixitov commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Same-file overlap only with #5611: it adds a technical-debt entry near the one this adds in docs/dev/debt/libkernel.md. No shared logic — either can land first and the other rebases.

AI-assisted: yes

@Nixitov
Nixitov force-pushed the feat/rtprio-thread branch from 05a9a36 to 90f609a Compare October 14, 2026 01:33
@Nixitov

Nixitov commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review — both points are addressed.

1. RTP_PRIO_NORMAL is 3, not 0. You're right. The lookup now returns the FreeBSD class numbers: RTP_PRIO_REALTIME (2) with the thread's priority for SCHED_FIFO/SCHED_RR, and RTP_PRIO_NORMAL (3) with 0 otherwise.

2. Set-then-lookup is now consistent. RTP_LOOKUP derives the value from the calling thread's stored policy and priority — the same state scePthreadGetschedparam reports — and RTP_SET succeeds only when it is handed that same value; any other value throws. So a succeeding set is observable through a following lookup and nothing is dropped silently. Reading a thread other than the calling one isn't modelled yet, so rtprio_thread on a live other thread throws instead of reporting the caller's state.

Which call Morrowind makes: I can't observe it from here yet — the title now stops at tzname (libSceLibcInternal, #5009) before it runs, so rtprio_thread is never reached in a run. Once #5009 lands I can capture the call; if the port sets a class we don't model, we can map it then (the console's mapping from the guest's 256–767 priority to the rtprio priority is unmeasured, and the debt entry now says so).

pthread_setconcurrency / pthread_getconcurrency are unchanged, as you noted.

AI-assisted: yes

@CnRJay

CnRJay commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Thanks, both points are handled the right way. Lookup comes from the thread's real state, and anything that would change that state throws.

Two small things on the new head:

  • The real-time prio range. FreeBSD's rtprio priorities for RTP_PRIO_REALTIME are 0–31 (RTP_PRIO_MIN..RTP_PRIO_MAX). Returning the guest priority (256–767) in prio gives values outside that range, so a caller that validates or indexes by it sees an impossible value. Since the console's mapping is unmeasured (as the debt entry now says), the exact option is to throw from RTP_LOOKUP for a real-time thread too, and report only the RTP_PRIO_NORMAL case for now.
  • fchown landed in this branch. The new fchown_nid_postfix (and the GuestFstat helper) isn't mentioned in the description and is a separate export. Per the one-topic rule, it would be better as its own PR, with the title that needs it.

@CnRJay

CnRJay commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Correction to my note above: #5562 already adds fchown on its own, so this branch probably just picked up that commit. Dropping it here and listing #5562 under Depends on if needed resolves it.

@github-actions github-actions Bot added the prx label Oct 14, 2026
@Nixitov
Nixitov force-pushed the feat/rtprio-thread branch from 90f609a to 6b3f79b Compare October 14, 2026 01:49
@Nixitov

Nixitov commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Thanks — both taken.

1. The real-time prio range. You're right that 256–767 is outside RTP_PRIO_MIN..RTP_PRIO_MAX (0–31), and every guest thread here runs under SCHED_FIFO/SCHED_RR, so the lookup has no measured mapping. RTP_LOOKUP (and RTP_SET) now throw for a thread whose policy is SCHED_FIFO/SCHED_RR, rather than report an impossible priority; a non-real-time thread reports RTP_PRIO_NORMAL (3) with 0, and RTP_SET accepts only that. The debt entry now says the mapping is unmeasured and that the real-time case throws.

2. fchown was in this branch — good catch. It came from a local build that stitched #5562 in; the commit now carries only rtprio_thread/concurrency (Thread.cpp, GuestSchedPriority.cpp, and the debt entry). It's dropped here, so no Depends on is needed and #5562 stands alone. (The stale-file listing you saw also came from that —rebuilt the branch onto current main.)

pthread_setconcurrency / pthread_getconcurrency are unchanged.

AI-assisted: yes

@CnRJay

CnRJay commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Thanks, throwing for the real-time case is the right call while the mapping is unmeasured.

One consequence to check: if every guest thread runs under SCHED_FIFO/SCHED_RR, then every RTP_LOOKUP and RTP_SET on a guest thread now throws, including Morrowind's. The Tested line ("passes rtprio_thread … and stops at fchown") and Unblocks: Morrowind were measured with the earlier version. Could you rerun the title on this head and update both? If it now stops inside rtprio_thread, the debt entry should say that too. The concurrency pair would still be worth landing on its own, with rtprio_thread waiting until the console's real-time mapping is known.

@Nixitov

Nixitov commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Reran the title on this head (rebased onto main, which now carries #5009's tzname) and updated both lines.

Result: with this change Morrowind relinks, loads and transfers control to the ELF entry point — on main it fails at load with 2I2RV6LyNng. It does not stop inside rtprio_thread: it never calls it. I put temporary stderr traces at the entry of the three exports and ran the title; the run logs none of them before the title exits, ~1.7 s after entry (traces discarded, nothing committed). So the real-time throw isn't exercised by this title, and the debt entry already says the real-time path throws while the mapping is unmeasured.

On splitting: the concurrency pair can't stand alone as a stop — 2I2RV6LyNng is first in the registry, so a title stopped there wouldn't advance on the pair alone. rtprio_thread throwing is still better than absent for a title that merely imports it (absent fails the load; throwing only fails if it is actually called). I've kept the three together as one topic ("the thread controls Morrowind imports"). Happy to split if you'd rather land the pair now and hold rtprio_thread until the mapping is measured — say the word.

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick rounds on rtprio_thread. One thing left:

  • pthread_setconcurrency (Thread.cpp:157-160) returns -1 and sets errno to EINVAL for a negative level. FreeBSD 11.4's libthr _pthread_setconcurrency returns EINVAL directly and leaves errno alone, like every other pthread_* function (POSIX style). Return the error code, and change GuestSchedPriority.cpp:73-74 to expect == 22 with errno untouched (success case already checks that).

Rest looks right to me (rtprio_thread classes, error cases, throws for unmodelled paths, debt entry). Happy to merge once that is fixed.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
…controls

Morrowind imports rtprio_thread, pthread_setconcurrency and pthread_getconcurrency and stops at start-up. Report every guest thread as normal priority and accept a set without applying it; store the concurrency level as a hint. Recorded in the libkernel debt.
@Nixitov

Nixitov commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Fixed and pushed (4091519b0).

  • pthread_setconcurrency (Thread.cpp:155-163) now returns EINVAL directly and leaves errno alone, like FreeBSD 11.4 libthr's _pthread_setconcurrency. GuestSchedPriority.cpp now sets errno to a sentinel (13) before the call and expects == 22 with errno still 13; the success case is unchanged.
  • The debt entry now says the error is returned rather than set through errno.

The branch is also rebased onto current main: it had become conflicting because #5545 (setpriority) merged and touched both GuestSchedPriority.cpp and docs/dev/debt/libkernel.md. The resolution keeps both changes — setpriority's declarations, tests and debt entry, and this PR's rtprio_thread/concurrency ones.

guest_sched_priority passes (Release, MinGW-w64 GCC 15.2.0) and python tools/check_conventions.py --base origin/main passes.

AI-assisted: yes

@Nixitov
Nixitov force-pushed the feat/rtprio-thread branch from 2aed1d0 to 4091519 Compare October 14, 2026 14:24
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#5611 docs/dev/debt/libkernel.md L198
#5835 docs/dev/debt/libkernel.md L198
#5993 docs/dev/debt/libkernel.md L198

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
#3891 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4156 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4396 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4397 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4422 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4423 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4424 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4520 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4521 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4522 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4523 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4566 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4599 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4718 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4740 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4749 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4760 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#4813 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#5021 core/libs/tests/GuestSchedPriority.cpp
docs/dev/debt/libkernel.md
#6044 core/libs/tests/GuestSchedPriority.cpp
#6222 docs/dev/debt/libkernel.md

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@Nixitov
Nixitov requested a review from adriadam10 October 14, 2026 18:05

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked the pthread_setconcurrency change (returns EINVAL directly, errno untouched, test pinned with a sentinel errno), the rtprio_thread paths and the debt entry against the new head. guest_sched_priority passes and fails to link without the change; merging.

@adriadam10
adriadam10 merged commit 264a528 into boykopovar:main Oct 15, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants