Skip to content

Instantly share code, notes, and snippets.

@jgalar
Created November 3, 2020 18:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jgalar/5c3c2673b69fa0df652bda80a88f860c to your computer and use it in GitHub Desktop.
Save jgalar/5c3c2673b69fa0df652bda80a88f860c to your computer and use it in GitHub Desktop.
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#define CHECK(OP) check(#OP, OP)
static int check(const char *what, int n)
{
if (n < 0) {
perror(what);
exit(EXIT_FAILURE);
}
return n;
}
/*
* Check if POLLHUP is received when polling on the read-end
* of a pipe whose write-end is closed either before or during
* the call to poll().
*/
int main(int argc, const char **argv)
{
pid_t child_pid;
int hup_pipe[2];
struct pollfd pfd = {};
int exit_status;
bool close_before = false, close_during = false;
if (argc != 2) {
puts("Usage: ./poll-hup-fork before|during");
exit_status = EXIT_SUCCESS;
goto end;
}
if (strcmp(argv[1], "during") == 0) {
close_during = true;
} else if (strcmp(argv[1], "before") == 0) {
close_before = true;
} else {
fprintf(stderr, "Unrecognized option '%s'", argv[1]);
exit_status = EXIT_FAILURE;
goto end;
}
CHECK(pipe(hup_pipe));
pfd.fd = hup_pipe[0];
/* Changing this to `POLLHUP | POLLIN` fixes the hang. */
pfd.events = POLLHUP;
child_pid = fork();
if (child_pid == 0) {
/* Child */
if (close_during) {
sleep(2);
}
/* Close pipe. */
CHECK(close(hup_pipe[0]));
CHECK(close(hup_pipe[1]));
exit_status = EXIT_SUCCESS;
} else if (child_pid > 0) {
/* Parent */
int wstatus;
/* Close pipe's write end. */
CHECK(close(hup_pipe[1]));
if (close_before) {
sleep(2);
}
CHECK(poll(&pfd, 1, -1));
switch (pfd.revents) {
case POLLIN:
printf("revents: POLLIN\n");
exit_status = EXIT_FAILURE;
break;
case POLLHUP:
printf("revents: POLLHUP\n");
exit_status = EXIT_SUCCESS;
break;
case POLLIN | POLLHUP:
printf("revents: POLLIN | POLLHUP\n");
exit_status = EXIT_FAILURE;
break;
default:
printf("Unexpected revents: %d\n", pfd.revents);
exit_status = EXIT_FAILURE;
}
CHECK(waitpid(child_pid, &wstatus, 0));
} else {
perror("Failed to fork");
exit_status = EXIT_FAILURE;
}
end:
return exit_status;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment