xref: /freebsd-src/tools/regression/poll/pipeselect.c (revision 2a63c3be158216222d89a073dcbd6a72ee4aab5a)
1*5861f966SKonstantin Belousov 
2*5861f966SKonstantin Belousov #include <sys/socket.h>
3*5861f966SKonstantin Belousov #include <sys/select.h>
4*5861f966SKonstantin Belousov #include <sys/stat.h>
5*5861f966SKonstantin Belousov 
6*5861f966SKonstantin Belousov #include <err.h>
7*5861f966SKonstantin Belousov #include <fcntl.h>
8*5861f966SKonstantin Belousov #include <signal.h>
9*5861f966SKonstantin Belousov #include <stdio.h>
10*5861f966SKonstantin Belousov #include <stdlib.h>
11*5861f966SKonstantin Belousov #include <unistd.h>
12*5861f966SKonstantin Belousov 
13*5861f966SKonstantin Belousov #define	FIFONAME	"fifo.tmp"
14*5861f966SKonstantin Belousov #define	FT_END		3
15*5861f966SKonstantin Belousov #define	FT_FIFO		2
16*5861f966SKonstantin Belousov #define	FT_PIPE		0
17*5861f966SKonstantin Belousov #define	FT_SOCKETPAIR	1
18*5861f966SKonstantin Belousov 
19*5861f966SKonstantin Belousov #define	SETUP(fd, rfds, tv) do {				\
20*5861f966SKonstantin Belousov 	FD_ZERO(&(rfds));					\
21*5861f966SKonstantin Belousov 	FD_SET((fd), &(rfds));					\
22*5861f966SKonstantin Belousov 	(tv).tv_sec = 0;					\
23*5861f966SKonstantin Belousov 	(tv).tv_usec = 0;					\
24*5861f966SKonstantin Belousov } while (0)
25*5861f966SKonstantin Belousov 
26*5861f966SKonstantin Belousov static int filetype;
27*5861f966SKonstantin Belousov 
28*5861f966SKonstantin Belousov static const char *
decode_events(int events)29*5861f966SKonstantin Belousov decode_events(int events)
30*5861f966SKonstantin Belousov {
31*5861f966SKonstantin Belousov 	return (events ? "set" : "clear");
32*5861f966SKonstantin Belousov }
33*5861f966SKonstantin Belousov 
34*5861f966SKonstantin Belousov static void
report(int num,const char * state,int expected,int got)35*5861f966SKonstantin Belousov report(int num, const char *state, int expected, int got)
36*5861f966SKonstantin Belousov {
37*5861f966SKonstantin Belousov 	if (!expected == !got)
38*5861f966SKonstantin Belousov 		printf("ok %-2d    ", num);
39*5861f966SKonstantin Belousov 	else
40*5861f966SKonstantin Belousov 		printf("not ok %-2d", num);
41*5861f966SKonstantin Belousov 	printf(" %s state %s: expected %s; got %s\n",
42*5861f966SKonstantin Belousov 	    filetype == FT_PIPE ? "Pipe" :
43*5861f966SKonstantin Belousov 	    filetype == FT_SOCKETPAIR ? "Sock" : "FIFO",
44*5861f966SKonstantin Belousov 	    state, decode_events(expected), decode_events(got));
45*5861f966SKonstantin Belousov 	fflush(stdout);
46*5861f966SKonstantin Belousov }
47*5861f966SKonstantin Belousov 
48*5861f966SKonstantin Belousov static pid_t cpid;
49*5861f966SKonstantin Belousov static pid_t ppid;
50*5861f966SKonstantin Belousov static volatile sig_atomic_t state;
51*5861f966SKonstantin Belousov 
52*5861f966SKonstantin Belousov static void
catch(int sig)53*5861f966SKonstantin Belousov catch(int sig)
54*5861f966SKonstantin Belousov {
55*5861f966SKonstantin Belousov 	state++;
56*5861f966SKonstantin Belousov }
57*5861f966SKonstantin Belousov 
58*5861f966SKonstantin Belousov static void
child(int fd,int num)59*5861f966SKonstantin Belousov child(int fd, int num)
60*5861f966SKonstantin Belousov {
61*5861f966SKonstantin Belousov 	fd_set rfds;
62*5861f966SKonstantin Belousov 	struct timeval tv;
63*5861f966SKonstantin Belousov 	int fd1, fd2;
64*5861f966SKonstantin Belousov 	char buf[256];
65*5861f966SKonstantin Belousov 
66*5861f966SKonstantin Belousov 	if (filetype == FT_FIFO) {
67*5861f966SKonstantin Belousov 		fd = open(FIFONAME, O_RDONLY | O_NONBLOCK);
68*5861f966SKonstantin Belousov 		if (fd < 0)
69*5861f966SKonstantin Belousov 			err(1, "open for read");
70*5861f966SKonstantin Belousov 	}
71*5861f966SKonstantin Belousov 	if (fd >= FD_SETSIZE)
72*5861f966SKonstantin Belousov 		errx(1, "fd = %d too large for select()", fd);
73*5861f966SKonstantin Belousov 
74*5861f966SKonstantin Belousov 	if (filetype == FT_FIFO) {
75*5861f966SKonstantin Belousov 		SETUP(fd, rfds, tv);
76*5861f966SKonstantin Belousov 		if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
77*5861f966SKonstantin Belousov 			err(1, "select");
78*5861f966SKonstantin Belousov 		/*
79*5861f966SKonstantin Belousov 		 * This state (a reader for which there has never been a
80*5861f966SKonstantin Belousov 		 * writer) is reported quite differently for select() than
81*5861f966SKonstantin Belousov 		 * for poll().  select() must see a ready-to-read descriptor
82*5861f966SKonstantin Belousov 		 * since read() will see EOF and not block; it cannot
83*5861f966SKonstantin Belousov 		 * distinguish this state from the one of a reader for which
84*5861f966SKonstantin Belousov 		 * there has been a writer but all writers have gone away
85*5861f966SKonstantin Belousov 		 * and all data has been read.  poll() and distinguish these
86*5861f966SKonstantin Belousov 		 * states by returning POLLHUP only for the latter; it does
87*5861f966SKonstantin Belousov 		 * this, although this makes it inconsistent with the
88*5861f966SKonstantin Belousov 		 * blockability of read() in the former.
89*5861f966SKonstantin Belousov 		 */
90*5861f966SKonstantin Belousov 		report(num++, "0", 1, FD_ISSET(fd, &rfds));
91*5861f966SKonstantin Belousov 	}
92*5861f966SKonstantin Belousov 	kill(ppid, SIGUSR1);
93*5861f966SKonstantin Belousov 
94*5861f966SKonstantin Belousov 	usleep(1);
95*5861f966SKonstantin Belousov 	while (state != 1)
96*5861f966SKonstantin Belousov 		;
97*5861f966SKonstantin Belousov 	if (filetype != FT_FIFO) {
98*5861f966SKonstantin Belousov 		/*
99*5861f966SKonstantin Belousov 		 * The connection cannot be reestablished.  Use the code that
100*5861f966SKonstantin Belousov 		 * delays the read until after the writer disconnects since
101*5861f966SKonstantin Belousov 		 * that case is more interesting.
102*5861f966SKonstantin Belousov 		 */
103*5861f966SKonstantin Belousov 		state = 4;
104*5861f966SKonstantin Belousov 		goto state4;
105*5861f966SKonstantin Belousov 	}
106*5861f966SKonstantin Belousov 	SETUP(fd, rfds, tv);
107*5861f966SKonstantin Belousov 	if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
108*5861f966SKonstantin Belousov 		err(1, "select");
109*5861f966SKonstantin Belousov 	report(num++, "1", 0, FD_ISSET(fd, &rfds));
110*5861f966SKonstantin Belousov 	kill(ppid, SIGUSR1);
111*5861f966SKonstantin Belousov 
112*5861f966SKonstantin Belousov 	usleep(1);
113*5861f966SKonstantin Belousov 	while (state != 2)
114*5861f966SKonstantin Belousov 		;
115*5861f966SKonstantin Belousov 	SETUP(fd, rfds, tv);
116*5861f966SKonstantin Belousov 	if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
117*5861f966SKonstantin Belousov 		err(1, "select");
118*5861f966SKonstantin Belousov 	report(num++, "2", 1, FD_ISSET(fd, &rfds));
119*5861f966SKonstantin Belousov 	if (read(fd, buf, sizeof buf) != 1)
120*5861f966SKonstantin Belousov 		err(1, "read");
121*5861f966SKonstantin Belousov 	SETUP(fd, rfds, tv);
122*5861f966SKonstantin Belousov 	if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
123*5861f966SKonstantin Belousov 		err(1, "select");
124*5861f966SKonstantin Belousov 	report(num++, "2a", 0, FD_ISSET(fd, &rfds));
125*5861f966SKonstantin Belousov 	kill(ppid, SIGUSR1);
126*5861f966SKonstantin Belousov 
127*5861f966SKonstantin Belousov 	usleep(1);
128*5861f966SKonstantin Belousov 	while (state != 3)
129*5861f966SKonstantin Belousov 		;
130*5861f966SKonstantin Belousov 	SETUP(fd, rfds, tv);
131*5861f966SKonstantin Belousov 	if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
132*5861f966SKonstantin Belousov 		err(1, "select");
133*5861f966SKonstantin Belousov 	report(num++, "3", 1, FD_ISSET(fd, &rfds));
134*5861f966SKonstantin Belousov 	kill(ppid, SIGUSR1);
135*5861f966SKonstantin Belousov 
136*5861f966SKonstantin Belousov 	/*
137*5861f966SKonstantin Belousov 	 * Now we expect a new writer, and a new connection too since
138*5861f966SKonstantin Belousov 	 * we read all the data.  The only new point is that we didn't
139*5861f966SKonstantin Belousov 	 * start quite from scratch since the read fd is not new.  Check
140*5861f966SKonstantin Belousov 	 * startup state as above, but don't do the read as above.
141*5861f966SKonstantin Belousov 	 */
142*5861f966SKonstantin Belousov 	usleep(1);
143*5861f966SKonstantin Belousov 	while (state != 4)
144*5861f966SKonstantin Belousov 		;
145*5861f966SKonstantin Belousov state4:
146*5861f966SKonstantin Belousov 	SETUP(fd, rfds, tv);
147*5861f966SKonstantin Belousov 	if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
148*5861f966SKonstantin Belousov 		err(1, "select");
149*5861f966SKonstantin Belousov 	report(num++, "4", 0, FD_ISSET(fd, &rfds));
150*5861f966SKonstantin Belousov 	kill(ppid, SIGUSR1);
151*5861f966SKonstantin Belousov 
152*5861f966SKonstantin Belousov 	usleep(1);
153*5861f966SKonstantin Belousov 	while (state != 5)
154*5861f966SKonstantin Belousov 		;
155*5861f966SKonstantin Belousov 	SETUP(fd, rfds, tv);
156*5861f966SKonstantin Belousov 	if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
157*5861f966SKonstantin Belousov 		err(1, "select");
158*5861f966SKonstantin Belousov 	report(num++, "5", 1, FD_ISSET(fd, &rfds));
159*5861f966SKonstantin Belousov 	kill(ppid, SIGUSR1);
160*5861f966SKonstantin Belousov 
161*5861f966SKonstantin Belousov 	usleep(1);
162*5861f966SKonstantin Belousov 	while (state != 6)
163*5861f966SKonstantin Belousov 		;
164*5861f966SKonstantin Belousov 	/*
165*5861f966SKonstantin Belousov 	 * Now we have no writer, but should still have data from the old
166*5861f966SKonstantin Belousov 	 * writer.  Check that we have a data-readable condition, and that
167*5861f966SKonstantin Belousov 	 * the data can be read in the usual way.
168*5861f966SKonstantin Belousov 	 */
169*5861f966SKonstantin Belousov 	SETUP(fd, rfds, tv);
170*5861f966SKonstantin Belousov 	if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
171*5861f966SKonstantin Belousov 		err(1, "select");
172*5861f966SKonstantin Belousov 	report(num++, "6", 1, FD_ISSET(fd, &rfds));
173*5861f966SKonstantin Belousov 	if (read(fd, buf, sizeof buf) != 1)
174*5861f966SKonstantin Belousov 		err(1, "read");
175*5861f966SKonstantin Belousov 	SETUP(fd, rfds, tv);
176*5861f966SKonstantin Belousov 	if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
177*5861f966SKonstantin Belousov 		err(1, "select");
178*5861f966SKonstantin Belousov 	report(num++, "6a", 1, FD_ISSET(fd, &rfds));
179*5861f966SKonstantin Belousov 	if (filetype == FT_FIFO) {
180*5861f966SKonstantin Belousov 		/*
181*5861f966SKonstantin Belousov 		 * Check that the readable-data condition is sticky for a
182*5861f966SKonstantin Belousov 		 * new reader and for the old reader.  We really only have
183*5861f966SKonstantin Belousov 		 * a hangup condition, but select() can only see this as
184*5861f966SKonstantin Belousov 		 * a readable-data condition for null data.  select()
185*5861f966SKonstantin Belousov 		 * cannot distinguish this state from the initial state
186*5861f966SKonstantin Belousov 		 * where there is a reader but has never been a writer, so
187*5861f966SKonstantin Belousov 		 * the following tests (to follow the pattern in pipepoll.c)
188*5861f966SKonstantin Belousov 		 * essentially test state 0 again.
189*5861f966SKonstantin Belousov 		 */
190*5861f966SKonstantin Belousov 		fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK);
191*5861f966SKonstantin Belousov 		if (fd2 < 0)
192*5861f966SKonstantin Belousov 			err(1, "open for read");
193*5861f966SKonstantin Belousov 		fd1 = fd;
194*5861f966SKonstantin Belousov 		fd = fd2;
195*5861f966SKonstantin Belousov 		SETUP(fd, rfds, tv);
196*5861f966SKonstantin Belousov 		if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
197*5861f966SKonstantin Belousov 			err(1, "select");
198*5861f966SKonstantin Belousov 		report(num++, "6b", 1, FD_ISSET(fd, &rfds));
199*5861f966SKonstantin Belousov 		fd = fd1;
200*5861f966SKonstantin Belousov 		SETUP(fd, rfds, tv);
201*5861f966SKonstantin Belousov 		if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
202*5861f966SKonstantin Belousov 			err(1, "select");
203*5861f966SKonstantin Belousov 		report(num++, "6c", 1, FD_ISSET(fd, &rfds));
204*5861f966SKonstantin Belousov 		close(fd2);
205*5861f966SKonstantin Belousov 		SETUP(fd, rfds, tv);
206*5861f966SKonstantin Belousov 		if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
207*5861f966SKonstantin Belousov 			err(1, "select");
208*5861f966SKonstantin Belousov 		report(num++, "6d", 1, FD_ISSET(fd, &rfds));
209*5861f966SKonstantin Belousov 	}
210*5861f966SKonstantin Belousov 	close(fd);
211*5861f966SKonstantin Belousov 	kill(ppid, SIGUSR1);
212*5861f966SKonstantin Belousov 
213*5861f966SKonstantin Belousov 	exit(0);
214*5861f966SKonstantin Belousov }
215*5861f966SKonstantin Belousov 
216*5861f966SKonstantin Belousov static void
parent(int fd)217*5861f966SKonstantin Belousov parent(int fd)
218*5861f966SKonstantin Belousov {
219*5861f966SKonstantin Belousov 	usleep(1);
220*5861f966SKonstantin Belousov 	while (state != 1)
221*5861f966SKonstantin Belousov 		;
222*5861f966SKonstantin Belousov 	if (filetype == FT_FIFO) {
223*5861f966SKonstantin Belousov 		fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
224*5861f966SKonstantin Belousov 		if (fd < 0)
225*5861f966SKonstantin Belousov 			err(1, "open for write");
226*5861f966SKonstantin Belousov 	}
227*5861f966SKonstantin Belousov 	kill(cpid, SIGUSR1);
228*5861f966SKonstantin Belousov 
229*5861f966SKonstantin Belousov 	usleep(1);
230*5861f966SKonstantin Belousov 	while (state != 2)
231*5861f966SKonstantin Belousov 		;
232*5861f966SKonstantin Belousov 	if (write(fd, "", 1) != 1)
233*5861f966SKonstantin Belousov 		err(1, "write");
234*5861f966SKonstantin Belousov 	kill(cpid, SIGUSR1);
235*5861f966SKonstantin Belousov 
236*5861f966SKonstantin Belousov 	usleep(1);
237*5861f966SKonstantin Belousov 	while (state != 3)
238*5861f966SKonstantin Belousov 		;
239*5861f966SKonstantin Belousov 	if (close(fd) != 0)
240*5861f966SKonstantin Belousov 		err(1, "close for write");
241*5861f966SKonstantin Belousov 	kill(cpid, SIGUSR1);
242*5861f966SKonstantin Belousov 
243*5861f966SKonstantin Belousov 	usleep(1);
244*5861f966SKonstantin Belousov 	while (state != 4)
245*5861f966SKonstantin Belousov 		;
246*5861f966SKonstantin Belousov 	if (filetype != FT_FIFO)
247*5861f966SKonstantin Belousov 		return;
248*5861f966SKonstantin Belousov 	fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
249*5861f966SKonstantin Belousov 	if (fd < 0)
250*5861f966SKonstantin Belousov 		err(1, "open for write");
251*5861f966SKonstantin Belousov 	kill(cpid, SIGUSR1);
252*5861f966SKonstantin Belousov 
253*5861f966SKonstantin Belousov 	usleep(1);
254*5861f966SKonstantin Belousov 	while (state != 5)
255*5861f966SKonstantin Belousov 		;
256*5861f966SKonstantin Belousov 	if (write(fd, "", 1) != 1)
257*5861f966SKonstantin Belousov 		err(1, "write");
258*5861f966SKonstantin Belousov 	kill(cpid, SIGUSR1);
259*5861f966SKonstantin Belousov 
260*5861f966SKonstantin Belousov 	usleep(1);
261*5861f966SKonstantin Belousov 	while (state != 6)
262*5861f966SKonstantin Belousov 		;
263*5861f966SKonstantin Belousov 	if (close(fd) != 0)
264*5861f966SKonstantin Belousov 		err(1, "close for write");
265*5861f966SKonstantin Belousov 	kill(cpid, SIGUSR1);
266*5861f966SKonstantin Belousov 
267*5861f966SKonstantin Belousov 	usleep(1);
268*5861f966SKonstantin Belousov 	while (state != 7)
269*5861f966SKonstantin Belousov 		;
270*5861f966SKonstantin Belousov }
271*5861f966SKonstantin Belousov 
272*5861f966SKonstantin Belousov int
main(void)273*5861f966SKonstantin Belousov main(void)
274*5861f966SKonstantin Belousov {
275*5861f966SKonstantin Belousov 	int fd[2], num;
276*5861f966SKonstantin Belousov 
277*5861f966SKonstantin Belousov 	num = 1;
278*5861f966SKonstantin Belousov 	printf("1..20\n");
279*5861f966SKonstantin Belousov 	fflush(stdout);
280*5861f966SKonstantin Belousov 	signal(SIGUSR1, catch);
281*5861f966SKonstantin Belousov 	ppid = getpid();
282*5861f966SKonstantin Belousov 	for (filetype = 0; filetype < FT_END; filetype++) {
283*5861f966SKonstantin Belousov 		switch (filetype) {
284*5861f966SKonstantin Belousov 		case FT_FIFO:
285*5861f966SKonstantin Belousov 			if (mkfifo(FIFONAME, 0666) != 0)
286*5861f966SKonstantin Belousov 				err(1, "mkfifo");
287*5861f966SKonstantin Belousov 			fd[0] = -1;
288*5861f966SKonstantin Belousov 			fd[1] = -1;
289*5861f966SKonstantin Belousov 			break;
290*5861f966SKonstantin Belousov 		case FT_SOCKETPAIR:
291*5861f966SKonstantin Belousov 			if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC,
292*5861f966SKonstantin Belousov 			    fd) != 0)
293*5861f966SKonstantin Belousov 				err(1, "socketpair");
294*5861f966SKonstantin Belousov 			break;
295*5861f966SKonstantin Belousov 		case FT_PIPE:
296*5861f966SKonstantin Belousov 			if (pipe(fd) != 0)
297*5861f966SKonstantin Belousov 				err(1, "pipe");
298*5861f966SKonstantin Belousov 			break;
299*5861f966SKonstantin Belousov 		}
300*5861f966SKonstantin Belousov 		state = 0;
301*5861f966SKonstantin Belousov 		switch (cpid = fork()) {
302*5861f966SKonstantin Belousov 		case -1:
303*5861f966SKonstantin Belousov 			err(1, "fork");
304*5861f966SKonstantin Belousov 		case 0:
305*5861f966SKonstantin Belousov 			(void)close(fd[1]);
306*5861f966SKonstantin Belousov 			child(fd[0], num);
307*5861f966SKonstantin Belousov 			break;
308*5861f966SKonstantin Belousov 		default:
309*5861f966SKonstantin Belousov 			(void)close(fd[0]);
310*5861f966SKonstantin Belousov 			parent(fd[1]);
311*5861f966SKonstantin Belousov 			break;
312*5861f966SKonstantin Belousov 		}
313*5861f966SKonstantin Belousov 		num += filetype == FT_FIFO ? 12 : 4;
314*5861f966SKonstantin Belousov 	}
315*5861f966SKonstantin Belousov 	(void)unlink(FIFONAME);
316*5861f966SKonstantin Belousov 	return (0);
317*5861f966SKonstantin Belousov }
318