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