ioctl_eventpoll(2)

πŸ’– ioctl_eventpoll β€” bestie, it's the epoll ioctl page ✨

okay so welcome to ioctl_eventpoll(2), part of the System Calls Manual, and literally the cutest little corner of the Linux kernel interface you're gonna meet today. it's giving "tiny struct, big opinions about how your NIC handles packets." let's get into it πŸ’…

πŸŽ€ LIBRARY

Standard C library (libc, -lc) 🫢


🌸 SYNOPSIS

#include <sys/epoll.h>  /* Definition of EPIOC* constants */
#include <sys/ioctl.h>

int ioctl(int fd, EPIOCSPARAMS, const struct epoll_params *argp);
int ioctl(int fd, EPIOCGPARAMS, struct epoll_params *argp);

#include <sys/epoll.h>

struct epoll_params {
    uint32_t  busy_poll_usecs;   /* Number of usecs to busy poll */
    uint16_t  busy_poll_budget;  /* Max packets per poll */
    uint8_t   prefer_busy_poll;  /* Boolean preference  */

    /* pad the struct to a multiple of 64bits */
    uint8_t   __pad;             /* Must be zero */
};

like look at that struct. four fields. one of them is just padding. it knows what it is and it's thriving 🌈


✨ DESCRIPTION ✨

EPIOCSPARAMS πŸ’–

Sets the epoll_params structure to configure how epoll operates. Wanna know what config is actually supported? Scroll down to the struct description, bestie, it's all there πŸ‘‡

EPIOCGPARAMS πŸ’–

Gets the current epoll_params configuration settings. Reading the room, respectfully 🫢

okay important: all the operations documented above have to be performed on an epoll file descriptor. You can get one of those by calling epoll_create(2) or epoll_create1(2). No random fds, this is a members-only situation πŸ”’

πŸ¦‹ The epoll_params structure

  • argp.busy_poll_usecs β€” the number of microseconds the network stack will busy poll. During this window, the network device gets polled repeatedly for packets. Not me being impatient on purpose. This value cannot exceed INT_MAX.
  • argp.busy_poll_budget β€” the maximum number of packets the network stack will retrieve on each poll attempt. This value cannot exceed NAPI_POLL_WEIGHT (which is 64 as of Linux 6.9) β€” unless the process is run with CAP_NET_ADMIN, in which case go off, you have privileges πŸ‘‘
  • argp.prefer_busy_poll β€” a boolean field and it must be either 0 (disabled) or 1 (enabled). If enabled, this tells the network stack that busy poll is the preferred method of processing network data, and the network stack should give the application the opportunity to busy poll. Without this option, very busy systems may keep on doing network processing via the normal method of IRQs triggering softIRQ and NAPI. it's giving "please, I'll handle it myself" 🫠
  • argp.__pad β€” must be zero. that's it. that's the whole job. zero. ⭐

πŸ‘‘ RETURN VALUE

On success, 0 is returned. On failure, -1 is returned, and errno is set to indicate the error. classic. the duality of syscall πŸ’€


πŸ’… ERRORS

  • EOPNOTSUPP β€” the kernel was not compiled with busy poll support. sad! the vibe check failed at compile time 😭
  • EINVAL β€” fd is not a valid file descriptor.
  • EINVAL β€” argp.__pad is not zero.
  • EINVAL β€” argp.busy_poll_usecs exceeds INT_MAX.
  • EINVAL β€” argp.prefer_busy_poll is not 0 or 1.
  • EPERM β€” the process is being run without CAP_NET_ADMIN and the specified argp.busy_poll_budget exceeds NAPI_POLL_WEIGHT. no cap, you need the cap 🧒
  • EFAULT β€” argp is an invalid address.

🌟 STANDARDS

Linux. that's the standard. periodt πŸ’œ


πŸ•°οΈ HISTORY

Linux 6.9, glibc 2.40. it's a young icon but an icon nonetheless ✨


πŸ“ EXAMPLES

Setting the epoll params to enable busy polling:

/* Code to set the epoll params to enable busy polling */

int epollfd = epoll_create1(0);
struct epoll_params params;

if (epollfd == -1) {
    perror("epoll_create1");
    exit(EXIT_FAILURE);
}

memset(&params, 0, sizeof(struct epoll_params));

params.busy_poll_usecs = 25;
params.busy_poll_budget = 8;
params.prefer_busy_poll = 1;

if (ioctl(epollfd, EPIOCSPARAMS, &params) == -1) {
    perror("ioctl");
    exit(EXIT_FAILURE);
}

and then how to retrieve the current settings:

/* Code to show how to retrieve the current settings */

memset(&params, 0, sizeof(struct epoll_params));

if (ioctl(epollfd, EPIOCGPARAMS, &params) == -1) {
    perror("ioctl");
    exit(EXIT_FAILURE);
}

/* params struct now contains the current parameters */

fprintf(stderr, "epoll usecs: %lu\n", params.busy_poll_usecs);
fprintf(stderr, "epoll packet budget: %u\n", params.busy_poll_budget);
fprintf(stderr, "epoll prefer busy poll: %u\n", params.prefer_busy_poll);

see how memset to zero shows up before both calls? that's the __pad being a good citizen btw. we love a struct that's fully zeroed 🌸


πŸ”₯ SEE ALSO


and that's the whole page, bestie!! πŸŽ€πŸ’–βœ¨

this read was brought to you by Linux man-pages 6.20, dated 2026-07-15, and the diva herself: ioctl_eventpoll(2). go busy poll something responsibly πŸ¦‹πŸ’…

πŸ“¦ where this page comes from
  • arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • πŸ“œ the page's license: Linux-man-pages-copyleft
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms