1*d5ba5019Smbuhl /* $OpenBSD: t_poll.c,v 1.3 2022/05/28 18:39:39 mbuhl Exp $ */
27496d4e5Sbluhm /* $NetBSD: t_poll.c,v 1.4 2020/07/17 15:34:16 kamil Exp $ */
3a545a52cSbluhm
4a545a52cSbluhm /*-
5a545a52cSbluhm * Copyright (c) 2011 The NetBSD Foundation, Inc.
6a545a52cSbluhm * All rights reserved.
7a545a52cSbluhm *
8a545a52cSbluhm * This code is derived from software contributed to The NetBSD Foundation
9a545a52cSbluhm * by Matthias Scheler.
10a545a52cSbluhm *
11a545a52cSbluhm * Redistribution and use in source and binary forms, with or without
12a545a52cSbluhm * modification, are permitted provided that the following conditions
13a545a52cSbluhm * are met:
14a545a52cSbluhm * 1. Redistributions of source code must retain the above copyright
15a545a52cSbluhm * notice, this list of conditions and the following disclaimer.
16a545a52cSbluhm * 2. Redistributions in binary form must reproduce the above copyright
17a545a52cSbluhm * notice, this list of conditions and the following disclaimer in the
18a545a52cSbluhm * documentation and/or other materials provided with the distribution.
19a545a52cSbluhm *
20a545a52cSbluhm * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21a545a52cSbluhm * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22a545a52cSbluhm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23a545a52cSbluhm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24a545a52cSbluhm * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25a545a52cSbluhm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26a545a52cSbluhm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27a545a52cSbluhm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28a545a52cSbluhm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29a545a52cSbluhm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30a545a52cSbluhm * POSSIBILITY OF SUCH DAMAGE.
31a545a52cSbluhm */
32a545a52cSbluhm
33a545a52cSbluhm #include "macros.h"
34a545a52cSbluhm
35a545a52cSbluhm #include <sys/time.h>
36a545a52cSbluhm #include <sys/wait.h>
37a545a52cSbluhm
38a545a52cSbluhm #include "atf-c.h"
39a545a52cSbluhm #include <errno.h>
40a545a52cSbluhm #include <fcntl.h>
41a545a52cSbluhm #include <paths.h>
42a545a52cSbluhm #include <poll.h>
43a545a52cSbluhm #include <stdio.h>
44a545a52cSbluhm #include <signal.h>
45a545a52cSbluhm #include <unistd.h>
46a545a52cSbluhm
47a545a52cSbluhm static int desc;
48a545a52cSbluhm
49a545a52cSbluhm static void
child1(void)50a545a52cSbluhm child1(void)
51a545a52cSbluhm {
52a545a52cSbluhm struct pollfd pfd;
53a545a52cSbluhm
54a545a52cSbluhm pfd.fd = desc;
55a545a52cSbluhm pfd.events = POLLIN | POLLHUP | POLLOUT;
56a545a52cSbluhm
57a545a52cSbluhm (void)poll(&pfd, 1, 2000);
58a545a52cSbluhm (void)printf("child1 exit\n");
59a545a52cSbluhm }
60a545a52cSbluhm
61a545a52cSbluhm static void
child2(void)62a545a52cSbluhm child2(void)
63a545a52cSbluhm {
64a545a52cSbluhm struct pollfd pfd;
65a545a52cSbluhm
66a545a52cSbluhm pfd.fd = desc;
67a545a52cSbluhm pfd.events = POLLIN | POLLHUP | POLLOUT;
68a545a52cSbluhm
69a545a52cSbluhm (void)sleep(1);
70a545a52cSbluhm (void)poll(&pfd, 1, INFTIM);
71a545a52cSbluhm (void)printf("child2 exit\n");
72a545a52cSbluhm }
73a545a52cSbluhm
74a545a52cSbluhm static void
child3(void)75a545a52cSbluhm child3(void)
76a545a52cSbluhm {
77a545a52cSbluhm struct pollfd pfd;
78a545a52cSbluhm
79a545a52cSbluhm (void)sleep(5);
80a545a52cSbluhm
81a545a52cSbluhm pfd.fd = desc;
82a545a52cSbluhm pfd.events = POLLIN | POLLHUP | POLLOUT;
83a545a52cSbluhm
84a545a52cSbluhm (void)poll(&pfd, 1, INFTIM);
85a545a52cSbluhm (void)printf("child3 exit\n");
86a545a52cSbluhm }
87a545a52cSbluhm
887496d4e5Sbluhm ATF_TC(3way);
897496d4e5Sbluhm ATF_TC_HEAD(3way, tc)
90a545a52cSbluhm {
91a545a52cSbluhm atf_tc_set_md_var(tc, "timeout", "15");
92a545a52cSbluhm atf_tc_set_md_var(tc, "descr",
93a545a52cSbluhm "Check for 3-way collision for descriptor. First child comes "
94a545a52cSbluhm "and polls on descriptor, second child comes and polls, first "
95a545a52cSbluhm "child times out and exits, third child comes and polls. When "
96a545a52cSbluhm "the wakeup event happens, the two remaining children should "
97a545a52cSbluhm "both be awaken. (kern/17517)");
98a545a52cSbluhm }
99a545a52cSbluhm
1007496d4e5Sbluhm ATF_TC_BODY(3way, tc)
101a545a52cSbluhm {
102a545a52cSbluhm int pf[2];
103a545a52cSbluhm int status, i;
104a545a52cSbluhm pid_t pid;
105a545a52cSbluhm
106a545a52cSbluhm pipe(pf);
107a545a52cSbluhm desc = pf[0];
108a545a52cSbluhm
109a545a52cSbluhm pid = fork();
110a545a52cSbluhm ATF_REQUIRE(pid >= 0);
111a545a52cSbluhm
112a545a52cSbluhm if (pid == 0) {
113a545a52cSbluhm (void)close(pf[1]);
114a545a52cSbluhm child1();
115a545a52cSbluhm _exit(0);
116a545a52cSbluhm /* NOTREACHED */
117a545a52cSbluhm }
118a545a52cSbluhm
119a545a52cSbluhm pid = fork();
120a545a52cSbluhm ATF_REQUIRE(pid >= 0);
121a545a52cSbluhm
122a545a52cSbluhm if (pid == 0) {
123a545a52cSbluhm (void)close(pf[1]);
124a545a52cSbluhm child2();
125a545a52cSbluhm _exit(0);
126a545a52cSbluhm /* NOTREACHED */
127a545a52cSbluhm }
128a545a52cSbluhm
129a545a52cSbluhm pid = fork();
130a545a52cSbluhm ATF_REQUIRE( pid >= 0);
131a545a52cSbluhm
132a545a52cSbluhm if (pid == 0) {
133a545a52cSbluhm (void)close(pf[1]);
134a545a52cSbluhm child3();
135a545a52cSbluhm _exit(0);
136a545a52cSbluhm /* NOTREACHED */
137a545a52cSbluhm }
138a545a52cSbluhm
139a545a52cSbluhm (void)sleep(10);
140a545a52cSbluhm
141a545a52cSbluhm (void)printf("parent write\n");
142a545a52cSbluhm
143a545a52cSbluhm ATF_REQUIRE(write(pf[1], "konec\n", 6) == 6);
144a545a52cSbluhm
145a545a52cSbluhm for(i = 0; i < 3; ++i)
146a545a52cSbluhm (void)wait(&status);
147a545a52cSbluhm
148a545a52cSbluhm (void)printf("parent terminated\n");
149a545a52cSbluhm }
150a545a52cSbluhm
1517496d4e5Sbluhm ATF_TC(basic);
ATF_TC_HEAD(basic,tc)1527496d4e5Sbluhm ATF_TC_HEAD(basic, tc)
153a545a52cSbluhm {
154a545a52cSbluhm atf_tc_set_md_var(tc, "timeout", "10");
155a545a52cSbluhm atf_tc_set_md_var(tc, "descr",
156a545a52cSbluhm "Basis functionality test for poll(2)");
157a545a52cSbluhm }
158a545a52cSbluhm
ATF_TC_BODY(basic,tc)1597496d4e5Sbluhm ATF_TC_BODY(basic, tc)
160a545a52cSbluhm {
161a545a52cSbluhm int fds[2];
162a545a52cSbluhm struct pollfd pfds[2];
163a545a52cSbluhm int ret;
164a545a52cSbluhm
165a545a52cSbluhm ATF_REQUIRE_EQ(pipe(fds), 0);
166a545a52cSbluhm
167a545a52cSbluhm pfds[0].fd = fds[0];
168a545a52cSbluhm pfds[0].events = POLLIN;
169a545a52cSbluhm pfds[1].fd = fds[1];
170a545a52cSbluhm pfds[1].events = POLLOUT;
171a545a52cSbluhm
172a545a52cSbluhm /*
173a545a52cSbluhm * Check that we get a timeout waiting for data on the read end
174a545a52cSbluhm * of our pipe.
175a545a52cSbluhm */
176a545a52cSbluhm pfds[0].revents = -1;
177a545a52cSbluhm pfds[1].revents = -1;
178*d5ba5019Smbuhl ret = poll(&pfds[0], 1, 1);
179*d5ba5019Smbuhl ATF_REQUIRE_EQ_MSG(ret, 0, "got: %d", ret);
180a545a52cSbluhm ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
181a545a52cSbluhm ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents);
182a545a52cSbluhm
183a545a52cSbluhm /* Check that the write end of the pipe as reported as ready. */
184a545a52cSbluhm pfds[0].revents = -1;
185a545a52cSbluhm pfds[1].revents = -1;
186*d5ba5019Smbuhl ret = poll(&pfds[1], 1, 1);
187*d5ba5019Smbuhl ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
188a545a52cSbluhm ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents);
189a545a52cSbluhm ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\
190a545a52cSbluhm pfds[1].revents);
191a545a52cSbluhm
192a545a52cSbluhm /* Check that only the write end of the pipe as reported as ready. */
193a545a52cSbluhm pfds[0].revents = -1;
194a545a52cSbluhm pfds[1].revents = -1;
195*d5ba5019Smbuhl ret = poll(pfds, 2, 1);
196*d5ba5019Smbuhl ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
197a545a52cSbluhm ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
198a545a52cSbluhm ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
199a545a52cSbluhm pfds[1].revents);
200a545a52cSbluhm
201a545a52cSbluhm /* Write data to our pipe. */
202a545a52cSbluhm ATF_REQUIRE_EQ(write(fds[1], "", 1), 1);
203a545a52cSbluhm
204a545a52cSbluhm /* Check that both ends of our pipe are reported as ready. */
205a545a52cSbluhm pfds[0].revents = -1;
206a545a52cSbluhm pfds[1].revents = -1;
207*d5ba5019Smbuhl ret = poll(pfds, 2, 1);
208*d5ba5019Smbuhl ATF_REQUIRE_EQ_MSG(ret, 2, "got: %d", ret);
209a545a52cSbluhm ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d",
210a545a52cSbluhm pfds[0].revents);
211a545a52cSbluhm ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
212a545a52cSbluhm pfds[1].revents);
213a545a52cSbluhm
214a545a52cSbluhm ATF_REQUIRE_EQ(close(fds[0]), 0);
215a545a52cSbluhm ATF_REQUIRE_EQ(close(fds[1]), 0);
216a545a52cSbluhm }
217a545a52cSbluhm
2187496d4e5Sbluhm ATF_TC(err);
ATF_TC_HEAD(err,tc)2197496d4e5Sbluhm ATF_TC_HEAD(err, tc)
220a545a52cSbluhm {
221a545a52cSbluhm atf_tc_set_md_var(tc, "descr", "Check errors from poll(2)");
222a545a52cSbluhm }
223a545a52cSbluhm
ATF_TC_BODY(err,tc)2247496d4e5Sbluhm ATF_TC_BODY(err, tc)
225a545a52cSbluhm {
226a545a52cSbluhm struct pollfd pfd;
227a545a52cSbluhm int fd = 0;
228a545a52cSbluhm
229a545a52cSbluhm pfd.fd = fd;
230a545a52cSbluhm pfd.events = POLLIN;
231a545a52cSbluhm
232a545a52cSbluhm errno = 0;
233a545a52cSbluhm ATF_REQUIRE_ERRNO(EFAULT, poll((struct pollfd *)-1, 1, -1) == -1);
234a545a52cSbluhm
235a545a52cSbluhm errno = 0;
236a545a52cSbluhm ATF_REQUIRE_ERRNO(EINVAL, poll(&pfd, 1, -2) == -1);
237a545a52cSbluhm }
238a545a52cSbluhm
ATF_TP_ADD_TCS(tp)239a545a52cSbluhm ATF_TP_ADD_TCS(tp)
240a545a52cSbluhm {
241a545a52cSbluhm
2427496d4e5Sbluhm ATF_TP_ADD_TC(tp, 3way);
2437496d4e5Sbluhm ATF_TP_ADD_TC(tp, basic);
2447496d4e5Sbluhm ATF_TP_ADD_TC(tp, err);
245a545a52cSbluhm
246a545a52cSbluhm return atf_no_error();
247a545a52cSbluhm }
248