Repository navigation
Conversation
…acOS hosts Two stream send behaviours of XNU differ from FreeBSD and Linux: - MSG_DONTWAIT does not keep a stream send on a blocking socket from waiting for buffer space; XNU only skips the wait for the send buffer lock. A 16 MiB send to a slow peer blocked until the peer went away. A MSG_DONTWAIT transfer now also passes XNU's MSG_NBIO (0x20000), which makes one call non-blocking: the send queues what fits and returns that count, or EAGAIN when nothing fits. - A blocking stream send that fails after queuing data, for example when sceNetSocketAbort shuts the socket down, returns only the error, where Linux returns the bytes queued. A blocking stream send now goes to the host in sends of 64 KiB and reports the bytes of the sends that completed when a later one fails, as boykopovar#8658 does. The debt entry records the undocumented flag and the bytes that a failing 64 KiB send queued but does not report. Co-authored-by: iamthehimansh <67262056+iamthehimansh@users.noreply.github.com>
jotitadev
left a comment
There was a problem hiding this comment.
Second Mac, newer macOS. Head 6b47a3636.
Machine: Apple M2 Max, macOS 27.2 (26B5112a), Apple clang 21. The libraries do not link on main alone, so the base is #8658 @ fbb251c25 (merge-base 4777caca3, the same as this PR). I replaced #8658's own macOS send code (its SO_NWRITE room check and chunked send) with this PR's: MSG_NBIO in native_message_flags, and the 64 KiB loop without the EINTR retry that #8658 has. x86-64 build under Rosetta 2.
- Without either fix, 7 of the 11
net_dontwaittests fail with the messages in the description ("MSG_DONTWAIT send blocked behind a slow peer…", "error discarded queued bytes"). With this PR, all 11 pass, 10 runs of 10 (ctest --repeat until-fail:10). 0x20000still works on macOS 27.2. A standalone probe gives the same results built for arm64 and for x86-64 under Rosetta. The setup is loopback TCP, 4 KiBSO_SNDBUF/SO_RCVBUF, a 16 MiB send, and a peer that closes after 2 s:sendwithMSG_DONTWAIT: blocks 2005 ms, then fails withEPIPE.sendwithMSG_DONTWAIT | 0x20000: returns 65328 at once.sendmsgwith the same flags also returns 65328, and returnsEAGAINon the next call with the buffer full.- The flag passes on the other paths this PR sends it to: UDP
sendtoandrecvaccept it withoutEINVAL, and an empty TCP or UDP receive returnsEAGAINat once, as withMSG_DONTWAITalone. - A blocking 16 MiB send, where another thread calls
shutdown(SHUT_RDWRorSHUT_WR) on the socket after 300 ms: one host send returns -1EPIPE. Sends of 64 KiB report 131072 bytes queued before theEPIPE.
Export.cppfrom the PR head compiles with-fsyntax-onlyfor arm64 and x86-64.- Not run: the guest socket tests (
guest_tcp,guest_udp, ...), Linux, Windows.
Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.
|
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 two reported macOS runs (M5 Max and the independent M2 Max rerun) are useful evidence, and I found no issue with the short-send behavior in the exercised cases.
I reviewed head 6b47a36368eeb1a0e97d3bcdc4d0d42d7cbc0eea. Local checks:
- Exact-head
Export.cpppassedg++ -std=c++20 -fsyntax-onlyon the Linux path; this does not compile the__APPLE__branch. - A temporary harness extracted the exact helper and passed full chunking, progress followed by an error, and zero-length cases. It does not exercise Darwin socket semantics or detect all undefined behavior.
git diff --checkandpython3 tools/check_conventions.py --base upstream/main --head refs/review/pr9733passed.- I could not run the Darwin socket suite in this Linux environment.
Before merge, please refresh the PR from current main (its base is 4777caca, 54 commits behind b7d1d47a) and rerun the focused macOS comparison on the refreshed head. The current open #8658 also changes the same Export.cpp send paths and contains a 64 KiB chunk helper. CONTRIBUTING requires agreement with the overlapping PR author on landing order and recording the dependency; this PR currently says Depends on: none. Please coordinate with #8658’s author and update the checklist to reflect the agreed order.
One edge case in the helper: the public functions permit buf == nullptr when len == 0, but the blocking-stream do loop still evaluates data + transferred (nullptr + 0) before calling the host send. Please bypass the pointer addition for zero length (while preserving the zero-length send) and add coverage. This is a C++ undefined-behavior concern; the temporary runtime harness passed but cannot rule it out.
|
Second data point on a different macOS version: M5 Pro, macOS 27.2 (26B5086k), Apple clang 21, x86-64 under Rosetta 2, Release. My tree is
So AI-assisted: yes |
What
The seven
net_dontwaitsend tests, new onmainthis week, fail on macOS. Two stream send behaviours of XNU differ from FreeBSD and Linux. Part of the macOS series announced on #1 (#1 (comment)).MSG_DONTWAIT. On a blocking socket, XNU'sMSG_DONTWAITonly skips the wait for the send buffer's lock; a stream send still waits for buffer space. A 16 MiB send to a slow peer blocks until the peer goes away, andnet_dontwait_send,_sendto,_sendmsgand_duplexfail with "MSG_DONTWAIT send blocked behind a slow peer". AMSG_DONTWAITtransfer now also passes XNU'sMSG_NBIO(0x20000), which makes that one call non-blocking: the send queues what fits and returns that count, orEAGAINwhen nothing fits. The flag is not in the SDK headers, so the debt entry records it.sceNetSocketAbortshuts down a socket during a blocking stream send that has queued data, XNU returns only the error, where Linux returns the bytes it queued.net_dontwait_blocking_send,_sendtoand_sendmsgfail with "error discarded queued bytes". A blocking stream send now goes to the host in sends of 64 KiB, and when one fails after others completed, the result is the bytes of those. This is the way feat: macOS host support (Apple Silicon via Rosetta 2, Vulkan on MoltenVK) #8658 does it, credited to @iamthehimansh in the commit; the bytes the failing 64 KiB send queued are not counted, as the debt entry says.Every change is in an
__APPLE__branch.MSG_NBIOis added where the guest flags become host flags, so it reaches receives too, which XNU'sMSG_DONTWAITalready keeps from waiting. The 64 KiB sends are insceNetSendandsceNetSendto, whichsceNetSendmsggoes through; datagram sends, guest non-blocking sockets andMSG_DONTWAITsends take one host call as before.Tested
macOS 26.5.1, Apple M5 Max, Apple clang 21, x86-64 build under Rosetta 2. The libraries do not link on macOS without the rest of the macOS series, so the run is on
main7e2ba73 with the series (ci/macos-series-2on my fork) and the libSceSsl change of #7332;mainhas not changed these files since.sendwithMSG_DONTWAITon a blocking loopback socket with 4 KiB buffers blocks until the peer shuts down 2 s later and then fails withEPIPE. WithMSG_DONTWAIT | 0x20000, or on anO_NONBLOCKsocket, it returns 65,328 at once.net_dontwaittests pass, 10 runs of 10.guest_tcp,guest_udp,guest_kqueue,guest_socket_*, the othernet_*tests) give the same results with and without it.guest_sce_net,guest_pollandguest_socket_pairfail either way; fix(libSceNet): match FreeBSD's inet_pton and socket errors on macOS #9231, @011010's announcedguest_pollchange and fix(libkernel): treat a socket direction that is already shut as shut on macOS hosts #9625 cover them.__APPLE__branch.Checklist
main; no other open PR implements the same functions (feat: macOS host support (Apple Silicon via Rosetta 2, Vulkan on MoltenVK) #8658 carries a version inside its full port)NotImplemented_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)