epoll_wait(2)

๐Ÿ’– epoll_wait(2) โ€” bestie edition ๐Ÿ’–

okay so this is the manual page for epoll_wait, epoll_pwait, and epoll_pwait2 โ€” three little legends from the Linux man-pages fam, living in section 2 (the System Calls Manual, iykyk). they wait for I/O events on an epoll file descriptor and honestly? iconic behavior. no cap. ๐Ÿฆ‹


โœจ NAME โœจ

epoll_wait, epoll_pwait, epoll_pwait2 โ€” wait for an I/O event on an epoll file descriptor ๐Ÿ’…

๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C library (libc, -lc)

๐ŸŽ€ SYNOPSIS ๐ŸŽ€

#include <sys/epoll.h>

int epoll_wait(int n;
               int epfd, struct epoll_event events[n], int n,
               int timeout);
int epoll_pwait(int n;
               int epfd, struct epoll_event events[n], int n,
               int timeout,
               const sigset_t *_Nullable sigmask);
int epoll_pwait2(int n;
               int epfd, struct epoll_event events[n], int n,
               const struct timespec *_Nullable timeout,
               const sigset_t *_Nullable sigmask);

๐ŸŒธ DESCRIPTION ๐ŸŒธ

okay so the epoll_wait() system call literally just sits there and waits for events on the epoll(7) instance that the file descriptor epfd is pointing at. the buffer that events points to is where all the tea gets returned โ€” info from the ready list about the file descriptors in the interest list that have some events available. up to n of them come back from epoll_wait(), and the n argument must be greater than zero, periodt.

the timeout argument is how many milliseconds epoll_wait() is gonna block for. time is measured against the CLOCK_MONOTONIC clock (โœจ the clock of truth โœจ).

so a call to epoll_wait() will block until one of these three things happens:

  • a file descriptor delivers an event ๐ŸŽ‰
  • the call gets interrupted by a signal handler ๐Ÿ˜ญ
  • the timeout expires โฐ

heads up bestie: the timeout interval gets rounded up to the system clock granularity, and kernel scheduling delays mean the blocking interval might overrun by a little bit. nature of the game. and:

  • timeout of -1 โ†’ epoll_wait() blocks forever, like it's waiting for him to text back ๐Ÿ’€
  • timeout of 0 โ†’ epoll_wait() returns immediately, even if there are zero events available. she's not waiting around.

the struct epoll_event is described over in epoll_event(3type).

the data field of each returned epoll_event structure holds the exact same data that was specified in the most recent call to epoll_ctl(2) (EPOLL_CTL_ADD, EPOLL_CTL_MOD) for the corresponding open file descriptor. same data, no changes, we keep the receipts bestie ๐Ÿงพ

the events field is a bit mask that shows which events have occurred for the corresponding open file description. want the full list of bits that can show up in this mask? go look at epoll_ctl(2). ๐Ÿ“‹

๐Ÿ’ซ epoll_pwait() ๐Ÿ’ซ

the relationship between epoll_wait() and epoll_pwait() is exactly like the relationship between select(2) and pselect(2) โ€” it's giving siblings. just like pselect(2), epoll_pwait() lets an application safely wait until either a file descriptor becomes ready or a signal is caught. ๐Ÿซถ

this following epoll_pwait() call:

ready = epoll_pwait(epfd, &events, n, timeout, &sigmask);

is equivalent to atomically executing these calls:

sigset_t origmask;

pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = epoll_wait(epfd, &events, n, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);

the sigmask argument can be specified as NULL, and in that case epoll_pwait() is just equivalent to epoll_wait(). twins fr fr. ๐Ÿ‘ฏ

๐ŸŒˆ epoll_pwait2() ๐ŸŒˆ

the epoll_pwait2() system call is equivalent to epoll_pwait() except for the timeout argument. it takes an argument of type timespec so you can specify a nanosecond resolution timeout. she's precise like that. โฑ๏ธ this argument functions the same as in pselect(2) and ppoll(2). if timeout is NULL, then epoll_pwait2() can block indefinitely โ€” main character energy, no time limit. ๐Ÿ‘‘


