1/*	$NetBSD: t_poll.c,v 1.8 2021/10/02 17:32:55 thorpej Exp $	*/
2
3/*-
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthias Scheler.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/wait.h>
35
36#include <atf-c.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <paths.h>
40#include <poll.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <signal.h>
44#include <unistd.h>
45
46static int desc;
47
48static void
49child1(void)
50{
51	struct pollfd pfd;
52
53	pfd.fd = desc;
54	pfd.events = POLLIN | POLLHUP | POLLOUT;
55
56	(void)poll(&pfd, 1, 2000);
57	(void)printf("child1 exit\n");
58}
59
60static void
61child2(void)
62{
63	struct pollfd pfd;
64
65	pfd.fd = desc;
66	pfd.events = POLLIN | POLLHUP | POLLOUT;
67
68	(void)sleep(1);
69	(void)poll(&pfd, 1, INFTIM);
70	(void)printf("child2 exit\n");
71}
72
73static void
74child3(void)
75{
76	struct pollfd pfd;
77
78	(void)sleep(5);
79
80	pfd.fd = desc;
81	pfd.events = POLLIN | POLLHUP | POLLOUT;
82
83	(void)poll(&pfd, 1, INFTIM);
84	(void)printf("child3 exit\n");
85}
86
87ATF_TC(3way);
88ATF_TC_HEAD(3way, tc)
89{
90	atf_tc_set_md_var(tc, "timeout", "15");
91	atf_tc_set_md_var(tc, "descr",
92	    "Check for 3-way collision for descriptor. First child comes "
93	    "and polls on descriptor, second child comes and polls, first "
94	    "child times out and exits, third child comes and polls. When "
95	    "the wakeup event happens, the two remaining children should "
96	    "both be awaken. (kern/17517)");
97}
98
99ATF_TC_BODY(3way, tc)
100{
101	int pf[2];
102	int status, i;
103	pid_t pid;
104
105	pipe(pf);
106	desc = pf[0];
107
108	pid = fork();
109	ATF_REQUIRE(pid >= 0);
110
111	if (pid == 0) {
112		(void)close(pf[1]);
113		child1();
114		_exit(0);
115		/* NOTREACHED */
116	}
117
118	pid = fork();
119	ATF_REQUIRE(pid >= 0);
120
121	if (pid == 0) {
122		(void)close(pf[1]);
123		child2();
124		_exit(0);
125		/* NOTREACHED */
126	}
127
128	pid = fork();
129	ATF_REQUIRE( pid >= 0);
130
131	if (pid == 0) {
132		(void)close(pf[1]);
133		child3();
134		_exit(0);
135		/* NOTREACHED */
136	}
137
138	(void)sleep(10);
139
140	(void)printf("parent write\n");
141
142	ATF_REQUIRE(write(pf[1], "konec\n", 6) == 6);
143
144	for(i = 0; i < 3; ++i)
145		(void)wait(&status);
146
147	(void)printf("parent terminated\n");
148}
149
150ATF_TC(basic);
151ATF_TC_HEAD(basic, tc)
152{
153	atf_tc_set_md_var(tc, "timeout", "10");
154	atf_tc_set_md_var(tc, "descr",
155	    "Basis functionality test for poll(2)");
156}
157
158ATF_TC_BODY(basic, tc)
159{
160	int fds[2];
161	struct pollfd pfds[2];
162	int ret;
163
164	ATF_REQUIRE_EQ(pipe(fds), 0);
165
166	pfds[0].fd = fds[0];
167	pfds[0].events = POLLIN;
168	pfds[1].fd = fds[1];
169	pfds[1].events = POLLOUT;
170
171	/*
172	 * Check that we get a timeout waiting for data on the read end
173	 * of our pipe.
174	 */
175	pfds[0].revents = -1;
176	pfds[1].revents = -1;
177	ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[0], 1, 1), 0,
178	    "got: %d", ret);
179	ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
180	ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents);
181
182	/* Check that the write end of the pipe as reported as ready. */
183	pfds[0].revents = -1;
184	pfds[1].revents = -1;
185	ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[1], 1, 1), 1,
186	    "got: %d", ret);
187	ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents);
188	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\
189	    pfds[1].revents);
190
191	/* Check that only the write end of the pipe as reported as ready. */
192	pfds[0].revents = -1;
193	pfds[1].revents = -1;
194	ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 1,
195	    "got: %d", ret);
196	ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
197	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
198	    pfds[1].revents);
199
200	/* Write data to our pipe. */
201	ATF_REQUIRE_EQ(write(fds[1], "", 1), 1);
202
203	/* Check that both ends of our pipe are reported as ready. */
204	pfds[0].revents = -1;
205	pfds[1].revents = -1;
206	ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 2,
207	    "got: %d", ret);
208	ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d",
209	    pfds[0].revents);
210	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
211	    pfds[1].revents);
212
213	ATF_REQUIRE_EQ(close(fds[0]), 0);
214	ATF_REQUIRE_EQ(close(fds[1]), 0);
215}
216
217ATF_TC(err);
218ATF_TC_HEAD(err, tc)
219{
220	atf_tc_set_md_var(tc, "descr", "Check errors from poll(2)");
221}
222
223ATF_TC_BODY(err, tc)
224{
225	struct pollfd pfd;
226	int fd = 0;
227
228	pfd.fd = fd;
229	pfd.events = POLLIN;
230
231	errno = 0;
232	ATF_REQUIRE_ERRNO(EFAULT, poll((struct pollfd *)-1, 1, -1) == -1);
233
234	errno = 0;
235	ATF_REQUIRE_ERRNO(EINVAL, poll(&pfd, 1, -2) == -1);
236}
237
238static const char	fifo_path[] = "pollhup_fifo";
239
240static void
241fifo_support(void)
242{
243	errno = 0;
244	if (mkfifo(fifo_path, 0600) == 0) {
245		ATF_REQUIRE(unlink(fifo_path) == 0);
246		return;
247	}
248
249	if (errno == EOPNOTSUPP) {
250		atf_tc_skip("the kernel does not support FIFOs");
251	} else {
252		atf_tc_fail("mkfifo(2) failed");
253	}
254}
255
256ATF_TC_WITH_CLEANUP(fifo_inout);
257ATF_TC_HEAD(fifo_inout, tc)
258{
259	atf_tc_set_md_var(tc, "descr",
260	    "Check POLLIN/POLLOUT behavior with fifos");
261}
262
263ATF_TC_BODY(fifo_inout, tc)
264{
265	struct pollfd pfd[2];
266	char *buf;
267	int rfd, wfd;
268	long pipe_buf;
269
270	fifo_support();
271
272	ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
273	ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
274	ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY | O_NONBLOCK)) >= 0);
275
276	/* Get the maximum atomic pipe write size. */
277	pipe_buf = fpathconf(wfd, _PC_PIPE_BUF);
278	ATF_REQUIRE(pipe_buf > 1);
279
280	buf = malloc(pipe_buf);
281	ATF_REQUIRE(buf != NULL);
282
283	memset(&pfd, 0, sizeof(pfd));
284	pfd[0].fd = rfd;
285	pfd[0].events = POLLIN | POLLRDNORM;
286	pfd[1].fd = wfd;
287	pfd[1].events = POLLOUT | POLLWRNORM;
288
289	/* We expect the FIFO to be writable but not readable. */
290	ATF_REQUIRE(poll(pfd, 2, 0) == 1);
291	ATF_REQUIRE(pfd[0].revents == 0);
292	ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
293
294	/* Write a single byte of data into the FIFO. */
295	ATF_REQUIRE(write(wfd, buf, 1) == 1);
296
297	/* We expect the FIFO to be readable and writable. */
298	ATF_REQUIRE(poll(pfd, 2, 0) == 2);
299	ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
300	ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
301
302	/* Read that single byte back out. */
303	ATF_REQUIRE(read(rfd, buf, 1) == 1);
304
305	/*
306	 * Write data into the FIFO until it is full, which is
307	 * defined as insufficient buffer space to hold a the
308	 * maximum atomic pipe write size.
309	 */
310	while (write(wfd, buf, pipe_buf) != -1) {
311		continue;
312	}
313	ATF_REQUIRE(errno == EAGAIN);
314
315	/* We expect the FIFO to be readble but not writable. */
316	ATF_REQUIRE(poll(pfd, 2, 0) == 1);
317	ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
318	ATF_REQUIRE(pfd[1].revents == 0);
319
320	/* Read a single byte of data from the FIFO. */
321	ATF_REQUIRE(read(rfd, buf, 1) == 1);
322
323	/*
324	 * Because we have read only a single byte out, there will
325	 * be insufficient space for a pipe_buf-sized message, so
326	 * the FIFO should still not be writable.
327	 */
328	ATF_REQUIRE(poll(pfd, 2, 0) == 1);
329	ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
330	ATF_REQUIRE(pfd[1].revents == 0);
331
332	/*
333	 * Now read enough so that exactly pipe_buf space should
334	 * be available.  The FIFO should be writable after that.
335	 * N.B. we don't care if it's readable at this point.
336	 */
337	ATF_REQUIRE(read(rfd, buf, pipe_buf - 1) == pipe_buf - 1);
338	ATF_REQUIRE(poll(pfd, 2, 0) >= 1);
339	ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
340
341	/*
342	 * Now read all of the data out of the FIFO and ensure that
343	 * we get back to the initial state.
344	 */
345	while (read(rfd, buf, pipe_buf) != -1) {
346		continue;
347	}
348	ATF_REQUIRE(errno == EAGAIN);
349
350	ATF_REQUIRE(poll(pfd, 2, 0) == 1);
351	ATF_REQUIRE(pfd[0].revents == 0);
352	ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
353
354	(void)close(wfd);
355	(void)close(rfd);
356}
357
358ATF_TC_CLEANUP(fifo_inout, tc)
359{
360	(void)unlink(fifo_path);
361}
362
363ATF_TC_WITH_CLEANUP(fifo_hup1);
364ATF_TC_HEAD(fifo_hup1, tc)
365{
366	atf_tc_set_md_var(tc, "descr",
367	    "Check POLLHUP behavior with fifos [1]");
368}
369
370ATF_TC_BODY(fifo_hup1, tc)
371{
372	struct pollfd pfd;
373	int rfd, wfd;
374
375	fifo_support();
376
377	ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
378	ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
379	ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
380
381	memset(&pfd, 0, sizeof(pfd));
382	pfd.fd = rfd;
383	pfd.events = POLLIN;
384
385	(void)close(wfd);
386
387	ATF_REQUIRE(poll(&pfd, 1, 0) == 1);
388	ATF_REQUIRE((pfd.revents & POLLHUP) != 0);
389
390	/*
391	 * Check that POLLHUP is cleared when a writer re-connects.
392	 * Since the writer will not put any data into the FIFO, we
393	 * expect no events.
394	 */
395	memset(&pfd, 0, sizeof(pfd));
396	pfd.fd = rfd;
397	pfd.events = POLLIN;
398
399	ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
400	ATF_REQUIRE(poll(&pfd, 1, 0) == 0);
401}
402
403ATF_TC_CLEANUP(fifo_hup1, tc)
404{
405	(void)unlink(fifo_path);
406}
407
408ATF_TC_WITH_CLEANUP(fifo_hup2);
409ATF_TC_HEAD(fifo_hup2, tc)
410{
411	atf_tc_set_md_var(tc, "descr",
412	    "Check POLLHUP behavior with fifos [2]");
413}
414
415ATF_TC_BODY(fifo_hup2, tc)
416{
417	struct pollfd pfd;
418	int rfd, wfd;
419	pid_t pid;
420	struct timespec ts1, ts2;
421
422	fifo_support();
423
424	ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
425	ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
426	ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
427
428	memset(&pfd, 0, sizeof(pfd));
429	pfd.fd = rfd;
430	pfd.events = POLLIN;
431
432	pid = fork();
433	ATF_REQUIRE(pid >= 0);
434
435	if (pid == 0) {
436		(void)close(rfd);
437		sleep(5);
438		(void)close(wfd);
439		_exit(0);
440	}
441	(void)close(wfd);
442
443	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts1) == 0);
444	ATF_REQUIRE(poll(&pfd, 1, INFTIM) == 1);
445	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts2) == 0);
446
447	/* Make sure at least a couple of seconds have elapsed. */
448	ATF_REQUIRE(ts2.tv_sec - ts1.tv_sec >= 2);
449
450	ATF_REQUIRE((pfd.revents & POLLHUP) != 0);
451}
452
453ATF_TC_CLEANUP(fifo_hup2, tc)
454{
455	(void)unlink(fifo_path);
456}
457
458ATF_TP_ADD_TCS(tp)
459{
460
461	ATF_TP_ADD_TC(tp, 3way);
462	ATF_TP_ADD_TC(tp, basic);
463	ATF_TP_ADD_TC(tp, err);
464
465	ATF_TP_ADD_TC(tp, fifo_inout);
466	ATF_TP_ADD_TC(tp, fifo_hup1);
467	ATF_TP_ADD_TC(tp, fifo_hup2);
468
469	return atf_no_error();
470}
471