▶  Watch

io_uring: How One System Call Does the Work of Thousands

A server handling 100,000 connections is often slow not because the network is slow, but because of system calls — every read or write crosses the wall between user space and the kernel. io_uring shares two ring buffers with the kernel so a whole batch of requests can be submitted and completed with barely any crossings at all.

Systems Networking Concurrency
What this teaches

Every read() or write() is a system call — a costly mode switch crossing the wall between your program's user space and the kernel. Even epoll only tells you when a socket is ready; you still have to make a separate syscall to actually read it, and at scale those crossings become the bottleneck. io_uring shares two ring buffers with the kernel in memory: a submission queue you drop requests onto, and a completion queue the kernel drops finished results onto. You batch many requests onto the submission queue, one call (or, in polled mode, none) picks up the whole batch, and the kernel does the I/O asynchronously and posts results to the completion queue — which you read from memory, no syscall required. Batching plus async plus shared memory turns hundreds of operations into a handful of wall-crossings.

Transcript

Picture a waiter who walks all the way to the kitchen and back for every single plate. Now imagine a hundred thousand plates. That walk is what a busy server does for every read and write — a trip into the kernel called a system call. What if it almost never had to make it?

Your program lives in user space; only the kernel can touch the disk or network. Crossing that wall is a system call, costing the CPU a mode switch every time. Even epoll only tells you WHEN a socket is ready. You still make a syscall to read it. At huge scale, those crossings themselves become the bottleneck.

io_uring's idea is to stop crossing the wall per operation. It sets up two ring buffers in memory that your app AND the kernel can both see. One is the submission queue — a rail you drop requests onto. The other is the completion queue — a rail the kernel drops results onto. Shared memory, no copy.

So instead of one syscall per read, you write a whole batch of requests onto the submission rail: read this socket, write that one, accept a connection. Then a single io_uring_enter tells the kernel to pick up the batch — and in polled mode, even that one call disappears. Hundreds of ops, one knock.

The kernel does the I/O asynchronously and clips each finished result onto the completion rail. You reap them by reading memory — no system call per result. The wall never moved. You just stopped knocking on it for every dish — one batch in, results out, the CPU freed from thousands of mode switches.

That's io_uring: two shared rails between you and the kernel, so I/O is batched and asynchronous instead of one costly trip per operation. So next time a server has to serve a hundred thousand people at once, remember — the trick wasn't running faster. It was stopping the walk to the kitchen for every plate.

← All videos · Vibe Engines · 2026