Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

epoll_wait(2)

FieldValue
Numbers (x64 / i386 / arm64-generic / arm32)epoll_wait 232 / 256 / - / 252; epoll_pwait 281 / 319 / 22 / 346; epoll_pwait2 441 / 441 / 441 / 441 (ledger + cached tables; the hub row carries the pwait slots 281/319/22/346)
Since (kernel)epoll_wait 2.6 (hub/ledger; man comment: 2.5.44); hub row Since “2.6.19” tracks epoll_pwait (2.6.19, epoll_wait.2); epoll_pwait2 5.11 (epoll_wait.2)
Man pageman2/epoll_wait.2 (cached roff, dated 2021-03-22; epoll_pwait.2 and epoll_pwait2.2 are .so aliases)
glibc wrapperepoll_wait 2.3.2; epoll_pwait 2.6; epoll_pwait2 glibc 2.35 (cached man page has a FIXME on pwait2; nm: epoll_pwait2@@GLIBC_2.35 in glibc 2.41)
Aliases coveredepoll_pwait (SC-epoll_pwait), epoll_pwait2 (SC-epoll_pwait2); old-slot note for epoll_ctl_old (x64 214) and epoll_wait_old (x64 215)
Ledger IDSC-epoll_wait

Purpose

epoll_wait() fetches ready events from the epoll instance epfd created by epoll_create: it fills events with up to maxevents epoll_event records for descriptors in the interest list that became ready. The pwait variants add an atomic sigmask swap like pselect/ppoll; pwait2 upgrades the timeout to nanoseconds.

Synopsis

#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,
               int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
                int maxevents, int timeout, const sigset_t *sigmask);
int epoll_pwait2(int epfd, struct epoll_event *events,
                 int maxevents, const struct timespec *timeout,
                 const sigset_t *sigmask);

Arguments and behavior

timeout is milliseconds, measured against CLOCK_MONOTONIC: -1 blocks indefinitely, 0 returns immediately. maxevents must be > 0. epoll_wait blocks until an event, a signal, or timeout expiry. epoll_pwait() equals atomically running sigprocmask(SIG_SETMASK, sigmask) around epoll_wait; sigmask NULL reduces it to epoll_wait. epoll_pwait2 (5.11) takes a timespec timeout like pselect/ppoll (NULL = infinite). The raw pwait syscalls take a sixth argument sigsetsize = sizeof(kernel sigset) which the glibc wrapper fixes (epoll_wait.2 C library/kernel differences). Returned data fields are exactly what epoll_ctl EPOLL_CTL_ADD/MOD stored.

Return value and errors

Number of ready fds, 0 on timeout; -1 with errno: EBADF, EFAULT (events not writable), EINTR, EINVAL (epfd not epoll; maxevents <= 0).

Flags and constants

Event bits in returned events come from the epoll_ctl mask (EPOLLIN, EPOLLOUT, EPOLLRDHUP, EPOLLPRI, EPOLLERR, EPOLLHUP); the four input-only EPOLLET/EPOLLONESHOT/EPOLLWAKEUP/EPOLLEXCLUSIVE bits never appear here.

Security and notes

Round-robin fairness: with more than maxevents ready fds, successive calls rotate through the ready set (epoll_wait.2 NOTES). Wait works even with an empty interest list; another thread’s ADD that turns ready unblocks the waiter. Pre-2.6.37 kernels treat oversized timeouts (> about LONG_MAX/HZ ms) as infinity (BUGS). Old slots (worklog 1-g, verified empty implementation columns in the cached syscall_64.tbl): x64 214 epoll_ctl_old and 215 epoll_wait_old were allocated but never enabled and have no i386/generic/arm rows – documented as researched in ledger/1-g. musl 1.2.5 (src/linux/epoll.c, worklog 1-g) calls SYS_epoll_pwait first and falls back to SYS_epoll_wait only when sigs is NULL.

References

  • Cached man page: source-cache/man-pages-sparse/man2/epoll_wait.2 (pwait/pwait2 .so).
  • Numbers: ledger.md; source-cache/kernel/syscall_{64,32,generic,arm}.tbl; hub overview.md.
  • glibc symbols: nm -D libc.so.6 (glibc 2.41, worklog 3-f); cached man FIXME noted.
  • Worklog Task 1-g (old slots verification; musl fallback).