1/*	$NetBSD: t_poll.c,v 1.3 2012/03/18 07:00:52 jruoho 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/time.h>
33#include <sys/wait.h>
34
35#include <atf-c.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <paths.h>
39#include <poll.h>
40#include <stdio.h>
41#include <signal.h>
42#include <unistd.h>
43
44static int desc;
45
46static void
47child1(void)
48{
49	struct pollfd pfd;
50
51	pfd.fd = desc;
52	pfd.events = POLLIN | POLLHUP | POLLOUT;
53
54	(void)poll(&pfd, 1, 2000);
55	(void)printf("child1 exit\n");
56}
57
58static void
59child2(void)
60{
61	struct pollfd pfd;
62
63	pfd.fd = desc;
64	pfd.events = POLLIN | POLLHUP | POLLOUT;
65
66	(void)sleep(1);
67	(void)poll(&pfd, 1, INFTIM);
68	(void)printf("child2 exit\n");
69}
70
71static void
72child3(void)
73{
74	struct pollfd pfd;
75
76	(void)sleep(5);
77
78	pfd.fd = desc;
79	pfd.events = POLLIN | POLLHUP | POLLOUT;
80
81	(void)poll(&pfd, 1, INFTIM);
82	(void)printf("child3 exit\n");
83}
84
85ATF_TC(poll_3way);
86ATF_TC_HEAD(poll_3way, tc)
87{
88	atf_tc_set_md_var(tc, "timeout", "15");
89	atf_tc_set_md_var(tc, "descr",
90	    "Check for 3-way collision for descriptor. First child comes "
91	    "and polls on descriptor, second child comes and polls, first "
92	    "child times out and exits, third child comes and polls. When "
93	    "the wakeup event happens, the two remaining children should "
94	    "both be awaken. (kern/17517)");
95}
96
97ATF_TC_BODY(poll_3way, tc)
98{
99	int pf[2];
100	int status, i;
101	pid_t pid;
102
103	pipe(pf);
104	desc = pf[0];
105
106	pid = fork();
107	ATF_REQUIRE(pid >= 0);
108
109	if (pid == 0) {
110		(void)close(pf[1]);
111		child1();
112		_exit(0);
113		/* NOTREACHED */
114	}
115
116	pid = fork();
117	ATF_REQUIRE(pid >= 0);
118
119	if (pid == 0) {
120		(void)close(pf[1]);
121		child2();
122		_exit(0);
123		/* NOTREACHED */
124	}
125
126	pid = fork();
127	ATF_REQUIRE( pid >= 0);
128
129	if (pid == 0) {
130		(void)close(pf[1]);
131		child3();
132		_exit(0);
133		/* NOTREACHED */
134	}
135
136	(void)sleep(10);
137
138	(void)printf("parent write\n");
139
140	ATF_REQUIRE(write(pf[1], "konec\n", 6) == 6);
141
142	for(i = 0; i < 3; ++i)
143		(void)wait(&status);
144
145	(void)printf("parent terminated\n");
146}
147
148ATF_TC(poll_basic);
149ATF_TC_HEAD(poll_basic, tc)
150{
151	atf_tc_set_md_var(tc, "timeout", "10");
152	atf_tc_set_md_var(tc, "descr",
153	    "Basis functionality test for poll(2)");
154}
155
156ATF_TC_BODY(poll_basic, tc)
157{
158	int fds[2];
159	struct pollfd pfds[2];
160	int ret;
161
162	ATF_REQUIRE_EQ(pipe(fds), 0);
163
164	pfds[0].fd = fds[0];
165	pfds[0].events = POLLIN;
166	pfds[1].fd = fds[1];
167	pfds[1].events = POLLOUT;
168
169	/*
170	 * Check that we get a timeout waiting for data on the read end
171	 * of our pipe.
172	 */
173	pfds[0].revents = -1;
174	pfds[1].revents = -1;
175	ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[0], 1, 1), 0,
176	    "got: %d", ret);
177	ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
178	ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents);
179
180	/* Check that the write end of the pipe as reported as ready. */
181	pfds[0].revents = -1;
182	pfds[1].revents = -1;
183	ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[1], 1, 1), 1,
184	    "got: %d", ret);
185	ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents);
186	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\
187	    pfds[1].revents);
188
189	/* Check that only the write end of the pipe as reported as ready. */
190	pfds[0].revents = -1;
191	pfds[1].revents = -1;
192	ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 1,
193	    "got: %d", ret);
194	ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
195	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
196	    pfds[1].revents);
197
198	/* Write data to our pipe. */
199	ATF_REQUIRE_EQ(write(fds[1], "", 1), 1);
200
201	/* Check that both ends of our pipe are reported as ready. */
202	pfds[0].revents = -1;
203	pfds[1].revents = -1;
204	ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 2,
205	    "got: %d", ret);
206	ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d",
207	    pfds[0].revents);
208	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
209	    pfds[1].revents);
210
211	ATF_REQUIRE_EQ(close(fds[0]), 0);
212	ATF_REQUIRE_EQ(close(fds[1]), 0);
213}
214
215ATF_TC(poll_err);
216ATF_TC_HEAD(poll_err, tc)
217{
218	atf_tc_set_md_var(tc, "descr", "Check errors from poll(2)");
219}
220
221ATF_TC_BODY(poll_err, tc)
222{
223	struct pollfd pfd;
224	int fd = 0;
225
226	pfd.fd = fd;
227	pfd.events = POLLIN;
228
229	errno = 0;
230	ATF_REQUIRE_ERRNO(EFAULT, poll((struct pollfd *)-1, 1, -1) == -1);
231
232	errno = 0;
233	ATF_REQUIRE_ERRNO(EINVAL, poll(&pfd, 1, -2) == -1);
234}
235
236#ifndef __FreeBSD__
237ATF_TC(pollts_basic);
238ATF_TC_HEAD(pollts_basic, tc)
239{
240	atf_tc_set_md_var(tc, "timeout", "10");
241	atf_tc_set_md_var(tc, "descr",
242	    "Basis functionality test for pollts(2)");
243}
244
245ATF_TC_BODY(pollts_basic, tc)
246{
247	int fds[2];
248	struct pollfd pfds[2];
249	struct timespec timeout;
250	int ret;
251
252	ATF_REQUIRE_EQ(pipe(fds), 0);
253
254	pfds[0].fd = fds[0];
255	pfds[0].events = POLLIN;
256	pfds[1].fd = fds[1];
257	pfds[1].events = POLLOUT;
258
259	/* Use a timeout of 1 second. */
260	timeout.tv_sec = 1;
261	timeout.tv_nsec = 0;
262
263	/*
264	 * Check that we get a timeout waiting for data on the read end
265	 * of our pipe.
266	 */
267	pfds[0].revents = -1;
268	pfds[1].revents = -1;
269	ATF_REQUIRE_EQ_MSG(ret = pollts(&pfds[0], 1, &timeout, NULL), 0,
270	    "got: %d", ret);
271	ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
272	ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents);
273
274	/* Check that the write end of the pipe as reported as ready. */
275	pfds[0].revents = -1;
276	pfds[1].revents = -1;
277	ATF_REQUIRE_EQ_MSG(ret = pollts(&pfds[1], 1, &timeout, NULL), 1,
278	    "got: %d", ret);
279	ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents);
280	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\
281	    pfds[1].revents);
282
283	/* Check that only the write end of the pipe as reported as ready. */
284	pfds[0].revents = -1;
285	pfds[1].revents = -1;
286	ATF_REQUIRE_EQ_MSG(ret = pollts(pfds, 2, &timeout, NULL), 1,
287	    "got: %d", ret);
288	ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
289	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
290	    pfds[1].revents);
291
292	/* Write data to our pipe. */
293	ATF_REQUIRE_EQ(write(fds[1], "", 1), 1);
294
295	/* Check that both ends of our pipe are reported as ready. */
296	pfds[0].revents = -1;
297	pfds[1].revents = -1;
298	ATF_REQUIRE_EQ_MSG(ret = pollts(pfds, 2, &timeout, NULL), 2,
299	    "got: %d", ret);
300	ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d",
301	    pfds[0].revents);
302	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
303	    pfds[1].revents);
304
305	ATF_REQUIRE_EQ(close(fds[0]), 0);
306	ATF_REQUIRE_EQ(close(fds[1]), 0);
307}
308
309ATF_TC(pollts_err);
310ATF_TC_HEAD(pollts_err, tc)
311{
312	atf_tc_set_md_var(tc, "descr", "Check errors from pollts(2)");
313}
314
315ATF_TC_BODY(pollts_err, tc)
316{
317	struct timespec timeout;
318	struct pollfd pfd;
319	int fd = 0;
320
321	pfd.fd = fd;
322	pfd.events = POLLIN;
323
324	timeout.tv_sec = 1;
325	timeout.tv_nsec = 0;
326
327	errno = 0;
328	ATF_REQUIRE_ERRNO(EFAULT, pollts((void *)-1, 1, &timeout, NULL) == -1);
329
330	timeout.tv_sec = -1;
331	timeout.tv_nsec = -1;
332
333	errno = 0;
334	ATF_REQUIRE_ERRNO(EINVAL, pollts(&pfd, 1, &timeout, NULL) == -1);
335}
336
337ATF_TC(pollts_sigmask);
338ATF_TC_HEAD(pollts_sigmask, tc)
339{
340	atf_tc_set_md_var(tc, "timeout", "10");
341	atf_tc_set_md_var(tc, "descr",
342	    "Check that pollts(2) restores the signal mask (PR kern/44986)");
343}
344
345ATF_TC_BODY(pollts_sigmask, tc)
346{
347	int fd;
348	struct pollfd pfd;
349	struct timespec timeout;
350	sigset_t mask;
351	int ret;
352
353	fd = open(_PATH_DEVNULL, O_RDONLY);
354	ATF_REQUIRE(fd >= 0);
355
356	pfd.fd = fd;
357	pfd.events = POLLIN;
358
359	/* Use a timeout of 1 second. */
360	timeout.tv_sec = 1;
361	timeout.tv_nsec = 0;
362
363	/* Unblock all signals. */
364	ATF_REQUIRE_EQ(sigfillset(&mask), 0);
365	ATF_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &mask, NULL), 0);
366
367	/*
368	 * Check that pollts(2) immediately returns. We block *all*
369	 * signals during pollts(2).
370	 */
371	ATF_REQUIRE_EQ_MSG(ret = pollts(&pfd, 1, &timeout, &mask), 1,
372	    "got: %d", ret);
373
374	/* Check that signals are now longer blocked. */
375	ATF_REQUIRE_EQ(sigprocmask(SIG_SETMASK, NULL, &mask), 0);
376	ATF_REQUIRE_EQ_MSG(sigismember(&mask, SIGUSR1), 0,
377	    "signal mask was changed.");
378
379	ATF_REQUIRE_EQ(close(fd), 0);
380}
381#endif
382
383ATF_TP_ADD_TCS(tp)
384{
385
386	ATF_TP_ADD_TC(tp, poll_3way);
387	ATF_TP_ADD_TC(tp, poll_basic);
388	ATF_TP_ADD_TC(tp, poll_err);
389#ifndef __FreeBSD__
390	ATF_TP_ADD_TC(tp, pollts_basic);
391	ATF_TP_ADD_TC(tp, pollts_err);
392	ATF_TP_ADD_TC(tp, pollts_sigmask);
393#endif
394
395	return atf_no_error();
396}
397