Repository navigation
fix(libkernel): return EINTR from pselect when its mask unblocks a pending signal - #10501
oneandonlydean merged 3 commits into
Conversation
…nding signal FreeBSD's kern_pselect installs the mask and kern_select sleeps with PCATCH, so a pending signal that the new mask unblocks makes the call return EINTR once the descriptors have been scanned. Here the handler ran inside the mask swap and select then waited the full timeout, or forever with no timeout. The swap now reports whether a handler ran, and pselect then scans the descriptors once without waiting: a ready descriptor, a zero timeout or an invalid argument keep select's answer, and otherwise the call fails with EINTR and leaves the descriptor sets unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
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.
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.
|
MarcZX10
left a comment
There was a problem hiding this comment.
The pselect change is narrowly scoped and the negative control plus ready-descriptor, timeout, mask-restore, and signal-blocking cases are useful. The author reports the related Windows tests passing on an earlier base with an identical patch-id; current hosted PR build jobs are skipped, and I did not rerun the test suite locally.
Please resolve two merge-order declarations before approval. The body explicitly says #9499 remains open, changes the same Signals.cpp helper, and that #9499 should land first; however the checklist says Depends on: none. The body also says open #10310 changes the pselect debt text and needs a text merge, but no order is declared for that overlap. Please coordinate with those authors and list the agreed order(s) in the checklist, following CONTRIBUTING. The current head is mergeable with main, so I found no separate rebase blocker or code defect in this pass.
|
@MarcZX10 Thanks. I've updated the checklist with the order. @EagleBearerYS, @orezraey, could you confirm it works for you?
Reviewed with AI assistance (Claude Code). |
|
@harisibrar1 that works for us: #9499 first, then #10501 on its |
|
Linux run (Ubuntu 26.04 container, GCC 15, glibc 2.43, CMake + Ninja, Release,
This covers the Linux part of "Not tested: Linux and macOS". |
|
Thanks, the #9499 author has now confirmed the proposed order, and the Linux follow-up supplies the missing platform run. The remaining coordination item is #10310: the checklist says its debt-text overlap can land in either order, but I do not see confirmation from its author yet. Please record that agreement before merge; the prior review request remains open until then. |
|
@harisibrar1 Either order works for #10310. It only rewrites the |
MarcZX10
left a comment
There was a problem hiding this comment.
Reviewed current head c7cd45c. The previously missing merge-order agreements are now explicit: #9499 confirmed it lands first, and #10310 confirmed either order for the adjacent debt text; the checklist records both. The implementation and regression coverage are unchanged from my prior review. The author reports the Windows focused signal suite and the Linux follow-up reports seven related tests passing three consecutive runs, including a negative control where main fails the new EINTR case. I did not reproduce those runs locally. Hosted structural checks pass; product build jobs are skipped by eligibility. No remaining blocker found.
|
Merged main e7e3e9c into the branch (head b8b4214) to resolve the conflict from the libkernel header refactor (#10706):
The behaviour is unchanged. Rerun on Windows 11, WinLibs GCC 15.2.0 r7, full Release build: no failed steps. Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine. |
|
@harisibrar1 Thanks for this. One change before it can go in: the new |
…ignal-eintr # Conflicts: # core/libs/prx/libkernel/System/src/Signals.cpp
|
@oneandonlydean done in
Windows 11, GCC 15.2.0: full build clean, and the 11 signal/pselect/select tests pass in 3 runs. With main's Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine. |
|
Overlap note: #11273 (@Gruzzberry, EFAULT for unusable signal pointers) also adds a trailing optional parameter to Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine. |
What
pselect(merged in #9273) never returnedEINTR. With the canonical pattern of blocking a signal, raising it and waiting with a mask that unblocks it:FreeBSD 11.4 runs the handler and returns -1/
EINTRat once. Here the handler ran inside the mask swap (_sigprocmaskdelivers a pending signal thatSIG_SETMASKunblocks), andselectthen waited the full 300 ms and returned 0. With a NULL timeout it never returned. This was raised in the review of #9273.In FreeBSD's
kern_pselectthe mask is installed andkern_selectsleeps withPCATCH. Before it sleeps,kern_selectchecksnd, the descriptors and the timeout, then scans once: a ready descriptor wins, a zero timeout returns 0, and only then does a pending signal end the sleep withEINTR(sys/kern/sys_generic.c, release/11.4.0). OnEINTRthe descriptor sets are not copied out.The change:
Signals.cpp: main'sChangeBlockedMask(from fix(libkernel): block a signal while its handler runs and honour SA_RESETHAND #9499) gains an optionalbool* caught, andDeliverUnblockedPendingreturns whether a guest handler ran.SetSignalMaskCatching_nid_no_patchuses it withSIG_SETMASK, releasing holds like thesigprocmaskcall it replaces._sigprocmaskitself behaves as before.SetSignalMaskCatching_nid_no_patchis declared once, inprx/libkernel/include/Api.hpp, which bothSignals.cppandPselect.cppinclude.Pselect.cpp: when the swap ran a handler,pselectscans the descriptors once with a zero timeout instead of waiting. A ready descriptor, a zero timeout or an invalid argument (nfds, timeout) keepselect's answer. Otherwise the call returns -1/EINTRand leaves the descriptor sets as they were.pselectdebt entry is rewritten. The old text described a narrow race; the remaining gap is that a signal raised during the wait (another thread'spthread_kill, orraisefrom a handler) still doesn't interrupt it, becauseselecthas noEINTRpath. It also notes that the mask is the process-wide one.Tested
Windows 11, WinLibs GCC 15.2.0 r7 (UCRT), Release. Full build of 7784604 (current
main47f9cee merged in): 0 failed steps.guest_kernel_sys_pselectpasses 3 out of 3 on 7784604. The new cases cover: the pending-signal idiom returnsEINTRin under 150 ms with the handler run once, the descriptor set unchanged and the mask restored; a NULL timeout returnsEINTRinstead of blocking; a ready descriptor still wins (returns 1); a zero timeout still returns 0; an invalid timeout still returnsEINVAL; and a mask that keeps the signal blocked still waits the full timeout, with the handler running only when the signal is later unblocked.Pselect.cppandSignals.cpp, the test fails at the firstEINTRcheck (line 129).guest_kernel_sys,guest_signals,guest_sigtimedwait,guest_getitimer,guest_itimerandguest_itimer_pending_default.tools/check_conventions.py --base origin/mainpasses.Overlap
ChangeBlockedMaskinstead of keeping a second helper.docs/dev/debt/libkernel.mdnear theselectentries; a rebase there is a text merge only.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)ChangeBlockedMask); docs(libkernel): record select limits as measured on a PS5 #10310 in either order, as a text merge indocs/dev/debt/libkernel.md(asked both authors to confirm below)🤖 Generated with Claude Code