Skip to content

feat(libkernel): implement pselect over select - #9273

Merged
oneandonlydean merged 4 commits into
boykopovar:mainfrom
DavidSamir:feat/libkernel-sys-pselect
Oct 23, 2026
Merged

oneandonlydean merged 4 commits into
boykopovar:mainfrom
DavidSamir:feat/libkernel-sys-pselect

Conversation

@DavidSamir

@DavidSamir DavidSamir commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

pselect was a discovery stub in libkernel_sys that threw NotImplemented. It is now implemented in libkernel, in libkernel/Socket/src/Pselect.cpp beside select, and the libkernel_sys stub is removed. It is built on libkernel's select and sigprocmask, as FreeBSD 11 sys_pselect / kern_pselect (sys/kern/sys_generic.c) do:

  • The timeout: the timespec is converted with TIMESPEC_TO_TIMEVAL's truncation (tv_usec = tv_nsec / 1000), and select's own timeval check rejects what FreeBSD's itimerfix rejects. So tv_nsec of 1,000,000,000 or more gives EINVAL, 999,999,999 is accepted, and nfds < 0 gives EINVAL.
  • The mask: a non-NULL sigmask is installed with SIG_SETMASK before the wait and the previous mask is restored after it, keeping select's errno. A sigprocmask failure returns -1 before any wait.

Moved to libkernel so libkernel imports reach it on Windows. The PS5 3.20 export lists have pselect in libkernel as well as libkernel_sys, and on Windows a libkernel import never searches libkernel_sys (WindowsEntryStubBuilder.cpp:175). With the libkernel export and no libkernel_sys stub, both imports reach it, and the duplicate-export rule holds. The code is unchanged by the move.

A debt line in libkernel.md records that the mask swap is not atomic with the wait: a signal that becomes deliverable between the swap and the wait is not guaranteed to interrupt it.

Tested

Windows 11 Pro 26200, WinLibs GCC 15.2.0 r7, Release. This is a CPU-side export, so no GPU is involved.

  • New guest_kernel_sys_pselect (core/libs/tests/GuestKernelSysPselect.cpp), on a pipe:
    • a 200 ms timespec waits at least 150 ms and returns 0, with SIGUSR1 blocked through sigmask and the original mask back afterwards;
    • after a write, the read end is ready (1) with tv_nsec 999,999,999 and with a NULL timeout;
    • tv_nsec 1,000,000,000 gives EINVAL with the mask restored;
    • nfds -1 gives EINVAL.
  • On main the test aborts with pselect_nid_postfix not implemented. On this branch it passes, 3 of 3 runs. guest_kernel_sys still passes, and tools/check_conventions.py --base origin/main passes.
  • Link control: with Pselect.cpp removed from libkernel's sources, the test fails to link (undefined reference to pselect_nid_postfix), so it reaches libkernel's export. pselect is exported by libkernel only.
  • Overlap: tools/pr_overlap.py crashes on this machine's partial clone, so I ran git merge-tree against every open PR that touches these files. Removing the libkernel_sys stub conflicts textually with feat(libkernel_sys): identify the initial pthread #9160 and with my feat(libkernel): implement four pthread_attr forms #9156, which edit the neighbouring stubs. That's a one-line resolution, by merging main after either lands. Everything else merges cleanly.

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
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Progress report (0c6a5bd → 375b53d)

📈 System libraries: 42.11% (+0.01%, +1 implemented, -1 removed functions)

✅ 1 implemented
Library Name
libkernel pselect_nid_postfix
🗑️ 1 removed
Library Name
libkernel_sys pselect_nid_postfix

@github-actions

github-actions Bot commented Oct 21, 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
PR 9160 core/libs/prx/libkernel_sys/Export.Discovery.cpp L289-297

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
PR 4563 core/libs/prx/libkernel/CMakeLists.txt
PR 4630 docs/dev/debt/libkernel.md
PR 5021 core/libs/CMakeLists.txt
core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 6044 core/libs/CMakeLists.txt
core/libs/prx/libkernel/CMakeLists.txt
PR 6149 docs/dev/debt/libkernel.md
PR 6740 docs/dev/debt/libkernel.md
PR 6830 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 6936 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 7049 docs/dev/debt/libkernel.md
PR 7088 docs/dev/debt/libkernel.md
PR 7105 docs/dev/debt/libkernel.md
PR 7121 docs/dev/debt/libkernel.md
PR 7149 docs/dev/debt/libkernel.md
PR 7201 core/libs/CMakeLists.txt
core/libs/prx/libkernel/CMakeLists.txt
PR 7275 core/libs/CMakeLists.txt
PR 7509 docs/dev/debt/libkernel.md
PR 7565 docs/dev/debt/libkernel.md
PR 7653 docs/dev/debt/libkernel.md
PR 7780 core/libs/CMakeLists.txt
PR 8010 docs/dev/debt/libkernel.md
PR 8285 core/libs/CMakeLists.txt
PR 8520 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 8553 docs/dev/debt/libkernel.md
PR 8650 core/libs/CMakeLists.txt
PR 9019 core/libs/CMakeLists.txt
core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9074 docs/dev/debt/libkernel.md
PR 9133 docs/dev/debt/libkernel.md
PR 9161 core/libs/CMakeLists.txt
core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9199 docs/dev/debt/libkernel.md
PR 9256 docs/dev/debt/libkernel.md
PR 9442 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9578 docs/dev/debt/libkernel.md
PR 9669 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 9693 core/libs/prx/libkernel/CMakeLists.txt
core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9902 core/libs/CMakeLists.txt
PR 10319 docs/dev/debt/libkernel.md

