A blocking receive on Linux normally sleeps when no data is ready and resumes after the networking path makes data available. With SO_BUSY_POLL, the receive path may instead spend a bounded interval actively polling the relevant NAPI context for incoming packets. That interval exchanges CPU time for a chance to process an arrival before the ordinary interrupt-driven path wakes the task.

The option does not turn a socket into a permanently polling endpoint. It supplies a busy-poll budget in microseconds, and the mechanism depends on receive history and network-device support.

The socket carries a busy-poll time budget

SO_BUSY_POLL is configured with an integer value representing an approximate busy-poll duration in microseconds. Linux added the socket option in 3.11. The system default for socket reads is exposed through net.core.busy_read, while a per-socket setting can override that default.

int usecs = 50;

if (setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL,
               &usecs, sizeof(usecs)) == -1) {
    /* handle error */
}

The value is a polling-time budget, not a receive timeout. A receive timeout bounds how long a blocking operation may wait before reporting a timeout condition. Busy polling instead changes what the kernel may do during part of that wait: execute receive-side polling rather than immediately depend on a later interrupt and scheduler wakeup.

Linux documents the duration as approximate. Scheduling, driver behavior, NAPI state, traffic timing, and kernel implementation details prevent the value from acting as a precise latency deadline.

Busy polling reaches into NAPI packet processing

NAPI is the Linux networking mechanism that coordinates packet processing between device notifications and polling. In ordinary operation, a network device can notify the host through an interrupt, after which NAPI processing handles queued work. Busy polling provides another entry path: a user task waiting for network input can trigger polling before the device interrupt fires.

That path is conditional. The socket must have last received data from a network device that supports busy polling. The kernel uses receive-side state associated with the socket to identify the relevant polling context; setting a nonzero option on an arbitrary socket does not guarantee that useful device work is available to poll.

This boundary also separates SO_BUSY_POLL from protocol semantics. TCP ordering, retransmission, congestion control, and byte-stream behavior are unchanged. UDP datagram boundaries are unchanged. The option affects when receive-side work may be driven, not the wire protocol or application framing.

Polling can reduce a wakeup path but consumes execution time

An interrupt-driven receive path can involve device interrupt delivery, NAPI scheduling, packet processing, socket queueing, and task wakeup before an application resumes. Busy polling can process an arrival while the application is already executing in the receive path, removing some waiting and wakeup delay in favorable conditions.

The cost is deliberate CPU consumption while no packet has yet become available. Linux kernel documentation describes NAPI busy polling as a trade of CPU cycles for lower latency, and the socket manual warns that it raises CPU utilization and power usage. A longer budget therefore is not an unconditional improvement.

The useful operating point depends on arrival rate, latency targets, CPU isolation, power constraints, NIC and driver behavior, and contention with other runnable work. A latency-sensitive service on dedicated CPUs has a different cost boundary from a densely consolidated host where idle CPU time and power are significant resources.

The per-socket option directly applies to blocking receives. Linux also exposes net.core.busy_poll for busy polling performed by readiness waits such as poll() and select() when eligible sockets have SO_BUSY_POLL enabled. Current NAPI interfaces additionally support epoll-oriented busy-poll configuration.

These controls should not be collapsed into one semantic guarantee. A socket-level receive budget, a system setting for readiness polling, and newer epoll NAPI parameters affect related parts of the receive path but operate at different interfaces.

Applications using an event loop also retain normal readiness semantics. Busy polling can cause packet processing to happen during the wait, but a readiness notification still reports current I/O state rather than reserving data for a particular thread.

Device support and kernel configuration bound the effect

The kernel must be built with receive busy-poll support, and the network path must expose a usable NAPI context. The documented sysctl controls are inactive as a latency mechanism when those prerequisites are absent. Virtual networking layers, driver choices, and deployment topology can also change which NAPI context is associated with received traffic.

Privilege is another boundary. The socket manual states that increasing SO_BUSY_POLL requires CAP_NET_ADMIN. Software should therefore treat configuration failure as an operational possibility rather than assume that a requested budget was installed.

A configured value also does not prove a latency reduction. It proves only that the application requested a kernel mechanism whose effect depends on packet timing and the active network path.

The latency trade belongs at the receive scheduling boundary

SO_BUSY_POLL is most accurately treated as receive scheduling policy. It permits bounded active work at a point where the task could otherwise wait for interrupt-driven progress. That can shorten a latency path when a packet arrives inside the polling window and the device path is eligible, while spending CPU cycles whenever the task polls without finding useful work.

The mechanism is therefore narrower than a general low-latency switch. Its value comes from matching the polling budget to a measured workload and a compatible NAPI path, with CPU and power cost accounted for alongside receive latency.