A QUIC server's hot loop is dominated by per-datagram syscalls: one
recvfrom per inbound packet, one sendto per outbound packet.
Under a burst that is N syscalls for N datagrams. Linux's
recvmmsg(2) / sendmmsg(2) move a whole vector of datagrams
across the user/kernel boundary in a single call, and UDP generic
segmentation offload (GSO, UDP_SEGMENT) lets one sendmsg hand
the kernel a big buffer that it slices into many equal-sized wire
datagrams. Together these cut the syscall count on a saturated path by
~Nx.
These syscalls are Linux-only and version-gated (recvmmsg 2.6.33,
sendmmsg 3.0, UDP_SEGMENT 4.18). This module is the capability
probe + safe wrapper:
- :func:
udp_batch_supported -- compile-time Linux gate. On any other
target the helpers are never reached; callers use the per-datagram
path.
- :class:
UdpBatchUnsupported -- raised when a running kernel lacks
the syscall (ENOSYS). Callers catch it once and latch back to the
per-datagram path for the rest of the process lifetime.
- :class:
BatchReceiver -- owns the struct mmsghdr[] + iovec[]
- name + data arrays and drains a burst with one
recvmmsg.
- :func:
send_batch -- one sendmmsg for a vector of
(payload, destination) pairs.
- :func:
send_segmented -- one GSO sendmsg that slices data
into seg_size wire datagrams to a single destination.
Struct layout (x86_64 / aarch64 Linux, the only targets these calls
run on):
struct iovec { void *base; size_t len; } // 16 B
struct msghdr { void *name; socklen_t namelen; (pad) // 0, 8
struct iovec *iov; size_t iovlen; // 16, 24
void *control; size_t controllen; // 32, 40
int flags; (pad) } // 48 -> 56 B
struct mmsghdr { struct msghdr hdr; unsigned len; (pad)} // 56 -> 64 B
The arrays are modeled as flat Pointer[UInt8] regions with
the fields poked at fixed offsets, mirroring
flare.runtime.iovec.IoVecBuf.
The name slots are sized for IPv4 + IPv6 (28 B), but the wire structs
are pinned to the 64-bit Linux ABI -- the only ABI where these
syscalls exist in this codebase. A 32-bit Linux port would need
different offsets, branching the comptime offsets on pointer width.