@xXPBSXx

xXPBSXx commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Independent Windows run of this PR (data only).

Environment: Windows 10 Pro 10.0.19045, Ryzen 7 5800X3D, WinLibs GCC 15.2.0 r7 (MinGW-w64 UCRT), Release, BUILD_TESTING=ON. Merge-tree of the PR head against main is clean. I built only guest_kernel_sys_pselect_tests; ctest -N -R guest_kernel_sys_pselect lists exactly one test.

PR head tested: 17650eed5f911ead4c7c32edf3a3d4815d56bca9.

Results (3 runs each):

  • PR head: guest_kernel_sys_pselect passes 3/3.
  • Baseline: I kept the PR's test and replaced only core/libs/prx/libkernel_sys/Export.Discovery.cpp with the version from the PR's merge base (d34da5d694), then rebuilt. The test fails 3/3 (exit 0xc0000409). I restored the PR's files afterwards.

Not run: other platforms, the other tests in the same family, the full repository CTest, and any title or console run.

AI-assisted (Claude Code).

The PS5 3.20 export lists have pselect in libkernel as well as
libkernel_sys, and on Windows a libkernel import never reaches
libkernel_sys. The implementation moves unchanged to
libkernel/Socket/src/Pselect.cpp, beside select.
@DavidSamir DavidSamir changed the title feat(libkernel_sys): implement pselect over select feat(libkernel): implement pselect over select Oct 21, 2026
@DavidSamir

Copy link
Copy Markdown
Contributor Author

Linux: Ubuntu 24.04.1 LTS (WSL2), GCC 13.3.0, Release; head 375b53d91 merged onto main 8c26eac3c.

  • guest_kernel_sys_pselect passes 3/3.
  • Link control: with pselect_nid_postfix renamed in Pselect.cpp (instead of removing the file from the sources), the test fails to link: undefined reference to pselect_nid_postfix, as listed.

Run from the PC (Windows host, Linux in WSL2), not from the PR author's machine.

@harisibrar1 harisibrar1 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.

Checked against main a6646f8 and FreeBSD release/11.4.0 sys/kern/sys_generic.c (sys_pselect/kern_pselect, kern_select):

  • The timespec handling matches TIMESPEC_TO_TIMEVAL (truncation, also for small negative tv_nsec). The EINVAL cases for tv_nsec >= 1000000000 and nfds < 0 match kern_select's checks, and the mask is restored with errno kept. Thanks for the clear tests.
  • One gap seems larger than the debt line says. On main, select_nid_postfix (Socket.cpp) has no EINTR path; it waits until a descriptor is ready or the timeout ends. And _sigprocmask (Signals.cpp:583-586) runs the handler of a pending signal that SIG_SETMASK unblocks synchronously, inside the call. So by my reading the usual pselect idiom doesn't interrupt the wait: block SIGUSR1, raise(SIGUSR1), then pselect(0, NULL, NULL, NULL, &{0, 300000000}, &empty). FreeBSD returns -1/EINTR at once (kern_select sleeps with PCATCH). Here the handler runs inside sigprocmask, then select waits the full 300 ms and returns 0, and with a NULL timeout it wouldn't return. A pthread_kill from another thread during the wait only marks the signal pending, so it doesn't end the wait either. I didn't get to run a probe for this, so it's from reading the code.
  • Could pselect return -1/EINTR when sigmask unblocks a signal that is already pending? sigpending before the swap gives that set: let the swap deliver it, restore the mask and skip the wait. That would cover the idiom above.
  • The debt line could then say that a signal raised during the wait never interrupts it, because select has no EINTR path. It could also say that the mask swapped here is the process-wide one, so it applies to every thread for the duration of the wait.

Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine.

@oneandonlydean oneandonlydean self-assigned this Oct 22, 2026
@oneandonlydean
oneandonlydean merged commit d8b73e3 into boykopovar:main Oct 23, 2026
12 checks passed
danielradosa added a commit to danielradosa/AnyPS5 that referenced this pull request Oct 24, 2026
…elect

Moved our pselect (same select/sigprocmask approach, but it throws when restoring the mask fails where the PR ignores it) from libkernel_sys/Export.cpp into the PR's libkernel/Socket/src/Pselect.cpp so libkernel exports it, with our debt line in place of the PR's; dropped the PR's test (GuestKernelSys CheckTimeAndSelect covers pselect).
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.

4 participants