Test suite for the poll(2)/select(2) on fifos, pipes and sockets,

and recorded results for several operating systems.

Submitted by:	bde
Approved by:	re (kensmith)
This commit is contained in:
Konstantin Belousov 2009-07-12 12:50:43 +00:00
parent 529ab57b9a
commit 5861f96654
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195636
14 changed files with 883 additions and 0 deletions

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected 0; got 0
ok 2 Pipe state 5: expected POLLIN; got POLLIN
ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
not ok 4 Pipe state 6a: expected POLLHUP; got POLLIN | POLLHUP
ok 5 Sock state 4: expected 0; got 0
ok 6 Sock state 5: expected POLLIN; got POLLIN
not ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN
not ok 8 Sock state 6a: expected POLLHUP; got POLLIN
not ok 9 FIFO state 0: expected 0; got POLLIN
ok 10 FIFO state 1: expected 0; got 0
ok 11 FIFO state 2: expected POLLIN; got POLLIN
ok 12 FIFO state 2a: expected 0; got 0
not ok 13 FIFO state 3: expected POLLHUP; got POLLIN
ok 14 FIFO state 4: expected 0; got 0
ok 15 FIFO state 5: expected POLLIN; got POLLIN
not ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN
not ok 17 FIFO state 6a: expected POLLHUP; got POLLIN
not ok 18 FIFO state 6b: expected 0; got POLLIN
not ok 19 FIFO state 6c: expected POLLHUP; got POLLIN
not ok 20 FIFO state 6d: expected POLLHUP; got POLLIN

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected clear; got clear
ok 2 Pipe state 5: expected set; got set
ok 3 Pipe state 6: expected set; got set
ok 4 Pipe state 6a: expected set; got set
ok 5 Sock state 4: expected clear; got clear
ok 6 Sock state 5: expected set; got set
ok 7 Sock state 6: expected set; got set
ok 8 Sock state 6a: expected set; got set
not ok 9 FIFO state 0: expected clear; got set
ok 10 FIFO state 1: expected clear; got clear
ok 11 FIFO state 2: expected set; got set
ok 12 FIFO state 2a: expected clear; got clear
ok 13 FIFO state 3: expected set; got set
ok 14 FIFO state 4: expected clear; got clear
ok 15 FIFO state 5: expected set; got set
ok 16 FIFO state 6: expected set; got set
ok 17 FIFO state 6a: expected set; got set
not ok 18 FIFO state 6b: expected clear; got set
ok 19 FIFO state 6c: expected set; got set
ok 20 FIFO state 6d: expected set; got set

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected 0; got 0
ok 2 Pipe state 5: expected POLLIN; got POLLIN
ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
not ok 4 Pipe state 6a: expected POLLHUP; got POLLIN | POLLHUP
ok 5 Sock state 4: expected 0; got 0
ok 6 Sock state 5: expected POLLIN; got POLLIN
not ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN
not ok 8 Sock state 6a: expected POLLHUP; got POLLIN
ok 9 FIFO state 0: expected 0; got 0
ok 10 FIFO state 1: expected 0; got 0
ok 11 FIFO state 2: expected POLLIN; got POLLIN
ok 12 FIFO state 2a: expected 0; got 0
not ok 13 FIFO state 3: expected POLLHUP; got 0
ok 14 FIFO state 4: expected 0; got 0
ok 15 FIFO state 5: expected POLLIN; got POLLIN
not ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN
not ok 17 FIFO state 6a: expected POLLHUP; got 0
ok 18 FIFO state 6b: expected 0; got 0
not ok 19 FIFO state 6c: expected POLLHUP; got 0
not ok 20 FIFO state 6d: expected POLLHUP; got 0

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected clear; got clear
ok 2 Pipe state 5: expected set; got set
ok 3 Pipe state 6: expected set; got set
ok 4 Pipe state 6a: expected set; got set
ok 5 Sock state 4: expected clear; got clear
ok 6 Sock state 5: expected set; got set
ok 7 Sock state 6: expected set; got set
ok 8 Sock state 6a: expected set; got set
ok 9 FIFO state 0: expected clear; got clear
ok 10 FIFO state 1: expected clear; got clear
ok 11 FIFO state 2: expected set; got set
ok 12 FIFO state 2a: expected clear; got clear
not ok 13 FIFO state 3: expected set; got clear
ok 14 FIFO state 4: expected clear; got clear
ok 15 FIFO state 5: expected set; got set
ok 16 FIFO state 6: expected set; got set
not ok 17 FIFO state 6a: expected set; got clear
ok 18 FIFO state 6b: expected clear; got clear
not ok 19 FIFO state 6c: expected set; got clear
not ok 20 FIFO state 6d: expected set; got clear

