Skip to content

fix(libkernel): clear select bits from nfds to the end of their word - #10777

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
harisibrar1:fix/select-clear-bits-past-nfds
Oct 25, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
harisibrar1:fix/select-clear-bits-past-nfds

Conversation

@harisibrar1

Copy link
Copy Markdown
Contributor

What

select leaves set bits in place from nfds up to the end of their 64-bit word, where the console clears them.

@orezraey measured this on a PS5 (firmware 13.60, payload process, pselect.log from #10310):

  • nfds_below_fd: nfds 16 with descriptor 16 set and a zero timeout returns 0 with the bit cleared (bit=0).
  • nfds_0_ready: nfds 0 leaves the bit set (bit=1).

FreeBSD 11.4's kern_select explains both cases (sys_generic.c). It sizes the sets as ncpubytes = roundup(nd, NFDBITS) / NBBY and, on success, copies ncpubytes of its output sets back to each non-null set (putbits, L1156-L1164). Those output sets hold only the ready bits. So every bit from nfds to the end of its 64-bit word comes back as 0, words past it are not touched, and with nfds 0 nothing is copied. On an error (EINTR, EBADF, EINVAL) nothing is copied either.

On main, select_nid_postfix (Socket.cpp) clears only the descriptors it asked about, all of them below nfds, on both the ready and the timeout return. This adds ClearDescriptorsFrom, which clears the bits from nfds to the end of that word in each non-null set, and calls it on those two returns. Error returns still leave the sets alone. It does nothing when nfds is a multiple of 64, 0 included.

Two existing tests pinned the old behaviour, and neither cites a measurement:

  • GuestSelect.cpp required the bit at nfds to survive a timeout (the select_nid_postfix(reader, …) case). That is the measured nfds_below_fd case, so it now requires the bit to be cleared, along with bit 63, while bit 64 in the next word is kept. New cases cover nfds 0 (bit kept, as measured) and the ready path (bits past nfds cleared, the ready bit kept).
  • GuestSelectWait.cpp required bit 63 to survive select with nfds 1. It is in the same word, so it is now cleared, and a bit in the next word is required to survive.

Tested

Windows 11, WinLibs GCC 15.2.0 r7, full Release build on main f26434a with this change: no failed steps.

  • guest_select, guest_select_wait, guest_kernel_sys_pselect, guest_socket_descriptors, guest_sce_net and guest_kernel_sys pass, 3 runs of 6/6.
  • Negative control: with main's Socket.cpp and these tests, guest_select and guest_select_wait both fail (2 runs).
  • tools/check_conventions.py --base origin/main passes.
  • Not tested: Linux and macOS. The change is host-independent bit arithmetic on the guest's sets.

Overlap

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 (debt-line order with docs(libkernel): record select limits as measured on a PS5 #10310 above)
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

🤖 Generated with Claude Code

…as FreeBSD copies them out

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

The PS5 measurements and FreeBSD comparison support clearing only through the end of the final 64-bit word selected by nfds. The implementation applies this on readiness and timeout returns, preserves words beyond that boundary, and leaves error returns untouched. Tests cover nfds == 0, timeout, readiness, an excluded descriptor within the final word, and preservation of the next word. Local git diff --check and the conventions checker pass; hosted test/build jobs are skipped by the current path policy, so I could not confirm a hosted native run.

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

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 10456 core/libs/prx/libkernel/Socket/src/Socket.cpp
core/libs/tests/GuestSelect.cpp

@oneandonlydean oneandonlydean self-assigned this Oct 25, 2026
@oneandonlydean
oneandonlydean merged commit b5f669f into boykopovar:main Oct 25, 2026
11 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