Repository navigation
Fix a macOS call to a full cell reporting unavailable instead of capacity - #111
Merged
Merged
Conversation
On macOS, a call to a full cell occasionally reported `unavailable` instead of `capacity`. A full cell answers and closes without reading the request, so the client's send fails. macOS sometimes reported that failure as `ENOTCONN`, but `deliver` ignored only `EPIPE` and `ECONNRESET`. Ignore `ENOTCONN` too. The comment on `deliver` names the kernel race, and the comment on `call` says how a full backlog on Linux still reaches `unavailable`. [Fix #110]
flavorjones
force-pushed
the
card-658-macos-sendmsg-enotconn
branch
from
October 10, 2026 17:06
3990ec8 to
cb8df4a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
A full cell writes
capacityand closes the connection without reading the request (Supervisor#refuse). The client's send then fails. Since #67,Transport::Socket#deliverignores that failure when it isErrno::EPIPEorErrno::ECONNRESET, soreceivereads thecapacityanswer.On macOS the send sometimes fails with
Errno::ENOTCONNinstead.deliverdoesn't rescue it, so the call reportsunavailable.test_an_answer_that_arrives_before_the_request_is_sent_is_still_the_verdictfailed on the macOS job for this reason (run):The XNU kernel's
sosendchecks the socket under its lock. It then drops the lock to copy the request in, and callsuipc_sendwithout checking again. If the cell's close lands in that window,uipc_sendtestsSS_ISCONNECTEDbeforeSS_CANTSENDMOREand returnsENOTCONNinstead ofEPIPE. In a probe on a macOS runner (run),sendmsgraisedENOTCONNin 5 of 5,000 tries, and the answer was readable after every one. On Linux it never did.Clients on Linux are not affected.
Details
deliveralso rescuesErrno::ENOTCONN.On Linux,
ENOTCONNfrom the send means the socket never connected because the cell's backlog was full (see the comment oncall). That call still reportsunavailableat once, because the read that follows fails withErrno::EINVAL. Its detail changes fromErrno::ENOTCONN: Transport endpoint is not connected - sendmsg(2)toErrno::EINVAL: Invalid argument.ControlTimeoutTestcovers that path.The new test stubs
Connection#send_messageto raiseErrno::ENOTCONNonce the cell's answer is on the socket. Before this change it failed with the same message as the macOS job.Fixes #110