View File

@ -0,0 +1,35 @@
$ $FreeBSD$
# This makefile has been uglified for portability.
# Nothing yet works with gmake for the path to the sources.
.PATH: ..
PROG= pipepoll pipeselect
CFLAGS+= -Werror -Wall
all: ${PROG}
pipepoll: pipepoll.c
pipeselect: pipeselect.c
pipepoll pipeselect:
${CC} ${CFLAGS} ${LDFLAGS} -o $@ $@.c
test: all
-for prog in ${PROG}; do \
./$${prog} > $${prog}.out.new; \
diff -u1 $${prog}.out $${prog}.out.new; \
done
clean:
for prog in ${PROG}; do \
rm -f $${prog} $${prog}.out.new; \
done
rename:
for prog in ${PROG}; do \
mv $${prog}.out.new $${prog}.out; \
done
veryclean: clean
for prog in ${PROG}; do \
rm -f $${prog}.out; \
done

View File

@ -0,0 +1,18 @@
$FreeBSD$
The directory contains poll(2) and select(2) compliance (and more) tests
from Bruce Evans, together with canned test results from several systems
for reference.
Citing Bruce Evans:
The subdirectories contain results of old runs:
{4,7}: FreeBSD-{4,7} with old tests (only state 0 and 6b have different
expectations; state 0 fails in FreeBSD-4 so the above is wrong
about at least when it was broken. I thought that I fixed it
completely for select() in FreeBSD-1. One or both of these states
were very broken in Net/2 and maybe in 4.4BSD-Lite*).
l: Linux-2.6.10 with old tests (only state 0 has different expectations)
m: my current version of FreeBSD with old tests (0 and 6b)
n: my previous version of FreeBSD with old tests (0 and 6b)

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected 0; got 0
ok 2 Pipe state 5: expected POLLIN; got POLLIN
ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
ok 4 Pipe state 6a: expected POLLHUP; got POLLHUP
ok 5 Sock state 4: expected 0; got 0
ok 6 Sock state 5: expected POLLIN; got POLLIN
ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
not ok 8 Sock state 6a: expected POLLHUP; got POLLIN | POLLHUP
ok 9 FIFO state 0: expected 0; got 0
ok 10 FIFO state 1: expected 0; got 0
ok 11 FIFO state 2: expected POLLIN; got POLLIN
ok 12 FIFO state 2a: expected 0; got 0
ok 13 FIFO state 3: expected POLLHUP; got POLLHUP
ok 14 FIFO state 4: expected 0; got 0
ok 15 FIFO state 5: expected POLLIN; got POLLIN
ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
ok 17 FIFO state 6a: expected POLLHUP; got POLLHUP
not ok 18 FIFO state 6b: expected POLLHUP; got 0
ok 19 FIFO state 6c: expected POLLHUP; got POLLHUP
ok 20 FIFO state 6d: expected POLLHUP; got POLLHUP

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected clear; got clear
ok 2 Pipe state 5: expected set; got set
ok 3 Pipe state 6: expected set; got set
ok 4 Pipe state 6a: expected set; got set
ok 5 Sock state 4: expected clear; got clear
ok 6 Sock state 5: expected set; got set
ok 7 Sock state 6: expected set; got set
ok 8 Sock state 6a: expected set; got set
not ok 9 FIFO state 0: expected set; got clear
ok 10 FIFO state 1: expected clear; got clear
ok 11 FIFO state 2: expected set; got set
ok 12 FIFO state 2a: expected clear; got clear
ok 13 FIFO state 3: expected set; got set
ok 14 FIFO state 4: expected clear; got clear
ok 15 FIFO state 5: expected set; got set
ok 16 FIFO state 6: expected set; got set
ok 17 FIFO state 6a: expected set; got set
not ok 18 FIFO state 6b: expected set; got clear
ok 19 FIFO state 6c: expected set; got set
ok 20 FIFO state 6d: expected set; got set

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected 0; got 0
ok 2 Pipe state 5: expected POLLIN; got POLLIN
ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
ok 4 Pipe state 6a: expected POLLHUP; got POLLHUP
ok 5 Sock state 4: expected 0; got 0
ok 6 Sock state 5: expected POLLIN; got POLLIN
ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
ok 8 Sock state 6a: expected POLLHUP; got POLLHUP
ok 9 FIFO state 0: expected 0; got 0
ok 10 FIFO state 1: expected 0; got 0
ok 11 FIFO state 2: expected POLLIN; got POLLIN
ok 12 FIFO state 2a: expected 0; got 0
ok 13 FIFO state 3: expected POLLHUP; got POLLHUP
ok 14 FIFO state 4: expected 0; got 0
ok 15 FIFO state 5: expected POLLIN; got POLLIN
ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
ok 17 FIFO state 6a: expected POLLHUP; got POLLHUP
ok 18 FIFO state 6b: expected POLLHUP; got POLLHUP
ok 19 FIFO state 6c: expected POLLHUP; got POLLHUP
ok 20 FIFO state 6d: expected POLLHUP; got POLLHUP

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected clear; got clear
ok 2 Pipe state 5: expected set; got set
ok 3 Pipe state 6: expected set; got set
ok 4 Pipe state 6a: expected set; got set
ok 5 Sock state 4: expected clear; got clear
ok 6 Sock state 5: expected set; got set
ok 7 Sock state 6: expected set; got set
ok 8 Sock state 6a: expected set; got set
not ok 9 FIFO state 0: expected set; got clear
ok 10 FIFO state 1: expected clear; got clear
ok 11 FIFO state 2: expected set; got set
ok 12 FIFO state 2a: expected clear; got clear
ok 13 FIFO state 3: expected set; got set
ok 14 FIFO state 4: expected clear; got clear
ok 15 FIFO state 5: expected set; got set
ok 16 FIFO state 6: expected set; got set
ok 17 FIFO state 6a: expected set; got set
ok 18 FIFO state 6b: expected set; got set
ok 19 FIFO state 6c: expected set; got set
ok 20 FIFO state 6d: expected set; got set

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected 0; got 0
ok 2 Pipe state 5: expected POLLIN; got POLLIN
ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
ok 4 Pipe state 6a: expected POLLHUP; got POLLHUP
ok 5 Sock state 4: expected 0; got 0
ok 6 Sock state 5: expected POLLIN; got POLLIN
ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
ok 8 Sock state 6a: expected POLLHUP; got POLLHUP
ok 9 FIFO state 0: expected 0; got 0
ok 10 FIFO state 1: expected 0; got 0
ok 11 FIFO state 2: expected POLLIN; got POLLIN
ok 12 FIFO state 2a: expected 0; got 0
ok 13 FIFO state 3: expected POLLHUP; got POLLHUP
ok 14 FIFO state 4: expected 0; got 0
ok 15 FIFO state 5: expected POLLIN; got POLLIN
ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP
ok 17 FIFO state 6a: expected POLLHUP; got POLLHUP
ok 18 FIFO state 6b: expected 0; got 0
ok 19 FIFO state 6c: expected POLLHUP; got POLLHUP
ok 20 FIFO state 6d: expected POLLHUP; got POLLHUP

View File

@ -0,0 +1,21 @@
1..20
ok 1 Pipe state 4: expected clear; got clear
ok 2 Pipe state 5: expected set; got set
ok 3 Pipe state 6: expected set; got set
ok 4 Pipe state 6a: expected set; got set
ok 5 Sock state 4: expected clear; got clear
ok 6 Sock state 5: expected set; got set
ok 7 Sock state 6: expected set; got set
ok 8 Sock state 6a: expected set; got set
ok 9 FIFO state 0: expected clear; got clear
ok 10 FIFO state 1: expected clear; got clear
ok 11 FIFO state 2: expected set; got set
ok 12 FIFO state 2a: expected clear; got clear
ok 13 FIFO state 3: expected set; got set
ok 14 FIFO state 4: expected clear; got clear
ok 15 FIFO state 5: expected set; got set
ok 16 FIFO state 6: expected set; got set
ok 17 FIFO state 6a: expected set; got set
ok 18 FIFO state 6b: expected clear; got clear
ok 19 FIFO state 6c: expected set; got set
ok 20 FIFO state 6d: expected set; got set

View File

@ -0,0 +1,302 @@
/* $FreeBSD$ */
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define FIFONAME "fifo.tmp"
#define FT_END 3
#define FT_FIFO 2
#define FT_PIPE 0
#define FT_SOCKETPAIR 1
static int filetype;
static const char *
decode_events(int events)
{
char *ncresult;
const char *result;
switch (events) {
case POLLIN:
result = "POLLIN";
break;
case POLLHUP:
result = "POLLHUP";
break;
case POLLIN | POLLHUP:
result = "POLLIN | POLLHUP";
break;
default:
asprintf(&ncresult, "%#x", events);
result = ncresult;
break;
}
return (result);
}
static void
report(int num, const char *state, int expected, int got)
{
if (expected == got)
printf("ok %-2d ", num);
else
printf("not ok %-2d", num);
printf(" %s state %s: expected %s; got %s\n",
filetype == FT_PIPE ? "Pipe" :
filetype == FT_SOCKETPAIR ? "Sock" : "FIFO",
state, decode_events(expected), decode_events(got));
fflush(stdout);
}
static pid_t cpid;
static pid_t ppid;
static volatile sig_atomic_t state;
static void
catch(int sig)
{
state++;
}
static void
child(int fd, int num)
{
struct pollfd pfd;
int fd2;
char buf[256];
if (filetype == FT_FIFO) {
fd = open(FIFONAME, O_RDONLY | O_NONBLOCK);
if (fd < 0)
err(1, "open for read");
}
pfd.fd = fd;
pfd.events = POLLIN;
if (filetype == FT_FIFO) {
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "0", 0, pfd.revents);
}
kill(ppid, SIGUSR1);
usleep(1);
while (state != 1)
;
if (filetype != FT_FIFO) {
/*
* The connection cannot be reestablished. Use the code that
* delays the read until after the writer disconnects since
* that case is more interesting.
*/
state = 4;
goto state4;
}
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "1", 0, pfd.revents);
kill(ppid, SIGUSR1);
usleep(1);
while (state != 2)
;
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "2", POLLIN, pfd.revents);
if (read(fd, buf, sizeof buf) != 1)
err(1, "read");
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "2a", 0, pfd.revents);
kill(ppid, SIGUSR1);
usleep(1);
while (state != 3)
;
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "3", POLLHUP, pfd.revents);
kill(ppid, SIGUSR1);
/*
* Now we expect a new writer, and a new connection too since
* we read all the data. The only new point is that we didn't
* start quite from scratch since the read fd is not new. Check
* startup state as above, but don't do the read as above.
*/
usleep(1);
while (state != 4)
;
state4:
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "4", 0, pfd.revents);
kill(ppid, SIGUSR1);
usleep(1);
while (state != 5)
;
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "5", POLLIN, pfd.revents);
kill(ppid, SIGUSR1);
usleep(1);
while (state != 6)
;
/*
* Now we have no writer, but should still have data from the old
* writer. Check that we have both a data-readable condition and a
* hangup condition, and that the data can be read in the usual way.
* Since Linux does this, programs must not quit reading when they
* see POLLHUP; they must see POLLHUP without POLLIN (or another
* input condition) before they decide that there is EOF. gdb-6.1.1
* is an example of a broken program that quits on POLLHUP only --
* see its event-loop.c.
*/
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "6", POLLIN | POLLHUP, pfd.revents);
if (read(fd, buf, sizeof buf) != 1)
err(1, "read");
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "6a", POLLHUP, pfd.revents);
if (filetype == FT_FIFO) {
/*
* Check that POLLHUP is sticky for a new reader and for
* the old reader.
*/
fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK);
if (fd2 < 0)
err(1, "open for read");
pfd.fd = fd2;
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "6b", POLLHUP, pfd.revents);
pfd.fd = fd;
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "6c", POLLHUP, pfd.revents);
close(fd2);
if (poll(&pfd, 1, 0) < 0)
err(1, "poll");
report(num++, "6d", POLLHUP, pfd.revents);
}
close(fd);
kill(ppid, SIGUSR1);
exit(0);
}
static void
parent(int fd)
{
usleep(1);
while (state != 1)
;
if (filetype == FT_FIFO) {
fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
if (fd < 0)
err(1, "open for write");
}
kill(cpid, SIGUSR1);
usleep(1);
while (state != 2)
;
if (write(fd, "", 1) != 1)
err(1, "write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 3)
;
if (close(fd) != 0)
err(1, "close for write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 4)
;
if (filetype != FT_FIFO)
return;
fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
if (fd < 0)
err(1, "open for write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 5)
;
if (write(fd, "", 1) != 1)
err(1, "write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 6)
;
if (close(fd) != 0)
err(1, "close for write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 7)
;
}
int
main(void)
{
int fd[2], num;
num = 1;
printf("1..20\n");
fflush(stdout);
signal(SIGUSR1, catch);
ppid = getpid();
for (filetype = 0; filetype < FT_END; filetype++) {
switch (filetype) {
case FT_FIFO:
if (mkfifo(FIFONAME, 0666) != 0)
err(1, "mkfifo");
fd[0] = -1;
fd[1] = -1;
break;
case FT_SOCKETPAIR:
if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC,
fd) != 0)
err(1, "socketpair");
break;
case FT_PIPE:
if (pipe(fd) != 0)
err(1, "pipe");
break;
}
state = 0;
switch (cpid = fork()) {
case -1:
err(1, "fork");
case 0:
(void)close(fd[1]);
child(fd[0], num);
break;
default:
(void)close(fd[0]);
parent(fd[1]);
break;
}
num += filetype == FT_FIFO ? 12 : 4;
}
(void)unlink(FIFONAME);
return (0);
}

View File

@ -0,0 +1,318 @@
/* $FreeBSD$ */
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define FIFONAME "fifo.tmp"
#define FT_END 3
#define FT_FIFO 2
#define FT_PIPE 0
#define FT_SOCKETPAIR 1
#define SETUP(fd, rfds, tv) do { \
FD_ZERO(&(rfds)); \
FD_SET((fd), &(rfds)); \
(tv).tv_sec = 0; \
(tv).tv_usec = 0; \
} while (0)
static int filetype;
static const char *
decode_events(int events)
{
return (events ? "set" : "clear");
}
static void
report(int num, const char *state, int expected, int got)
{
if (!expected == !got)
printf("ok %-2d ", num);
else
printf("not ok %-2d", num);
printf(" %s state %s: expected %s; got %s\n",
filetype == FT_PIPE ? "Pipe" :
filetype == FT_SOCKETPAIR ? "Sock" : "FIFO",
state, decode_events(expected), decode_events(got));
fflush(stdout);
}
static pid_t cpid;
static pid_t ppid;
static volatile sig_atomic_t state;
static void
catch(int sig)
{
state++;
}
static void
child(int fd, int num)
{
fd_set rfds;
struct timeval tv;
int fd1, fd2;
char buf[256];
if (filetype == FT_FIFO) {
fd = open(FIFONAME, O_RDONLY | O_NONBLOCK);
if (fd < 0)
err(1, "open for read");
}
if (fd >= FD_SETSIZE)
errx(1, "fd = %d too large for select()", fd);
if (filetype == FT_FIFO) {
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
/*
* This state (a reader for which there has never been a
* writer) is reported quite differently for select() than
* for poll(). select() must see a ready-to-read descriptor
* since read() will see EOF and not block; it cannot
* distinguish this state from the one of a reader for which
* there has been a writer but all writers have gone away
* and all data has been read. poll() and distinguish these
* states by returning POLLHUP only for the latter; it does
* this, although this makes it inconsistent with the
* blockability of read() in the former.
*/
report(num++, "0", 1, FD_ISSET(fd, &rfds));
}
kill(ppid, SIGUSR1);
usleep(1);
while (state != 1)
;
if (filetype != FT_FIFO) {
/*
* The connection cannot be reestablished. Use the code that
* delays the read until after the writer disconnects since
* that case is more interesting.
*/
state = 4;
goto state4;
}
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "1", 0, FD_ISSET(fd, &rfds));
kill(ppid, SIGUSR1);
usleep(1);
while (state != 2)
;
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "2", 1, FD_ISSET(fd, &rfds));
if (read(fd, buf, sizeof buf) != 1)
err(1, "read");
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "2a", 0, FD_ISSET(fd, &rfds));
kill(ppid, SIGUSR1);
usleep(1);
while (state != 3)
;
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "3", 1, FD_ISSET(fd, &rfds));
kill(ppid, SIGUSR1);
/*
* Now we expect a new writer, and a new connection too since
* we read all the data. The only new point is that we didn't
* start quite from scratch since the read fd is not new. Check
* startup state as above, but don't do the read as above.
*/
usleep(1);
while (state != 4)
;
state4:
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "4", 0, FD_ISSET(fd, &rfds));
kill(ppid, SIGUSR1);
usleep(1);
while (state != 5)
;
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "5", 1, FD_ISSET(fd, &rfds));
kill(ppid, SIGUSR1);
usleep(1);
while (state != 6)
;
/*
* Now we have no writer, but should still have data from the old
* writer. Check that we have a data-readable condition, and that
* the data can be read in the usual way.
*/
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "6", 1, FD_ISSET(fd, &rfds));
if (read(fd, buf, sizeof buf) != 1)
err(1, "read");
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "6a", 1, FD_ISSET(fd, &rfds));
if (filetype == FT_FIFO) {
/*
* Check that the readable-data condition is sticky for a
* new reader and for the old reader. We really only have
* a hangup condition, but select() can only see this as
* a readable-data condition for null data. select()
* cannot distinguish this state from the initial state
* where there is a reader but has never been a writer, so
* the following tests (to follow the pattern in pipepoll.c)
* essentially test state 0 again.
*/
fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK);
if (fd2 < 0)
err(1, "open for read");
fd1 = fd;
fd = fd2;
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "6b", 1, FD_ISSET(fd, &rfds));
fd = fd1;
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "6c", 1, FD_ISSET(fd, &rfds));
close(fd2);
SETUP(fd, rfds, tv);
if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
err(1, "select");
report(num++, "6d", 1, FD_ISSET(fd, &rfds));
}
close(fd);
kill(ppid, SIGUSR1);
exit(0);
}
static void
parent(int fd)
{
usleep(1);
while (state != 1)
;
if (filetype == FT_FIFO) {
fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
if (fd < 0)
err(1, "open for write");
}
kill(cpid, SIGUSR1);
usleep(1);
while (state != 2)
;
if (write(fd, "", 1) != 1)
err(1, "write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 3)
;
if (close(fd) != 0)
err(1, "close for write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 4)
;
if (filetype != FT_FIFO)
return;
fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
if (fd < 0)
err(1, "open for write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 5)
;
if (write(fd, "", 1) != 1)
err(1, "write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 6)
;
if (close(fd) != 0)
err(1, "close for write");
kill(cpid, SIGUSR1);
usleep(1);
while (state != 7)
;
}
int
main(void)
{
int fd[2], num;
num = 1;
printf("1..20\n");
fflush(stdout);
signal(SIGUSR1, catch);
ppid = getpid();
for (filetype = 0; filetype < FT_END; filetype++) {
switch (filetype) {
case FT_FIFO:
if (mkfifo(FIFONAME, 0666) != 0)
err(1, "mkfifo");
fd[0] = -1;
fd[1] = -1;
break;
case FT_SOCKETPAIR:
if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC,
fd) != 0)
err(1, "socketpair");
break;
case FT_PIPE:
if (pipe(fd) != 0)
err(1, "pipe");
break;
}
state = 0;
switch (cpid = fork()) {
case -1:
err(1, "fork");
case 0:
(void)close(fd[1]);
child(fd[0], num);
break;
default:
(void)close(fd[0]);
parent(fd[1]);
break;
}
num += filetype == FT_FIFO ? 12 : 4;
}
(void)unlink(FIFONAME);
return (0);
}