poll(2)
๐ poll(2) โ System Calls Manual ๐
okay so we're in the System Calls Manual and this page is literally about poll and ppoll, two besties who have one job: wait for some event on a file descriptor. and they do it beautifully. ๐
โจ NAME โจ
poll, ppoll โ wait for some event on a file descriptor
๐ LIBRARY ๐
Standard C library (libc, -lc). classic.
๐ง SYNOPSIS ๐ง
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <poll.h>
int ppoll(struct pollfd *fds, nfds_t nfds,
const struct timespec *_Nullable tmo_p,
const sigset_t *_Nullable sigmask);
๐ธ DESCRIPTION ๐ธ
so poll() is doing the same little task as select(2): it waits for one of a set of file descriptors to become ready to do I/O. and there's also the Linux-specific epoll(7) API which does a similar thing but comes with features that go beyond what poll() can do. slay for epoll honestly, but we're here for poll today. ๐
The set of file descriptors you're monitoring? That's the fds argument, and it's an array of structures that look exactly like this:
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
The caller is the one who has to say how many items are in the fds array โ that goes in nfds. yes bestie, you gotta count them yourself.
The fd field holds a file descriptor for an open file. and here's a fun one: if this field is negative, then the corresponding events field gets ignored and revents returns zero. (why is that useful? because it's a super easy way to ignore a file descriptor for a single poll() call โ you literally just set the fd field to its bitwise complement. iconic move. โจ)
The events field is an input parameter โ a bit mask saying which events the app cares about for file descriptor fd. It's allowed to be zero, and in that case the only events that can come back in revents are POLLHUP, POLLERR, and POLLNVAL (more on those below ๐).
The revents field is an output parameter, filled in by the kernel with the events that actually happened. The bits returned in revents can include any of the ones you specified in events, plus one of POLLERR, POLLHUP, or POLLNVAL. (heads up: those three bits are meaningless in the events field, and they get set in revents whenever that condition is true, no matter what.)
If none of the requested events (and no error) has happened for any of the file descriptors, then poll() blocks until one of the events occurs. just vibing, waiting. ๐ฆ
The timeout argument is the number of milliseconds that poll() should block waiting for a file descriptor to become ready. The call blocks until either:
- a file descriptor becomes ready;
- the call is interrupted by a signal handler; or
- the timeout expires.
Being "ready" means the requested operation will not block. which is why poll()ing regular files, block devices, and other files with no reasonable polling semantic always returns instantly as ready to read and write. no waiting, no drama. ๐
Note that the timeout interval gets rounded up to the system clock granularity, and kernel scheduling delays mean the blocking interval may overrun by a small amount. Also: a negative value intimeoutmeans an infinite timeout. And a timeout of zero makespoll()return immediately, even if nothing is ready.
The bits that may be set/returned in events and revents are defined in <poll.h>:
POLLINโ There is data to read.POLLPRIโ There is some exceptional condition on the file descriptor. Possible situations include:- There is out-of-band data on a TCP socket (see
tcp(7)). - A pseudoterminal master in packet mode has seen a state change on the slave (see
ioctl_tty(2)). - A
cgroup.eventsfile has been modified (seecgroups(7)).
- There is out-of-band data on a TCP socket (see
POLLOUTโ Writing is now possible, though a write larger than the available space in a socket or pipe will still block (unlessO_NONBLOCKis set).POLLRDHUP(since Linux 2.6.17) โ Stream socket peer closed connection, or shut down writing half of connection. The_GNU_SOURCEfeature test macro must be defined (before including any header files) in order to obtain this definition.POLLERRโ Error condition (only returned inrevents; ignored inevents). This bit is also set for a file descriptor referring to the write end of a pipe when the read end has been closed.POLLHUPโ Hang up (only returned inrevents; ignored inevents). Note that when reading from a channel such as a pipe or a stream socket, this event merely indicates that the peer closed its end of the channel. Subsequent reads from the channel will return 0 (end of file) only after all outstanding data in the channel has been consumed.POLLNVALโ Invalid request:fdnot open (only returned inrevents; ignored inevents).
When compiling with _XOPEN_SOURCE defined, you also get the following, which convey no further information beyond the bits listed above:
POLLRDNORMโ Equivalent toPOLLIN.POLLRDBANDโ Priority band data can be read (generally unused on Linux).POLLWRNORMโ Equivalent toPOLLOUT.POLLWRBANDโ Priority data may be written.
Linux also knows about, but does not use, POLLMSG. it's just... there. lurking. ๐
๐ ppoll() ๐
The relationship between poll() and ppoll() is analogous to the relationship between select(2) and pselect(2): like pselect(2), ppoll() lets an application safely wait until either a file descriptor becomes ready or until a signal is caught. so safe, so secure, so girlboss. ๐
Other than the difference in the precision of the timeout argument, this ppoll() call:
ready = ppoll(&fds, nfds, tmo_p, &sigmask);
is nearly equivalent to atomically executing these calls:
sigset_t origmask;
int timeout;
timeout = (tmo_p == NULL) ? -1 :
(tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000);
pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = poll(&fds, nfds, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);
and it's only "nearly" equivalent because โ the way that a negative timeout value for poll() is read as an infinite timeout, but a negative value expressed in *tmo_p results in an error from ppoll(). so like, almost the same, but not quite. ๐
See the description of pselect(2) for an explanation of why ppoll() is even necessary.
If the sigmask argument is specified as NULL, then no signal mask manipulation happens at all โ and thus ppoll() differs from poll() only in the precision of the timeout argument.
The tmo_p argument specifies an upper limit on the amount of time that ppoll() will block. This argument is a pointer to a timespec(3) structure.
If tmo_p is specified as NULL, then ppoll() can block indefinitely. forever girl. โญ
๐ซ RETURN VALUE ๐ซ
On success, poll() returns a nonnegative value which is the number of elements in the pollfds whose revents fields have been set to a nonzero value (meaning an event or an error happened). A return value of zero means the system call timed out before any file descriptors became ready.
On error, -1 is returned, and errno is set to indicate the error.
๐ญ ERRORS ๐ญ
EFAULTโfdspoints outside the process's accessible address space. The array given as argument was not contained in the calling program's address space. ๐EINTRโ A signal occurred before any requested event; seesignal(7).EINVALโ Thenfdsvalue exceeds theRLIMIT_NOFILEvalue.EINVAL(ppoll()) โ The timeout value expressed in*tmo_pis invalid (negative).ENOMEMโ Unable to allocate memory for kernel data structures.
๐ VERSIONS ๐
On some other UNIX systems, poll() can fail with the error EAGAIN if the system fails to allocate kernel-internal resources โ instead of ENOMEM like Linux does. POSIX permits this behavior. so if you're writing portable programs, you may wanna check for EAGAIN and loop, just like you would with EINTR. lowkey important. ๐ซถ
Some implementations define the nonstandard constant INFTIM with the value -1 for use as a timeout for poll(). This constant is not provided in glibc. no cap.
๐งต C library/kernel differences ๐งต
The Linux ppoll() system call modifies its tmo_p argument. however!! the glibc wrapper function hides this behavior by using a local variable for the timeout argument that gets passed to the system call. so the glibc ppoll() function does not modify its tmo_p argument. she keeps that to herself. ๐
The raw ppoll() system call has a fifth argument, size_t sigsetsize, which specifies the size in bytes of the sigmask argument. The glibc ppoll() wrapper function specifies this argument as a fixed value (equal to sizeof(kernel_sigset_t)). See sigprocmask(2) for a discussion on the differences between the kernel and the libc notion of the sigset.
๐ STANDARDS ๐
POSIX.1-2024.
๐ฐ๏ธ HISTORY ๐ฐ๏ธ
poll() โ POSIX.1-2001. Linux 2.1.23.
On older kernels that lack this system call, the glibc poll() wrapper function provides emulation using select(2).
ppoll() โ POSIX.1-2024. Linux 2.6.16, glibc 2.4.
๐ NOTES ๐
The operation of poll() and ppoll() is not affected by the O_NONBLOCK flag. wild but true.
For a discussion of what may happen if a file descriptor being monitored by poll() is closed in another thread, see select(2).
๐ BUGS ๐
See the discussion of spurious readiness notifications under the BUGS section of select(2).
๐ EXAMPLES ๐
Okay bestie, here's the moment you've been waiting for โ an actual working program that uses poll(). Iconic behavior, honestly. ๐
So this little program opens every file that you name on the command line, and then it watches the resulting file descriptors to see if they're ready to be read (POLLIN). It just loops forever-ish, calling poll() over and over to keep an eye on those fds, and it prints how many of them came back ready. And for each ready fd, the program does this:
- shows you the returned
reventsfield in a form that a human can actually read, no cap; - if the fd is readable, it reads some data out of it and shows that data on standard output; and
- if the fd wasn't readable but some other event happened (which is probably
POLLHUP), it closes the fd.
Now picture this: you run the program in one terminal and ask it to open a FIFO:
$ mkfifo myfifo;
$ ./poll_input myfifo;
Then in a second terminal window, you open that FIFO for writing, write some data into it, and close it:
$ echo aaaaabbbbbccccc > myfifo;
And back in the terminal where the program is running? You'd see this:
Opened "myfifo" on fd 3
About to poll()
Ready: 1
fd=3; events: POLLIN POLLHUP
read 10 bytes: aaaaabbbbb
About to poll()
Ready: 1
fd=3; events: POLLIN POLLHUP
read 6 bytes: ccccc
About to poll()
Ready: 1
fd=3; events: POLLHUP
closing fd 3
All file descriptors closed. Bye.
So in that output, poll() returned three times, and here's the tea on each one: ๐ซ
- First return: the bits in the
reventsfield werePOLLIN(meaning the fd is readable) andPOLLHUP(meaning the other end of the FIFO got closed). The program then ate some of the available input. - Second return from
poll()also saidPOLLINandPOLLHUPโ and the program consumed the last of the available input. - On the final return,
poll()reported onlyPOLLHUPon the FIFO, so the fd got closed and the program said bye bye. ๐
๐ง Program source
/* poll_input.c
Licensed under GNU General Public License v2 or later.
*/
#include <err.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
int ready;
char buf[10];
nfds_t num_open_fds, nfds;
ssize_t s;
struct pollfd *pfds;
if (argc < 2) {
fprintf(stderr, "Usage: %s file...\n", argv[0]);
exit(EXIT_FAILURE);
}
num_open_fds = nfds = argc - 1;
pfds = calloc(nfds, sizeof(struct pollfd));
if (pfds == NULL)
err(EXIT_FAILURE, "malloc");
/* Open each file on command line, and add it to 'pfds' array. */
for (nfds_t j = 0; j < nfds; j++) {
pfds[j].fd = open(argv[j + 1], O_RDONLY);
if (pfds[j].fd == -1)
err(EXIT_FAILURE, "open");
printf("Opened \"%s\" on fd %d\n", argv[j + 1], pfds[j].fd);
pfds[j].events = POLLIN;
}
/* Keep calling poll() as long as at least one file descriptor is
open. */
while (num_open_fds > 0) {
printf("About to poll()\n");
ready = poll(pfds, nfds, -1);
if (ready == -1)
err(EXIT_FAILURE, "poll");
printf("Ready: %d\n", ready);
/* Deal with array returned by poll(). */
for (nfds_t j = 0; j < nfds; j++) {
if (pfds[j].revents != 0) {
printf(" fd=%d; events: %s%s%s\n", pfds[j].fd,
(pfds[j].revents & POLLIN) ? "POLLIN " : "",
(pfds[j].revents & POLLHUP) ? "POLLHUP " : "",
(pfds[j].revents & POLLERR) ? "POLLERR " : "");
if (pfds[j].revents & POLLIN) {
s = read(pfds[j].fd, buf, sizeof(buf));
if (s == -1)
err(EXIT_FAILURE, "read");
printf(" read %zd bytes: %.*s\n",
s, (int) s, buf);
} else { /* POLLERR | POLLHUP */
printf(" closing fd %d\n", pfds[j].fd);
if (close(pfds[j].fd) == -1)
err(EXIT_FAILURE, "close");
num_open_fds--;
}
}
}
}
printf("All file descriptors closed. Bye.\n");
exit(EXIT_SUCCESS);
}
๐ SEE ALSO ๐
And that's the whole page, bestie!! ๐ฆ You made it to the very end, which is giving academic weapon energy fr fr. โจ
Quick li'l sign-off so you know exactly which version of this page you just devoured: it's from Linux man-pages 6.20, dated 2026-02-08, and it's all about poll(2). Screenshot it, bookmark it, tattoo it on your forearm โ whatever works for you. ๐ Bye!! ๐
๐ฆ 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
- Copyright 2006-2019, Michael Kerrisk <mtk.manpages@gmail.com>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms