Repository navigation
fix(libkernel): report POLLHUP on macOS only once both directions of a stream have ended - #11858
Conversation
…a stream have ended XNU's poll reports POLLHUP as soon as either direction of a stream socket has ended, adds POLLPRI and POLLRDBAND to it and then drops POLLOUT. FreeBSD's sopoll_generic reports POLLHUP only once the receive and the send side are both shut, and Linux does the same, so on macOS a guest saw POLLIN|POLLHUP for a stream whose peer had only shut its sending side, and POLLHUP for one that had only shut its own. When the host reports POLLHUP on a guest stream socket, ask it about each direction alone and keep POLLHUP only when both have ended, report the requested POLLOUT while the sending side is shut or writable, and leave urgent data to SIOCATMARK.
|
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.
I reviewed the macOS-only normalization against the existing Windows counterpart, the poll result collection path (including the later SIOCATMARK urgent-data check), and the new half-close assertions. The branch is based on 801d5b9bc1; I checked that current main has not changed the touched Udp.cpp, GuestPoll.cpp or debt lines since then, and the current-base diff is whitespace-clean. The reported macOS before/after runs and 97-test comparison are detailed, but I cannot independently run the macOS-specific runtime case on this Linux host. I found no additional code defect in the reviewed diff; this is a COMMENTED review rather than an approval because that platform-specific behavior remains author-reported here.
|
Same result on a second Mac: Apple M5 Pro, macOS 27.2, Apple clang 21, x86-64 Release under Rosetta 2. Tree: this PR's base,
So the only test that changes is AI-assisted: yes |
|
Checked the macOS |
What
guest_pollaborts on macOS inPollsAStreamWhosePeerClosed: after the peer'sshutdown(SHUT_WR),pollon the accepted socket returnsPOLLIN|POLLHUP(0x11) forPOLLINand forPOLLIN|POLLOUT, where the test expects 0x1 and 0x5.XNU's
pollis built on kqueue:poll_callbacksetsPOLLHUPonEV_EOFfrom either filter, so it reportsPOLLHUPas soon as either direction of a stream has ended, addsPOLLPRI|POLLRDBANDto a read-side EOF, and then dropsPOLLOUT. FreeBSD 11.4'ssopoll_genericreportsPOLLHUPonly once both the receive and the send side are shut, and Linux does the same. Measured with a plain C probe on macOS 27.2 (arm64 and x86-64 under Rosetta give the same), eventsPOLLIN/POLLOUT/POLLIN|POLLOUT:On macOS, when the host reports
POLLHUP(withoutPOLLERR) on a guest stream socket,pollnow asks the host about each direction alone (a zero-timeoutPOLLINandPOLLOUTpoll, whosePOLLHUPmeans that direction ended), keepsPOLLHUPonly when both have ended, reports the requestedPOLLOUTwhile the sending side is shut or writable, and drops thePOLLPRI|POLLRDBANDthat XNU adds to an EOF; real urgent data still comes from the existingSIOCATMARKcheck. It is the macOS counterpart of the WindowsClosedStreamEvents, which already does this fromsendShut. Linux and Windows are unchanged.The test gets two checks in
PollsAStreamWhosePeerClosed: the socket that shut its own sending side reports onlyPOLLOUTforPOLLIN|POLLOUT, and (not on Windows, wherePOLLPRIis asked asPOLLRDBAND)POLLIN|POLLPRI|POLLRDBANDon the half-closed socket reportsPOLLINonly. The macOS sockets debt entry records the remaining gap: a call that asks for no event gets nothing from XNU, where FreeBSD reportsPOLLHUP.Tested
main801d5b9 plus feat(libkernel): direct memory mappings on macOS hosts #7631, build(libkernel): compile Exception on macOS #11249, fix(libSceLibcInternal): declare environ for the spawn test on macOS #11358, build(libSceAudioIn): keep --exclude-libs off Apple's linker #10669, fix(libkernel): build the file, module and rtld calls on macOS hosts #10552, feat(libkernel): process, thread and clock queries on macOS hosts #7804, build(agc): compile Lifecycle, GuestMemory and GuestBufferMemory on macOS #11447, build(agc): keep the Linux-only parts of three AGC tests off macOS #11437 and fix(agc): load the Vulkan loader and list MoltenVK on macOS #11554.guest_pollaborts at the first peer-closed check, 3 of 3 (and at the new own-shut check with the new test).guest_pollpasses 3 of 3. Without only thePOLLPRIline, the newPOLLPRIcheck fails 3 of 3.guest_poll(guest_socket_port_zeroandguest_sce_netfail on both, covered by fix(libkernel): count a dissolved datagram association as disconnected on macOS #10544 and fix(libSceNet): match FreeBSD's inet_pton and socket errors on macOS #9231).guest_pollpasses 3 of 3.tools/check_conventions.pypasses.Overlap: #11247 and #11223 edit the same
pollcode inUdp.cpp.git merge-treemerges this branch with #11247 cleanly. #11223 and #5021 already conflict withmaininUdp.cpp; with this branch they conflict at the same hunks (shifted by the 13 added lines), none of them inClosedStreamEventsor thecollectstep this PR touches. #5021'sUdp.cpphunks are in the includes, the equeue wait,NativePair,Readyandioctl, disjoint from these.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)🤖 Generated with Claude Code