The manpages say for poll(2):
POLLHUP - Hang up (output only)
POLLNVAL - Invalid request: fd not open (output only)
What exactly is the difference? Writing a simple program shows that POLLNVAL will trigger if I close a file descriptor, then try reading from the closed fd. However, I can't figure out a way to return a POLLHUP.
3 Answers
POLLNVAL is equivalent to EBADF: it means the file descriptor does not actually refer to any open file, i.e. it was closed or never open to begin with. This can never happen except as a result of a programming error or intentional attempt to query whether a file descriptor is invalid. External conditions, such as a peer closing its end of a network socket or pipe, can never close your file descriptor to your end of the socket or pipe. If it could, this would lead to massive vulnerabilities in basically any program using sockets/pipes/etc.
POLLHUP, on the other hand, indicates that your file descriptor is valid, but that it's in a state where:
A device has been disconnected, or a pipe or FIFO has been closed by the last process that had it open for writing. Once set, the hangup state of a FIFO shall persist until some process opens the FIFO for writing or until all read-only file descriptors for the FIFO are closed. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive. This flag is only valid in the revents bitmask; it shall be ignored in the events member.
If you want to see POLLHUP, simply open a pipe, close the reading end, and query the writing end with poll.
If your goal is to write a program that triggers POLLHUP, try something like opening a pipe, closing the write end of it and then poll()ing the read end (code modified from ):
#include <unistd.h> #include <stdio.h> #include <poll.h> #include <stdlib.h> #include <errno.h> #include <string.h> int main(void) { int p[2]; struct pollfd ufd; if (pipe(p) < 0) { perror("pipe"); return EXIT_FAILURE; } if (close(p[1]) < 0) { /* close the write fd */ perror("close"); return EXIT_FAILURE; } memset(&ufd, 0, sizeof ufd); ufd.fd = p[0]; /* poll the read fd after the write fd is closed */ ufd.events = POLLIN; if (poll(&ufd, 1, 1000) < 0) { perror("poll"); return EXIT_FAILURE; } switch(ufd.revents & (POLLIN|POLLHUP)) { case POLLIN: printf("POLLIN\n"); break; case POLLHUP: printf("POLLHUP\n"); break; case POLLIN|POLLHUP: printf("POLLIN|POLLHUP\n"); break; case POLLERR: printf("POLLERR\n"); break; default: printf("%#x\n", (unsigned)ufd.revents); break; } return EXIT_SUCCESS; } The above prints POLLHUP for me.
POLLNVAL means that the file descriptor value is invalid. It usually indicates an error in your program, but you can rely on poll returning POLLNVAL if you've closed a file descriptor and you haven't opened any file since then that might have reused the descriptor.
POLLHUP basically means that what's at the other end of the connection has closed its end of the connection. POSIX describes it as
The device has been disconnected. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred.
This is clear enough for a terminal: the terminal has gone away (same event that generates a SIGHUP: the modem session has been terminated, the terminal emulator window has been closed, etc.). POLLHUP is never sent for a regular file. For pipes and sockets, it depends. Linux sets POLLHUP when the program on the writing end of a pipe closes the pipe, and sets POLLIN|POLLHUP when the other end of a socket closed the socket, but POLLIN only for a socket shutdown. Recent *BSD set POLLIN|POLLUP when the writing end of a pipe closes the pipe, and the behavior for sockets is more variable.
To observe POLLHUP, have your program read from a terminal and close the terminal. Or, on Linux, have your program read from a pipe and close the writing end (e.g. sleep 1 | yourprogram).