Swap back to a blocking udp socket, test shutdown(2) - #1806
Merged
Conversation
JackDoan
reviewed
Jul 17, 2026
JackDoan
previously approved these changes
Jul 17, 2026
Co-authored-by: Jack Doan <me@jackdoan.com>
JackDoan
approved these changes
Jul 17, 2026
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.
Before #1654 the Linux UDP reader used a raw blocking socket with a direct recvmmsg loop. #1654 switched to a
net.UDPConn+syscall.RawConnnetpoller path to get a clean shutdown. On many-core hosts, netpoller constantly parks and wakes the reader goroutines, and the resulting scheduler churn (findRunnable/lock2/futex) roughly halves UDP throughput. A 16-routine test on a 64 vCPU host fell from ~28.5 Gbps to ~13 Gbps, scaling routines beyond 8 made each perf test progressively worse.This restores the blocking read, which parks the worker thread in the kernel and brings throughput back to ~28.5 Gbps with the churn gone entirely.
Close()sets a closed flag and callsshutdown(2), and the read helpers translate the resulting wake intonet.ErrClosed, matching the darwin/generic/windows paths.The subtlety that sank an earlier blocking-plus-shutdown attempt (#1591, part of the now-closed #1375) is that once a socket has received a packet,
shutdown(2)wakesrecvmmsgwith n>=1/Len==0 rather than n==0, so keying teardown off the message count spins forever; keying it off the closed flag handles every wake shape.Also added some tests to make sure we correctly shutdown on linux in all situations.
I left
runtime.LockOSThread()out because it increased scheduler pressure and made per packet cpu utilization go up in my testing.