2026-09-02
You already know io_uring lets one thread submit and reap I/O without syscalls. But what happens when you have multiple io_uring instances — say one per worker thread in a sharded server — and a submitter on ring A needs to hand work to a consumer on ring B? Historically the answer was ugly: write to an eventfd registered with ring B, which costs a syscall on the write side and a wakeup on the read side. IORING_OP_MSG_RING (added in kernel 5.18) collapses that into a single SQE.
The mechanics: you submit an SQE on ring A with opcode IORING_OP_MSG_RING, the fd field set to the file descriptor of ring B, and two 64-bit user-supplied values (len and off). The kernel synthesizes a CQE directly onto ring B's completion queue carrying those values, and wakes any thread blocked in io_uring_enter on B. No socket, no pipe, no write(), no extra file descriptor. Since kernel 6.0 you can also pass IORING_MSG_RING_FLAGS_PASS to set the CQE's flags field, letting you encode a 32-bit tag alongside the payload.
Real-world example: ScyllaDB's Seastar-style shard-per-core architecture. Each core owns a ring and a set of partitions. When a request lands on core 3 but needs data on core 7, core 3 previously round-tripped through a lock-free MPMC queue plus an eventfd write to poke core 7 awake — ~800 ns of overhead per cross-shard message. With IORING_OP_MSG_RING, core 3 batches the cross-shard sends into its next SQE flush; core 7 sees them as regular CQEs interleaved with its I/O completions. Measured cost drops to ~150 ns and, critically, the wakeup piggybacks on the same io_uring_enter that core 7 was already going to make.
Rule of thumb: if you're using an eventfd purely to signal "check your queue," and the reader is already polling an io_uring, replace it with IORING_OP_MSG_RING. You save one syscall on the sender and one file descriptor per pair — roughly 600 ns and 64 bytes of kernel memory per notification path.
Two subtleties. First, the target ring's CQ must have space; otherwise the operation completes with -EOVERFLOW and the message is dropped (io_uring's overflow list can catch it if IORING_SETUP_CQSIZE is generous). Second, if ring B was created with IORING_SETUP_SINGLE_ISSUER, only the owning thread may submit — but MSG_RING is explicitly exempt, since it's the whole point.
IORING_OP_MSG_RING turns cross-ring notification into a zero-syscall SQE that delivers a CQE directly onto another ring's completion queue — replacing the eventfd+write pattern with something roughly 5× cheaper.