Repository navigation
feat(libkernel): support EVFILT_READ on the read end of a pipe - #5973
Conversation
23f5297 to
682e213
Compare
682e213 to
45bf549
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q9h7doEdokbmaQm6eLBFit
|
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.
|
kevent threw for any descriptor that is not a guest socket. The read end of a pipe now gets the descriptor knote, following FreeBSD 11's filt_piperead: data is the number of buffered bytes and EV_EOF is set once the write end is closed. GuestSockets::Ready falls back to the new PipeReadState for a descriptor that is not a socket, and WaitAny waits on the pipe with ppoll on Linux or in 1 ms WSAPoll slices on Windows, only when the queue holds a pipe. On Windows the equeue waker now starts Winsock itself, since a queue can wait on a pipe before any socket exists.
45bf549 to
46d4913
Compare
karimibrahim07
left a comment
There was a problem hiding this comment.
Windows check of head 46d49131e, merged onto main 5d9dcc42d (clean merge). Windows 11 Pro (26300), Ryzen 5 3600, RTX 3060, WinLibs GCC 15.2.0 r7, Ninja Release.
Title: Java 25 Networking (PPSA99868, 01.000.003, SHA-256 9765536f…bc2, matching the release's SHA256SUMS), relinked with --windows --to-intel --trap-sdk-syscall-stubs --registry. On main the third row stopped right after STAGE: Network: NIO channels and selector with kevent: EVFILT_READ on a non-socket descriptor not implemented. With this PR, all four rows pass:
STAGE: Network: security configuration
STAGE: Network: numeric IPv4 loopback
STAGE: Network: TCP client/server echo
STAGE: Network: UDP two-way datagrams
STAGE: Network: NIO channels and selector
STAGE: Network25 returned normally
STAGE: DestroyJavaVM complete
Tests: guest_kqueue, guest_poll, guest_select*, guest_equeue*, guest_socket*, guest_tcp, guest_udp, guest_sce_net*: 29 of 29 pass.
Code: I checked the Windows wait path for the case where an equeue waits only on pipes. entries can then hold no socket, but the thread's waker socket is always appended, so WSAPoll never gets an empty array, and the 1 ms slices only apply while a pipe interest is present. PipeReadState tells the read end from the write end by FILE_READ_DATA on Windows and O_ACCMODE on Linux, which matches the new throwing cases in Errors(). I found no issue.
AI-assisted: yes. I ran the build, the tests and the title above.
|
Windows run of head
Titles: PPSA99868 is not available here. In the relinked titles I have, Notes on the diff, none blocking:
Not checked: Linux, PPSA99868. Written with Claude Code assistance (validation by a subagent, reviewed in this session). |
…vent PipeReadiness and PipeReadState both opened the pipe handle and asked NtQueryInformationFile for its access mask and local information. Both now go through QueryPipe, which keeps each caller's error prefix.
|
Thanks for the run.
Done in 647b5a1: both go through
Right. Today that only happens for pipes:
Yes, same as |
|
Checked on Linux (build + |
|
Re-checked against current |
What
keventthrewkevent: EVFILT_READ on a non-socket descriptorfor anything that isn't a guest socket. Java 25 Networking (PPSA99868) stops there onmain, in itsNIO channels and selectorstage: the JDK's kqueue selector opens a pipe and registers its read end withEVFILT_READ/EV_ADDto wake itself up (KQueueSelectorImpl.java L84-L95).EVFILT_READnow works on the read end of a pipe, following FreeBSD 11'sfilt_piperead:datais the number of buffered bytes (L1794),EV_EOFis set once the write end is closed (L1798-L1803), and the event is active while either holds (L1804). It uses the same host checks #3644 added forpoll:GuestSockets::PipeReadState(new, next toReady) reads the buffered byte count and whether the write end is gone:NtQueryInformationFileon Windows, the queryPipeReadinessmakes;FIONREADandPOLLHUPon Linux.PipeReadinessand feat(libkernel): select on pipes on Windows #5013'sPipeReadyonly report poll bits, so they don't givedata; both are untouched.GuestSockets::Ready, which the descriptor knote polls, falls back to it for a descriptor that isn't a socket.GuestSockets::WaitAnyputs the pipe in the hostppollon Linux, with a read mask: its only caller, the equeue wait, gets non-socket interests only from these knotes. Windows can't wait on a pipe, so there an infinite or longerWSAPollis cut to 1 ms, only when the queue has a non-socket interest.WSAStartupitself, assocketandsocketpairalready do. A kqueue can now wait on a pipe before the process has opened any socket, and the waker's loopback socket failed then withequeue waker: loopback socket setup failed, guest errno 5.Still throwing:
EVFILT_WRITEon a pipe,EVFILT_READon the write end (FreeBSD opens both ends for reading and writing,kern_pipeL422; host pipes are one-way), andEV_CLEARandNOTE_LOWATon a pipe. A newkevent on a pipeentry in the debt doc lists them, along with the 1 ms slices.pr_overlap flags #5847 (
EV_DISABLE,EV_DISPATCH,EV_FORCEONESHOT) and #5493 on the kqueue entry ofdocs/dev/debt/libkernel.md. This PR only changes two phrases on that line, the pointer to the new entry andEV_CLEARon a pipe, so whichever goes second keeps both.Kqueue.cppandGuestKqueue.cppmerge cleanly with #5847.Tested
Windows 11 Pro (26300), WinLibs GCC 15.2.0 r7, Ninja Release, on
mainf3b5daaf8:guest_kqueuepasses 5/5. The new case registers the read end and checks that it's quiet. Then 3 bytes givedata == 3and noEV_EOF, and akeventwith a 5 s timeout returns the event after a write from another thread at 50 ms. Closing the write end givesEV_EOFwith the 1 byte still buffered, anddata == 0once it's read.maine34c47921, with the source changes reverted and the test kept, it aborts withkevent: EVFILT_READ on a non-socket descriptor not implemented. With only the 1 ms cut removed, thatkeventcomes back at the 5 s timeout instead and the test fails after 5.35 s, so it can't hang CI. Without the waker'sWSAStartup, it aborts withequeue waker: loopback socket setup failed, guest errno 5, since the pipe case runs before any socket is opened.guest_poll,guest_select,guest_equeue_events,guest_socket_*,guest_tcp,guest_udp,guest_sce_net, ...) pass, 31/31. The full suite passed one34c47921, 1198/1198.Linux, Ubuntu 26.04 under WSL 2, GCC 15.2.0, CMake 4.2.3, Ninja Release,
BUILD_TESTING=ON, on the same commit, from an archive of this branch with its submodules.FFMPEG_PREBUILT_DIRpoints at the headers of the local Windows FFmpeg package instead of downloading the Linux one, and none of the built targets link FFmpeg. I built the targets of the tests below and ran them, not the whole suite:guest_kqueuepasses 5/5. WithKqueue.cpp,Udp.cppandSocketRuntime.hppfrommain, it aborts with the samekevent: EVFILT_READ on a non-socket descriptor not implemented.guest_dup,guest_equeue_events,guest_kernel_fcntl,guest_poll,guest_rudp_*,guest_sce_net,guest_select,guest_select_wait,guest_socket_*,guest_tcp,guest_udpandguest_kqueuepass, 19/19.Java 25 Networking (PPSA99868, 01.000.003, SHA-256
9765536f274f3b3e35922b29564ac67afc7cfe979df5d8f3cf5f2a3b3649ebc2, matching the release'sSHA256SUMS), relinked with--trap-sdk-syscall-stubs, onmaine34c47921:main, the third row stops right afterSTAGE: Network: NIO channels and selectorwithwhat(): kevent: EVFILT_READ on a non-socket descriptor not implemented.STAGE: Network25 returned normally, thenSTAGE: DestroyJavaVM complete, as on the console.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)