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