๐Ÿ“ RETURN VALUE ๐Ÿ“

on success, epoll_wait() returns the number of file descriptors ready for the requested I/O operation. or zero, if no file descriptor became ready during the requested timeout milliseconds (sad, but valid). on failure, epoll_wait() returns -1 and errno is set to indicate the error. ๐Ÿ˜ค


๐Ÿ’… ERRORS ๐Ÿ’…

  • EBADF โ€” the epfd is not a valid file descriptor. it's giving fake.
  • EFAULT โ€” the memory area pointed to by events is not accessible with write permissions. rude.
  • EINTR โ€” the call was interrupted by a signal handler before either (1) any of the requested events occurred or (2) the timeout expired; see signal(7).
  • EINVAL โ€” the epfd is not an epoll file descriptor, or n is less than or equal to zero. (yes, n <= 0 is a crime here, bestie.)

โญ STANDARDS โญ

Linux. that's it, that's the standard. ๐Ÿง


๐Ÿ‘‘ HISTORY ๐Ÿ‘‘

  • epoll_wait() โ€” Linux 2.6, glibc 2.3.2. a true vintage.
  • epoll_pwait() โ€” Linux 2.6.19, glibc 2.6. glow up era.
  • epoll_pwait2() โ€” Linux 5.11. the new kid, and she's slaying.

๐Ÿฆ‹ NOTES ๐Ÿฆ‹

while one thread is blocked in a call to epoll_wait(), it's totally possible for another thread to add a file descriptor to the waited-upon epoll instance. and if that new file descriptor becomes ready, it will cause the epoll_wait() call to unblock. teamwork makes the dream work ๐Ÿซถ

if more than n file descriptors are ready when epoll_wait() is called, then successive epoll_wait() calls will round robin through the set of ready file descriptors. this behavior helps avoid starvation scenarios, where a process fails to notice that additional file descriptors are ready because it's focusing on a set of file descriptors that are already known to be ready. like, girl, look around. ๐Ÿ‘€

also note that it's possible to call epoll_wait() on an epoll instance whose interest list is currently empty โ€” or whose interest list becomes empty because file descriptors are closed or removed from the interest in another thread. the call will block until some file descriptor is later added to the interest list (in another thread) and that file descriptor becomes ready. manifesting events. ๐ŸŒ 

๐Ÿ” C library/kernel differences ๐Ÿ”

the raw epoll_pwait() and epoll_pwait2() system calls have a sixth argument, size_t sigsetsize, which specifies the size in bytes of the sigmask argument. the glibc epoll_pwait() wrapper function specifies this argument as a fixed value (equal to sizeof(sigset_t)). glibc said "I got it, don't worry about it." ๐Ÿ’


๐Ÿ’€ BUGS ๐Ÿ’€

before Linux 2.6.37, a timeout value larger than approximately LONG_MAX / HZ milliseconds is treated as -1 (i.e., infinity). so for example, on a system where sizeof(long) is 4 and the kernel HZ value is 1000, this means that timeouts greater than 35.79 minutes are treated as infinity. not her rounding up, just straight up ignoring you. old kernel behavior, we don't miss it. ๐Ÿ™ˆ


๐Ÿ”ฅ SEE ALSO ๐Ÿ”ฅ

epoll_create(2), epoll_ctl(2), epoll(7)


and that's the whole page bestie, you ate that. ๐Ÿฝ๏ธโœจ

this lil tour came to you from Linux man-pages 6.20, dated 2026-02-08 โ€” drop a ๐Ÿ’– for epoll_wait(2) and go make your event loop iconic. ๐Ÿ’œ๐Ÿ‘‘๐Ÿฆ‹

๐Ÿ“ฆ 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: GPL-2.0-or-later
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms