xref: /freebsd/tests/sys/kern/pipe/pipe_kqueue_test.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020 Jan Kokemüller
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #include <sys/param.h>
30 #include <sys/event.h>
31 #include <sys/stat.h>
32 
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <limits.h>
36 #include <poll.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <time.h>
40 #include <unistd.h>
41 
42 #include <atf-c.h>
43 
44 ATF_TC_WITHOUT_HEAD(pipe_kqueue__write_end);
45 ATF_TC_BODY(pipe_kqueue__write_end, tc)
46 {
47 	int p[2] = { -1, -1 };
48 
49 	ATF_REQUIRE(pipe2(p, O_CLOEXEC | O_NONBLOCK) == 0);
50 	ATF_REQUIRE(p[0] >= 0);
51 	ATF_REQUIRE(p[1] >= 0);
52 
53 	int kq = kqueue();
54 	ATF_REQUIRE(kq >= 0);
55 
56 	struct kevent kev[32];
57 	EV_SET(&kev[0], p[1], EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, 0);
58 
59 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, NULL) == 0);
60 
61 	/* Test that EVFILT_WRITE behaves sensibly on the write end. */
62 
63 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
64 	    &(struct timespec) { 0, 0 }) == 1);
65 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
66 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
67 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
68 	ATF_REQUIRE(kev[0].fflags == 0);
69 	ATF_REQUIRE(kev[0].data == 16384);
70 	ATF_REQUIRE(kev[0].udata == 0);
71 
72 	/* Filling up the pipe should make the EVFILT_WRITE disappear. */
73 
74 	char c = 0;
75 	ssize_t r;
76 	while ((r = write(p[1], &c, 1)) == 1) {
77 	}
78 	ATF_REQUIRE(r < 0);
79 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
80 
81 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
82 	    &(struct timespec) { 0, 0 }) == 0);
83 
84 	/* Reading (PIPE_BUF - 1) bytes will not trigger a EVFILT_WRITE yet. */
85 
86 	for (int i = 0; i < PIPE_BUF - 1; ++i) {
87 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
88 	}
89 
90 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
91 	    &(struct timespec) { 0, 0 }) == 0);
92 
93 	/* Reading one additional byte triggers the EVFILT_WRITE. */
94 
95 	ATF_REQUIRE(read(p[0], &c, 1) == 1);
96 
97 	r = kevent(kq, NULL, 0, kev, nitems(kev), &(struct timespec) { 0, 0 });
98 	ATF_REQUIRE(r == 1);
99 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
100 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
101 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
102 	ATF_REQUIRE(kev[0].fflags == 0);
103 	ATF_REQUIRE(kev[0].data == PIPE_BUF);
104 	ATF_REQUIRE(kev[0].udata == 0);
105 
106 	/*
107 	 * Reading another byte triggers the EVFILT_WRITE again with a changed
108 	 * 'data' field.
109 	 */
110 
111 	ATF_REQUIRE(read(p[0], &c, 1) == 1);
112 
113 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
114 	    &(struct timespec) { 0, 0 }) == 1);
115 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
116 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
117 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
118 	ATF_REQUIRE(kev[0].fflags == 0);
119 	ATF_REQUIRE(kev[0].data == PIPE_BUF + 1);
120 	ATF_REQUIRE(kev[0].udata == 0);
121 
122 	/*
123 	 * Closing the read end should make a EV_EOF appear but leave the 'data'
124 	 * field unchanged.
125 	 */
126 
127 	ATF_REQUIRE(close(p[0]) == 0);
128 
129 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
130 	    &(struct timespec) { 0, 0 }) == 1);
131 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
132 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
133 	ATF_REQUIRE(kev[0].flags == (EV_CLEAR | EV_EOF | EV_ONESHOT));
134 	ATF_REQUIRE(kev[0].fflags == 0);
135 	ATF_REQUIRE(kev[0].data == PIPE_BUF + 1);
136 	ATF_REQUIRE(kev[0].udata == 0);
137 
138 	ATF_REQUIRE(close(kq) == 0);
139 	ATF_REQUIRE(close(p[1]) == 0);
140 }
141 
142 ATF_TC_WITHOUT_HEAD(pipe_kqueue__closed_read_end);
143 ATF_TC_BODY(pipe_kqueue__closed_read_end, tc)
144 {
145 	int p[2] = { -1, -1 };
146 
147 	ATF_REQUIRE(pipe2(p, O_CLOEXEC | O_NONBLOCK) == 0);
148 	ATF_REQUIRE(p[0] >= 0);
149 	ATF_REQUIRE(p[1] >= 0);
150 
151 	ATF_REQUIRE(close(p[0]) == 0);
152 
153 	int kq = kqueue();
154 	ATF_REQUIRE(kq >= 0);
155 
156 	struct kevent kev[32];
157 	EV_SET(&kev[0], p[1], EVFILT_READ, EV_ADD | EV_CLEAR | EV_RECEIPT, /**/
158 	    0, 0, 0);
159 	EV_SET(&kev[1], p[1], EVFILT_WRITE, EV_ADD | EV_CLEAR | EV_RECEIPT, /**/
160 	    0, 0, 0);
161 
162 	/*
163 	 * Trying to register EVFILT_WRITE when the pipe is closed leads to an
164 	 * EPIPE error.
165 	 */
166 
167 	ATF_REQUIRE(kevent(kq, kev, 2, kev, 2, NULL) == 2);
168 	ATF_REQUIRE((kev[0].flags & EV_ERROR) != 0);
169 	ATF_REQUIRE(kev[0].data == 0);
170 	ATF_REQUIRE((kev[1].flags & EV_ERROR) != 0);
171 	ATF_REQUIRE(kev[1].data == EPIPE);
172 
173 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
174 	    &(struct timespec) { 0, 0 }) == 1);
175 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
176 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
177 	ATF_REQUIRE(kev[0].flags == (EV_EOF | EV_CLEAR | EV_RECEIPT));
178 	ATF_REQUIRE(kev[0].fflags == 0);
179 	ATF_REQUIRE(kev[0].data == 0);
180 	ATF_REQUIRE(kev[0].udata == 0);
181 
182 	ATF_REQUIRE(close(kq) == 0);
183 	ATF_REQUIRE(close(p[1]) == 0);
184 }
185 
186 ATF_TC_WITHOUT_HEAD(pipe_kqueue__closed_read_end_register_before_close);
187 ATF_TC_BODY(pipe_kqueue__closed_read_end_register_before_close, tc)
188 {
189 	int p[2] = { -1, -1 };
190 
191 	ATF_REQUIRE(pipe2(p, O_CLOEXEC | O_NONBLOCK) == 0);
192 	ATF_REQUIRE(p[0] >= 0);
193 	ATF_REQUIRE(p[1] >= 0);
194 
195 	int kq = kqueue();
196 	ATF_REQUIRE(kq >= 0);
197 
198 	struct kevent kev[32];
199 	EV_SET(&kev[0], p[1], EVFILT_READ, EV_ADD | EV_CLEAR | EV_RECEIPT, /**/
200 	    0, 0, 0);
201 	EV_SET(&kev[1], p[1], EVFILT_WRITE, EV_ADD | EV_CLEAR | EV_RECEIPT, /**/
202 	    0, 0, 0);
203 
204 	/*
205 	 * Registering EVFILT_WRITE before the pipe is closed leads to a
206 	 * EVFILT_WRITE event with EV_EOF set.
207 	 */
208 
209 	ATF_REQUIRE(kevent(kq, kev, 2, kev, 2, NULL) == 2);
210 	ATF_REQUIRE((kev[0].flags & EV_ERROR) != 0);
211 	ATF_REQUIRE(kev[0].data == 0);
212 	ATF_REQUIRE((kev[1].flags & EV_ERROR) != 0);
213 	ATF_REQUIRE(kev[1].data == 0);
214 
215 	ATF_REQUIRE(close(p[0]) == 0);
216 
217 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
218 	    &(struct timespec) { 0, 0 }) == 2);
219 	{
220 		ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
221 		ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
222 		ATF_REQUIRE(kev[0].flags ==
223 		    (EV_EOF | EV_CLEAR | EV_ONESHOT | EV_RECEIPT));
224 		ATF_REQUIRE(kev[0].fflags == 0);
225 		ATF_REQUIRE(kev[0].data == 16384);
226 		ATF_REQUIRE(kev[0].udata == 0);
227 	}
228 	{
229 		ATF_REQUIRE(kev[1].ident == (uintptr_t)p[1]);
230 		ATF_REQUIRE(kev[1].filter == EVFILT_READ);
231 		ATF_REQUIRE(kev[1].flags == (EV_EOF | EV_CLEAR | EV_RECEIPT));
232 		ATF_REQUIRE(kev[1].fflags == 0);
233 		ATF_REQUIRE(kev[1].data == 0);
234 		ATF_REQUIRE(kev[1].udata == 0);
235 	}
236 
237 	ATF_REQUIRE(close(kq) == 0);
238 	ATF_REQUIRE(close(p[1]) == 0);
239 }
240 
241 ATF_TC_WITHOUT_HEAD(pipe_kqueue__closed_write_end);
242 ATF_TC_BODY(pipe_kqueue__closed_write_end, tc)
243 {
244 	struct kevent kev[32];
245 	ssize_t bytes, n;
246 	int kq, p[2];
247 	char c;
248 
249 	ATF_REQUIRE(pipe2(p, O_CLOEXEC | O_NONBLOCK) == 0);
250 	ATF_REQUIRE(p[0] >= 0);
251 	ATF_REQUIRE(p[1] >= 0);
252 
253 	bytes = 0;
254 	c = 0;
255 	while ((n = write(p[1], &c, 1)) == 1)
256 		bytes++;
257 	ATF_REQUIRE(n < 0);
258 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
259 
260 	ATF_REQUIRE(close(p[1]) == 0);
261 
262 	kq = kqueue();
263 	ATF_REQUIRE(kq >= 0);
264 
265 	EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR | EV_RECEIPT,
266 	    0, 0, 0);
267 	EV_SET(&kev[1], p[0], EVFILT_WRITE, EV_ADD | EV_CLEAR | EV_RECEIPT,
268 	    0, 0, 0);
269 
270 	/*
271 	 * Trying to register EVFILT_WRITE when the pipe is closed leads to an
272 	 * EPIPE error.
273 	 */
274 
275 	ATF_REQUIRE(kevent(kq, kev, 2, kev, 2, NULL) == 2);
276 	ATF_REQUIRE((kev[0].flags & EV_ERROR) != 0);
277 	ATF_REQUIRE(kev[0].data == 0);
278 	ATF_REQUIRE((kev[1].flags & EV_ERROR) != 0);
279 	ATF_REQUIRE(kev[1].data == EPIPE);
280 
281 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
282 	    &(struct timespec) { 0, 0 }) == 1);
283 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
284 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
285 	ATF_REQUIRE(kev[0].flags == (EV_EOF | EV_CLEAR | EV_RECEIPT));
286 	ATF_REQUIRE(kev[0].fflags == 0);
287 	ATF_REQUIRE(kev[0].data == bytes);
288 	ATF_REQUIRE(kev[0].udata == 0);
289 
290 	ATF_REQUIRE(close(kq) == 0);
291 	ATF_REQUIRE(close(p[0]) == 0);
292 }
293 
294 ATF_TC_WITHOUT_HEAD(pipe_kqueue__closed_write_end_register_before_close);
295 ATF_TC_BODY(pipe_kqueue__closed_write_end_register_before_close, tc)
296 {
297 	struct kevent kev[32];
298 	ssize_t bytes, n;
299 	int kq, p[2];
300 	char c;
301 
302 	ATF_REQUIRE(pipe2(p, O_CLOEXEC | O_NONBLOCK) == 0);
303 	ATF_REQUIRE(p[0] >= 0);
304 	ATF_REQUIRE(p[1] >= 0);
305 
306 	kq = kqueue();
307 	ATF_REQUIRE(kq >= 0);
308 
309 	EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR | EV_RECEIPT,
310 	    0, 0, 0);
311 	EV_SET(&kev[1], p[0], EVFILT_WRITE, EV_ADD | EV_CLEAR | EV_RECEIPT,
312 	    0, 0, 0);
313 
314 	/*
315 	 * Registering EVFILT_WRITE before the pipe is closed leads to a
316 	 * EVFILT_WRITE event with EV_EOF set.
317 	 */
318 
319 	ATF_REQUIRE(kevent(kq, kev, 2, kev, 2, NULL) == 2);
320 	ATF_REQUIRE((kev[0].flags & EV_ERROR) != 0);
321 	ATF_REQUIRE(kev[0].data == 0);
322 	ATF_REQUIRE((kev[1].flags & EV_ERROR) != 0);
323 	ATF_REQUIRE(kev[1].data == 0);
324 
325 	bytes = 0;
326 	c = 0;
327 	while ((n = write(p[1], &c, 1)) == 1)
328 		bytes++;
329 	ATF_REQUIRE(n < 0);
330 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
331 
332 	ATF_REQUIRE(close(p[1]) == 0);
333 
334 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
335 	    &(struct timespec){ 0, 0 }) == 2);
336 
337 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
338 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
339 	ATF_REQUIRE(kev[0].flags ==
340 	    (EV_EOF | EV_CLEAR | EV_ONESHOT | EV_RECEIPT));
341 	ATF_REQUIRE(kev[0].fflags == 0);
342 	ATF_REQUIRE(kev[0].data > 0);
343 	ATF_REQUIRE(kev[0].udata == 0);
344 
345 	ATF_REQUIRE(kev[1].ident == (uintptr_t)p[0]);
346 	ATF_REQUIRE(kev[1].filter == EVFILT_READ);
347 	ATF_REQUIRE(kev[1].flags == (EV_EOF | EV_CLEAR | EV_RECEIPT));
348 	ATF_REQUIRE(kev[1].fflags == 0);
349 	ATF_REQUIRE(kev[1].data == bytes);
350 	ATF_REQUIRE(kev[1].udata == 0);
351 
352 	ATF_REQUIRE(close(kq) == 0);
353 	ATF_REQUIRE(close(p[0]) == 0);
354 }
355 
356 ATF_TP_ADD_TCS(tp)
357 {
358 	ATF_TP_ADD_TC(tp, pipe_kqueue__write_end);
359 	ATF_TP_ADD_TC(tp, pipe_kqueue__closed_read_end);
360 	ATF_TP_ADD_TC(tp, pipe_kqueue__closed_read_end_register_before_close);
361 	ATF_TP_ADD_TC(tp, pipe_kqueue__closed_write_end);
362 	ATF_TP_ADD_TC(tp, pipe_kqueue__closed_write_end_register_before_close);
363 
364 	return atf_no_error();
365 }
366