1195636Skib/* $FreeBSD$ */
2195636Skib
3195636Skib#include <sys/poll.h>
4195636Skib#include <sys/socket.h>
5195636Skib#include <sys/stat.h>
6195636Skib
7195636Skib#include <err.h>
8195636Skib#include <fcntl.h>
9195636Skib#include <signal.h>
10195636Skib#include <stdio.h>
11195636Skib#include <stdlib.h>
12195636Skib#include <unistd.h>
13195636Skib
14195636Skib#define	FIFONAME	"fifo.tmp"
15195636Skib#define	FT_END		3
16195636Skib#define	FT_FIFO		2
17195636Skib#define	FT_PIPE		0
18195636Skib#define	FT_SOCKETPAIR	1
19195636Skib
20195636Skibstatic int filetype;
21195636Skib
22195636Skibstatic const char *
23195636Skibdecode_events(int events)
24195636Skib{
25195636Skib	char *ncresult;
26195636Skib	const char *result;
27195636Skib
28195636Skib	switch (events) {
29195636Skib	case POLLIN:
30195636Skib		result = "POLLIN";
31195636Skib		break;
32195636Skib	case POLLHUP:
33195636Skib		result = "POLLHUP";
34195636Skib		break;
35195636Skib	case POLLIN | POLLHUP:
36195636Skib		result = "POLLIN | POLLHUP";
37195636Skib		break;
38195636Skib	default:
39195636Skib		asprintf(&ncresult, "%#x", events);
40195636Skib		result = ncresult;
41195636Skib		break;
42195636Skib	}
43195636Skib	return (result);
44195636Skib}
45195636Skib
46195636Skibstatic void
47211940Skibreport_state(const char *state)
48195636Skib{
49211940Skib
50211940Skib	printf(" %s state %s: ",
51195636Skib	    filetype == FT_PIPE ? "Pipe" :
52195636Skib	    filetype == FT_SOCKETPAIR ? "Sock" : "FIFO",
53211940Skib	    state);
54211940Skib}
55211940Skib
56211940Skibstatic void
57211940Skibreport(int num, const char *state, int expected, int got, int res,
58211940Skib    int res_expected)
59211940Skib{
60211940Skib
61211940Skib	if (res != res_expected) {
62211940Skib		printf("not ok %-2d", num);
63211940Skib		report_state(state);
64211940Skib		printf("poll result %d expected %d. ",
65211940Skib		    res, res_expected);
66211940Skib	} else {
67211940Skib		if (expected == got)
68211940Skib			printf("ok %-2d    ", num);
69211940Skib		else
70211940Skib			printf("not ok %-2d", num);
71211940Skib		report_state(state);
72211940Skib	}
73211940Skib	printf("expected %s; got %s\n", decode_events(expected),
74211940Skib	    decode_events(got));
75195636Skib	fflush(stdout);
76195636Skib}
77195636Skib
78195636Skibstatic pid_t cpid;
79195636Skibstatic pid_t ppid;
80195636Skibstatic volatile sig_atomic_t state;
81195636Skib
82195636Skibstatic void
83211940Skibcatch(int sig __unused)
84195636Skib{
85211940Skib
86195636Skib	state++;
87195636Skib}
88195636Skib
89195636Skibstatic void
90195636Skibchild(int fd, int num)
91195636Skib{
92195636Skib	struct pollfd pfd;
93211940Skib	int fd2, res;
94195636Skib	char buf[256];
95195636Skib
96195636Skib	if (filetype == FT_FIFO) {
97195636Skib		fd = open(FIFONAME, O_RDONLY | O_NONBLOCK);
98195636Skib		if (fd < 0)
99195636Skib			err(1, "open for read");
100195636Skib	}
101195636Skib	pfd.fd = fd;
102195636Skib	pfd.events = POLLIN;
103195636Skib
104195636Skib	if (filetype == FT_FIFO) {
105211940Skib		if ((res = poll(&pfd, 1, 0)) < 0)
106195636Skib			err(1, "poll");
107211940Skib		report(num++, "0", 0, pfd.revents, res, 0);
108195636Skib	}
109195636Skib	kill(ppid, SIGUSR1);
110195636Skib
111195636Skib	usleep(1);
112195636Skib	while (state != 1)
113195636Skib		;
114195636Skib	if (filetype != FT_FIFO) {
115195636Skib		/*
116195636Skib		 * The connection cannot be reestablished.  Use the code that
117195636Skib		 * delays the read until after the writer disconnects since
118195636Skib		 * that case is more interesting.
119195636Skib		 */
120195636Skib		state = 4;
121195636Skib		goto state4;
122195636Skib	}
123211940Skib	if ((res = poll(&pfd, 1, 0)) < 0)
124195636Skib		err(1, "poll");
125211940Skib	report(num++, "1", 0, pfd.revents, res, 0);
126195636Skib	kill(ppid, SIGUSR1);
127195636Skib
128195636Skib	usleep(1);
129195636Skib	while (state != 2)
130195636Skib		;
131211940Skib	if ((res = poll(&pfd, 1, 0)) < 0)
132195636Skib		err(1, "poll");
133211940Skib	report(num++, "2", POLLIN, pfd.revents, res, 1);
134195636Skib	if (read(fd, buf, sizeof buf) != 1)
135195636Skib		err(1, "read");
136211940Skib	if ((res = poll(&pfd, 1, 0)) < 0)
137195636Skib		err(1, "poll");
138211940Skib	report(num++, "2a", 0, pfd.revents, res, 0);
139195636Skib	kill(ppid, SIGUSR1);
140195636Skib
141195636Skib	usleep(1);
142195636Skib	while (state != 3)
143195636Skib		;
144211940Skib	if ((res = poll(&pfd, 1, 0)) < 0)
145195636Skib		err(1, "poll");
146211940Skib	report(num++, "3", POLLHUP, pfd.revents, res, 1);
147195636Skib	kill(ppid, SIGUSR1);
148195636Skib
149195636Skib	/*
150195636Skib	 * Now we expect a new writer, and a new connection too since
151195636Skib	 * we read all the data.  The only new point is that we didn't
152195636Skib	 * start quite from scratch since the read fd is not new.  Check
153195636Skib	 * startup state as above, but don't do the read as above.
154195636Skib	 */
155195636Skib	usleep(1);
156195636Skib	while (state != 4)
157195636Skib		;
158195636Skibstate4:
159211940Skib	if ((res = poll(&pfd, 1, 0)) < 0)
160195636Skib		err(1, "poll");
161211940Skib	report(num++, "4", 0, pfd.revents, res, 0);
162195636Skib	kill(ppid, SIGUSR1);
163195636Skib
164195636Skib	usleep(1);
165195636Skib	while (state != 5)
166195636Skib		;
167211940Skib	if ((res = poll(&pfd, 1, 0)) < 0)
168195636Skib		err(1, "poll");
169211940Skib	report(num++, "5", POLLIN, pfd.revents, res, 1);
170195636Skib	kill(ppid, SIGUSR1);
171195636Skib
172195636Skib	usleep(1);
173195636Skib	while (state != 6)
174195636Skib		;
175195636Skib	/*
176195636Skib	 * Now we have no writer, but should still have data from the old
177195636Skib	 * writer.  Check that we have both a data-readable condition and a
178195636Skib	 * hangup condition, and that the data can be read in the usual way.
179195636Skib	 * Since Linux does this, programs must not quit reading when they
180195636Skib	 * see POLLHUP; they must see POLLHUP without POLLIN (or another
181195636Skib	 * input condition) before they decide that there is EOF.  gdb-6.1.1
182195636Skib	 * is an example of a broken program that quits on POLLHUP only --
183195636Skib	 * see its event-loop.c.
184195636Skib	 */
185211940Skib	if ((res = poll(&pfd, 1, 0)) < 0)
186195636Skib		err(1, "poll");
187211940Skib	report(num++, "6", POLLIN | POLLHUP, pfd.revents, res, 1);
188195636Skib	if (read(fd, buf, sizeof buf) != 1)
189195636Skib		err(1, "read");
190211940Skib	if ((res = poll(&pfd, 1, 0)) < 0)
191195636Skib		err(1, "poll");
192211940Skib	report(num++, "6a", POLLHUP, pfd.revents, res, 1);
193195636Skib	if (filetype == FT_FIFO) {
194195636Skib		/*
195195636Skib		 * Check that POLLHUP is sticky for a new reader and for
196195636Skib		 * the old reader.
197195636Skib		 */
198195636Skib		fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK);
199195636Skib		if (fd2 < 0)
200195636Skib			err(1, "open for read");
201195636Skib		pfd.fd = fd2;
202211940Skib		if ((res = poll(&pfd, 1, 0)) < 0)
203195636Skib			err(1, "poll");
204211940Skib		report(num++, "6b", POLLHUP, pfd.revents, res, 1);
205195636Skib		pfd.fd = fd;
206211940Skib		if ((res = poll(&pfd, 1, 0)) < 0)
207195636Skib			err(1, "poll");
208211940Skib		report(num++, "6c", POLLHUP, pfd.revents, res, 1);
209195636Skib		close(fd2);
210211940Skib		if ((res = poll(&pfd, 1, 0)) < 0)
211195636Skib			err(1, "poll");
212211940Skib		report(num++, "6d", POLLHUP, pfd.revents, res, 1);
213195636Skib	}
214195636Skib	close(fd);
215195636Skib	kill(ppid, SIGUSR1);
216195636Skib
217195636Skib	exit(0);
218195636Skib}
219195636Skib
220195636Skibstatic void
221195636Skibparent(int fd)
222195636Skib{
223195636Skib	usleep(1);
224195636Skib	while (state != 1)
225195636Skib		;
226195636Skib	if (filetype == FT_FIFO) {
227195636Skib		fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
228195636Skib		if (fd < 0)
229195636Skib			err(1, "open for write");
230195636Skib	}
231195636Skib	kill(cpid, SIGUSR1);
232195636Skib
233195636Skib	usleep(1);
234195636Skib	while (state != 2)
235195636Skib		;
236195636Skib	if (write(fd, "", 1) != 1)
237195636Skib		err(1, "write");
238195636Skib	kill(cpid, SIGUSR1);
239195636Skib
240195636Skib	usleep(1);
241195636Skib	while (state != 3)
242195636Skib		;
243195636Skib	if (close(fd) != 0)
244195636Skib		err(1, "close for write");
245195636Skib	kill(cpid, SIGUSR1);
246195636Skib
247195636Skib	usleep(1);
248195636Skib	while (state != 4)
249195636Skib		;
250195636Skib	if (filetype != FT_FIFO)
251195636Skib		return;
252195636Skib	fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
253195636Skib	if (fd < 0)
254195636Skib		err(1, "open for write");
255195636Skib	kill(cpid, SIGUSR1);
256195636Skib
257195636Skib	usleep(1);
258195636Skib	while (state != 5)
259195636Skib		;
260195636Skib	if (write(fd, "", 1) != 1)
261195636Skib		err(1, "write");
262195636Skib	kill(cpid, SIGUSR1);
263195636Skib
264195636Skib	usleep(1);
265195636Skib	while (state != 6)
266195636Skib		;
267195636Skib	if (close(fd) != 0)
268195636Skib		err(1, "close for write");
269195636Skib	kill(cpid, SIGUSR1);
270195636Skib
271195636Skib	usleep(1);
272195636Skib	while (state != 7)
273195636Skib		;
274195636Skib}
275195636Skib
276195636Skibint
277195636Skibmain(void)
278195636Skib{
279195636Skib	int fd[2], num;
280195636Skib
281195636Skib	num = 1;
282195636Skib	printf("1..20\n");
283195636Skib	fflush(stdout);
284195636Skib	signal(SIGUSR1, catch);
285195636Skib	ppid = getpid();
286195636Skib	for (filetype = 0; filetype < FT_END; filetype++) {
287195636Skib		switch (filetype) {
288195636Skib		case FT_FIFO:
289195636Skib			if (mkfifo(FIFONAME, 0666) != 0)
290195636Skib				err(1, "mkfifo");
291195636Skib			fd[0] = -1;
292195636Skib			fd[1] = -1;
293195636Skib			break;
294195636Skib		case FT_SOCKETPAIR:
295195636Skib			if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC,
296195636Skib			    fd) != 0)
297195636Skib				err(1, "socketpair");
298195636Skib			break;
299195636Skib		case FT_PIPE:
300195636Skib			if (pipe(fd) != 0)
301195636Skib				err(1, "pipe");
302195636Skib			break;
303195636Skib		}
304195636Skib		state = 0;
305195636Skib		switch (cpid = fork()) {
306195636Skib		case -1:
307195636Skib			err(1, "fork");
308195636Skib		case 0:
309195636Skib			(void)close(fd[1]);
310195636Skib			child(fd[0], num);
311195636Skib			break;
312195636Skib		default:
313195636Skib			(void)close(fd[0]);
314195636Skib			parent(fd[1]);
315195636Skib			break;
316195636Skib		}
317195636Skib		num += filetype == FT_FIFO ? 12 : 4;
318195636Skib	}
319195636Skib	(void)unlink(FIFONAME);
320195636Skib	return (0);
321195636Skib}
322