From 2ddff9569992dbf4948dd457c8febe6925d72437 Mon Sep 17 00:00:00 2001 From: millert Date: Tue, 12 May 2015 19:38:13 +0000 Subject: [PATCH] Race less. --- regress/sys/fifofs/fifotest.c | 127 ++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 51 deletions(-) diff --git a/regress/sys/fifofs/fifotest.c b/regress/sys/fifofs/fifotest.c index 87c1332dc27..ee316303381 100644 --- a/regress/sys/fifofs/fifotest.c +++ b/regress/sys/fifofs/fifotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2014 Todd C. Miller + * Copyright (c) 2004, 2014-2015 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -32,8 +32,9 @@ void usage(void); void sigalrm(int); -void dopoll(int, int, char *, int); -void doselect(int, int, int); +void sigusr1(int); +void dopoll(pid_t, int, int, char *, int); +void doselect(pid_t, int, int, int); void runtest(char *, int, int); void eoftest(char *, int, int); @@ -58,12 +59,17 @@ main(int argc, char **argv) if (argc != 2) usage(); - /* Just warn EINTR from SIGALRM */ + /* Just want EINTR from SIGALRM */ sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = sigalrm; sigaction(SIGALRM, &sa, NULL); + /* SIGUSR1 is used for syncronization only. */ + sa.sa_flags = SA_RESTART; + sa.sa_handler = sigusr1; + sigaction(SIGUSR1, &sa, NULL); + runtest(argv[1], 0, 0); runtest(argv[1], 0, INFTIM); runtest(argv[1], O_NONBLOCK, 0); @@ -86,6 +92,7 @@ runtest(char *fifo, int flags, int timeout) exit(1); } + /* Note: O_RDWR not required by POSIX */ alarm(2); if ((fd = open(fifo, O_RDWR | flags, 0644)) == -1) { printf("open %s: %s\n", fifo, strerror(errno)); @@ -97,14 +104,14 @@ runtest(char *fifo, int flags, int timeout) (flags & O_NONBLOCK) ? " (nonblocking)" : ""); printf("\nTesting empty FIFO:\n"); - dopoll(fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); - dopoll(fd, POLLIN, "POLLIN", timeout); - dopoll(fd, POLLOUT, "POLLOUT", timeout); - dopoll(fd, 0, "(none)", timeout); - doselect(fd, fd, timeout); - doselect(fd, -1, timeout); - doselect(-1, fd, timeout); - doselect(-1, -1, timeout); + dopoll(-1, fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); + dopoll(-1, fd, POLLIN, "POLLIN", timeout); + dopoll(-1, fd, POLLOUT, "POLLOUT", timeout); + dopoll(-1, fd, 0, "(none)", timeout); + doselect(-1, fd, fd, timeout); + doselect(-1, fd, -1, timeout); + doselect(-1, -1, fd, timeout); + doselect(-1, -1, -1, timeout); if (write(fd, "test", 4) != 4) { printf("write error: %s\n", strerror(errno)); @@ -112,14 +119,14 @@ runtest(char *fifo, int flags, int timeout) } printf("\nTesting full FIFO:\n"); - dopoll(fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); - dopoll(fd, POLLIN, "POLLIN", timeout); - dopoll(fd, POLLOUT, "POLLOUT", timeout); - dopoll(fd, 0, "(none)", timeout); - doselect(fd, fd, timeout); - doselect(fd, -1, timeout); - doselect(-1, fd, timeout); - doselect(-1, -1, timeout); + dopoll(-1, fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); + dopoll(-1, fd, POLLIN, "POLLIN", timeout); + dopoll(-1, fd, POLLOUT, "POLLOUT", timeout); + dopoll(-1, fd, 0, "(none)", timeout); + doselect(-1, fd, fd, timeout); + doselect(-1, fd, -1, timeout); + doselect(-1, -1, fd, timeout); + doselect(-1, -1, -1, timeout); if ((nread = read(fd, buf, sizeof(buf))) <= 0) { printf("read error: %s\n", (nread == 0) ? "EOF" : strerror(errno)); @@ -129,12 +136,19 @@ runtest(char *fifo, int flags, int timeout) printf("\treceived '%s' from FIFO\n", buf); } -int +pid_t eof_writer(const char *fifo, int flags) { int fd; + pid_t pid; + sigset_t mask, omask; - switch (fork()) { + /* Block SIGUSR1 (in child). */ + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_BLOCK, &mask, &omask); + + switch ((pid = fork())) { case -1: printf("fork: %s\n", strerror(errno)); return -1; @@ -143,26 +157,27 @@ eof_writer(const char *fifo, int flags) break; default: /* parent */ - return 0; + sigprocmask(SIG_SETMASK, &omask, NULL); + return pid; } - /* Wait for the reader to connect. */ - for (;;) { - alarm(2); - fd = open(fifo, O_WRONLY | flags, 0644); - alarm(0); - if (fd != -1) - break; - if (errno != ENOENT && errno != ENXIO) { - printf("open %s O_WRONLY: %s\n", fifo, strerror(errno)); - return -1; - } - usleep(10000); + /* Wait for reader. */ + sigemptyset(&mask); + sigsuspend(&mask); + sigprocmask(SIG_SETMASK, &omask, NULL); + + /* connect to FIFO. */ + alarm(2); + fd = open(fifo, O_WRONLY | flags, 0644); + alarm(0); + if (fd == -1) { + printf("open %s O_WRONLY: %s\n", fifo, strerror(errno)); + return -1; } /* - * We need to give the reader time to call select() before - * we close the fd. This is racey... + * We need to give the reader time to call poll() or select() + * before we close the fd. This is racey... */ usleep(100000); close(fd); @@ -173,7 +188,8 @@ void eoftest(char *fifo, int flags, int timeout) { ssize_t nread; - int fd = -1, rval, pass, status; + int fd = -1, pass, status; + pid_t writer; char buf[BUFSIZ]; /* @@ -211,42 +227,42 @@ eoftest(char *fifo, int flags, int timeout) * The writer will sleep for a bit to give the reader time * to call select() before anything has been written. */ - rval = eof_writer(fifo, flags); - if (rval == -1) + writer = eof_writer(fifo, flags); + if (writer == -1) exit(1); switch (pass) { case 0: case 1: - dopoll(fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); + dopoll(writer, fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); break; case 2: case 3: - dopoll(fd, POLLIN, "POLLIN", timeout); + dopoll(writer, fd, POLLIN, "POLLIN", timeout); break; case 4: case 5: - dopoll(fd, POLLOUT, "POLLOUT", timeout); + dopoll(writer, fd, POLLOUT, "POLLOUT", timeout); break; case 6: case 7: - dopoll(fd, 0, "(none)", timeout); + dopoll(writer, fd, 0, "(none)", timeout); break; case 8: case 9: - doselect(fd, fd, timeout); + doselect(writer, fd, fd, timeout); break; case 10: case 11: - doselect(fd, -1, timeout); + doselect(writer, fd, -1, timeout); break; case 12: case 13: - doselect(-1, fd, timeout); + doselect(writer, -1, fd, timeout); break; case 14: case 15: - doselect(-1, -1, timeout); + doselect(writer, -1, -1, timeout); break; } wait(&status); @@ -263,7 +279,7 @@ eoftest(char *fifo, int flags, int timeout) } void -dopoll(int fd, int events, char *str, int timeout) +dopoll(pid_t writer, int fd, int events, char *str, int timeout) { struct pollfd pfd; int nready; @@ -273,6 +289,8 @@ dopoll(int fd, int events, char *str, int timeout) printf("\tpoll %s, timeout=%d\n", str, timeout); pfd.events = events; + if (writer != -1) + kill(writer, SIGUSR1); alarm(2); nready = poll(&pfd, 1, timeout); alarm(0); @@ -295,7 +313,7 @@ dopoll(int fd, int events, char *str, int timeout) } void -doselect(int rfd, int wfd, int timeout) +doselect(pid_t writer, int rfd, int wfd, int timeout) { struct timeval tv, *tvp; fd_set *rfds = NULL, *wfds = NULL; @@ -329,7 +347,8 @@ doselect(int rfd, int wfd, int timeout) printf("\tselect%s%s, timeout=%d\n", rfds ? " read" : "", wfds ? " write" : rfds ? "" : " (none)", timeout); - + if (writer != -1) + kill(writer, SIGUSR1); alarm(2); nready = select(maxfd + 1, rfds, wfds, NULL, &tv); alarm(0); @@ -355,6 +374,12 @@ sigalrm(int dummy) return; } +void +sigusr1(int dummy) +{ + return; +} + void usage(void) { -- 2.20.1