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