Severity: medium — not a correctness hole (the !more re-arm handles multishot termination), but a silent performance cliff under burst.
Problem
Ring.Create sets no IORING_SETUP_CQSIZE, so the CQ defaults to 2× SQ entries — 16384 CQEs at the default RingEntries = 8192:
With multishot accept + multishot recv, CQE production is decoupled from SQE submission — a reactor holding tens of thousands of connections can complete more than 16384 events between two io_uring_enter calls. On CQ overflow the kernel falls back to the allocated overflow-list slow path, and multishot ops can terminate (extra re-arm churn), exactly when the server is busiest.
Suggested fix
- Set
IORING_SETUP_CQSIZE (1u << 3) and pass cq_entries in IoUringParams; default to 4–8× SQ entries and expose it in ServerConfig.
- The mapped
cq_off.overflow counter already exists in CqRingOffsets — surface it in the per-reactor stats (observability issue) so overflow is visible instead of silent.
Severity: medium — not a correctness hole (the
!morere-arm handles multishot termination), but a silent performance cliff under burst.Problem
Ring.Createsets noIORING_SETUP_CQSIZE, so the CQ defaults to 2× SQ entries — 16384 CQEs at the defaultRingEntries = 8192:With multishot accept + multishot recv, CQE production is decoupled from SQE submission — a reactor holding tens of thousands of connections can complete more than 16384 events between two
io_uring_entercalls. On CQ overflow the kernel falls back to the allocated overflow-list slow path, and multishot ops can terminate (extra re-arm churn), exactly when the server is busiest.Suggested fix
IORING_SETUP_CQSIZE(1u << 3) and passcq_entriesinIoUringParams; default to 4–8× SQ entries and expose it inServerConfig.cq_off.overflowcounter already exists inCqRingOffsets— surface it in the per-reactor stats (observability issue) so overflow is visible instead of silent.