xref: /freebsd/tests/sys/fifo/fifo_kqueue.c (revision 4e8d558c)
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 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/event.h>
33 #include <sys/stat.h>
34 
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <limits.h>
38 #include <poll.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <time.h>
42 #include <unistd.h>
43 
44 #include <atf-c.h>
45 
46 ATF_TC_WITHOUT_HEAD(fifo_kqueue__writes);
47 ATF_TC_BODY(fifo_kqueue__writes, tc)
48 {
49 	int p[2] = { -1, -1 };
50 
51 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
52 
53 	ATF_REQUIRE((p[0] = open("testfifo",
54 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
55 	ATF_REQUIRE((p[1] = open("testfifo",
56 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
57 
58 	int kq = kqueue();
59 	ATF_REQUIRE(kq >= 0);
60 
61 	struct kevent kev[32];
62 	EV_SET(&kev[0], p[1], EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, 0);
63 	EV_SET(&kev[1], p[1], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
64 
65 	ATF_REQUIRE(kevent(kq, kev, 2, NULL, 0, NULL) == 0);
66 
67 	/* A new writer should immediately get a EVFILT_WRITE event. */
68 
69 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
70 	    &(struct timespec) { 0, 0 }) == 1);
71 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
72 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
73 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
74 	ATF_REQUIRE(kev[0].fflags == 0);
75 	ATF_REQUIRE(kev[0].data == 16384);
76 	ATF_REQUIRE(kev[0].udata == 0);
77 
78 	/* Filling up the pipe should make the EVFILT_WRITE disappear. */
79 
80 	char c = 0;
81 	ssize_t r;
82 	while ((r = write(p[1], &c, 1)) == 1) {
83 	}
84 	ATF_REQUIRE(r < 0);
85 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
86 
87 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
88 	    &(struct timespec) { 0, 0 }) == 0);
89 
90 	/* Reading (PIPE_BUF - 1) bytes will not trigger a EVFILT_WRITE yet. */
91 
92 	for (int i = 0; i < PIPE_BUF - 1; ++i) {
93 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
94 	}
95 
96 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
97 	    &(struct timespec) { 0, 0 }) == 0);
98 
99 	/* Reading one additional byte triggers the EVFILT_WRITE. */
100 
101 	ATF_REQUIRE(read(p[0], &c, 1) == 1);
102 
103 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
104 	    &(struct timespec) { 0, 0 }) == 1);
105 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
106 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
107 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
108 	ATF_REQUIRE(kev[0].fflags == 0);
109 	ATF_REQUIRE(kev[0].data == PIPE_BUF);
110 	ATF_REQUIRE(kev[0].udata == 0);
111 
112 	/*
113 	 * Reading another byte triggers the EVFILT_WRITE again with a changed
114 	 * 'data' field.
115 	 */
116 
117 	ATF_REQUIRE(read(p[0], &c, 1) == 1);
118 
119 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
120 	    &(struct timespec) { 0, 0 }) == 1);
121 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
122 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
123 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
124 	ATF_REQUIRE(kev[0].fflags == 0);
125 	ATF_REQUIRE(kev[0].data == PIPE_BUF + 1);
126 	ATF_REQUIRE(kev[0].udata == 0);
127 
128 	/*
129 	 * Closing the read end should make a EV_EOF appear but leave the 'data'
130 	 * field unchanged.
131 	 */
132 
133 	ATF_REQUIRE(close(p[0]) == 0);
134 
135 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev), NULL) == 1);
136 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
137 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
138 	ATF_REQUIRE(kev[0].flags == (EV_CLEAR | EV_EOF));
139 	ATF_REQUIRE(kev[0].fflags == 0);
140 	ATF_REQUIRE(kev[0].data == PIPE_BUF + 1);
141 	ATF_REQUIRE(kev[0].udata == 0);
142 
143 	ATF_REQUIRE(close(kq) == 0);
144 	ATF_REQUIRE(close(p[1]) == 0);
145 }
146 
147 ATF_TC_WITHOUT_HEAD(fifo_kqueue__connecting_reader);
148 ATF_TC_BODY(fifo_kqueue__connecting_reader, tc)
149 {
150 	int p[2] = { -1, -1 };
151 
152 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
153 
154 	ATF_REQUIRE((p[0] = open("testfifo",
155 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
156 	ATF_REQUIRE((p[1] = open("testfifo",
157 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
158 
159 	int kq = kqueue();
160 	ATF_REQUIRE(kq >= 0);
161 
162 	struct kevent kev[32];
163 	EV_SET(&kev[0], p[1], EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, 0);
164 	EV_SET(&kev[1], p[1], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
165 
166 	ATF_REQUIRE(kevent(kq, kev, 2, NULL, 0, NULL) == 0);
167 
168 	/* A new writer should immediately get a EVFILT_WRITE event. */
169 
170 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
171 	    &(struct timespec) { 0, 0 }) == 1);
172 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
173 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
174 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
175 	    &(struct timespec) { 0, 0 }) == 0);
176 
177 	/*
178 	 * Filling the pipe, reading (PIPE_BUF + 1) bytes, then closing the
179 	 * read end leads to a EVFILT_WRITE with EV_EOF set.
180 	 */
181 
182 	char c = 0;
183 	ssize_t r;
184 	while ((r = write(p[1], &c, 1)) == 1) {
185 	}
186 	ATF_REQUIRE(r < 0);
187 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
188 
189 	for (int i = 0; i < PIPE_BUF + 1; ++i) {
190 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
191 	}
192 
193 	ATF_REQUIRE(close(p[0]) == 0);
194 
195 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev), NULL) == 1);
196 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
197 	ATF_REQUIRE((kev[0].flags & EV_EOF) != 0);
198 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
199 	    &(struct timespec) { 0, 0 }) == 0);
200 
201 	/* Opening the reader again must trigger the EVFILT_WRITE. */
202 
203 	ATF_REQUIRE((p[0] = open("testfifo",
204 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
205 
206 	r = kevent(kq, NULL, 0, kev, nitems(kev), &(struct timespec) { 1, 0 });
207 	ATF_REQUIRE(r == 1);
208 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
209 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
210 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
211 	ATF_REQUIRE(kev[0].fflags == 0);
212 	ATF_REQUIRE(kev[0].data == PIPE_BUF + 1);
213 	ATF_REQUIRE(kev[0].udata == 0);
214 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
215 	    &(struct timespec) { 0, 0 }) == 0);
216 
217 	ATF_REQUIRE(close(kq) == 0);
218 	ATF_REQUIRE(close(p[0]) == 0);
219 	ATF_REQUIRE(close(p[1]) == 0);
220 }
221 
222 /* Check that EVFILT_READ behaves sensibly on a FIFO reader. */
223 ATF_TC_WITHOUT_HEAD(fifo_kqueue__reads);
224 ATF_TC_BODY(fifo_kqueue__reads, tc)
225 {
226 	struct kevent kev[32];
227 	ssize_t bytes, i, n;
228 	int kq, p[2];
229 	char c;
230 
231 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
232 
233 	ATF_REQUIRE((p[0] = open("testfifo",
234 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
235 	ATF_REQUIRE((p[1] = open("testfifo",
236 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
237 
238 	bytes = 0;
239 	c = 0;
240 	while ((n = write(p[1], &c, 1)) == 1)
241 		bytes++;
242 	ATF_REQUIRE(n < 0);
243 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
244 	ATF_REQUIRE(bytes > 1);
245 
246 	for (i = 0; i < bytes / 2; i++)
247 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
248 	bytes -= i;
249 
250 	kq = kqueue();
251 	ATF_REQUIRE(kq >= 0);
252 
253 	EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
254 
255 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, NULL) == 0);
256 
257 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
258 	    &(struct timespec){ 0, 0 }) == 1);
259 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
260 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
261 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
262 	ATF_REQUIRE(kev[0].fflags == 0);
263 	ATF_REQUIRE(kev[0].data == bytes);
264 	ATF_REQUIRE(kev[0].udata == 0);
265 
266 	while (bytes-- > 0)
267 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
268 	n = read(p[0], &c, 1);
269 	ATF_REQUIRE(n < 0);
270 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
271 
272 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
273 	    &(struct timespec) { 0, 0 }) == 0);
274 
275 	ATF_REQUIRE(close(kq) == 0);
276 	ATF_REQUIRE(close(p[0]) == 0);
277 	ATF_REQUIRE(close(p[1]) == 0);
278 }
279 
280 ATF_TC_WITHOUT_HEAD(fifo_kqueue__read_eof_wakeups);
281 ATF_TC_BODY(fifo_kqueue__read_eof_wakeups, tc)
282 {
283 	int p[2] = { -1, -1 };
284 
285 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
286 
287 	ATF_REQUIRE((p[0] = open("testfifo",
288 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
289 	ATF_REQUIRE((p[1] = open("testfifo",
290 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
291 
292 	int kq = kqueue();
293 	ATF_REQUIRE(kq >= 0);
294 
295 	struct kevent kev[32];
296 
297 	EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
298 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, NULL) == 0);
299 
300 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
301 	    &(struct timespec) { 0, 0 }) == 0);
302 
303 	/*
304 	 * Closing the writer must trigger a EVFILT_READ edge with EV_EOF set.
305 	 */
306 
307 	ATF_REQUIRE(close(p[1]) == 0);
308 
309 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
310 	    &(struct timespec) { 0, 0 }) == 1);
311 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
312 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
313 	ATF_REQUIRE(kev[0].flags == (EV_EOF | EV_CLEAR));
314 	ATF_REQUIRE(kev[0].fflags == 0);
315 	ATF_REQUIRE(kev[0].data == 0);
316 	ATF_REQUIRE(kev[0].udata == 0);
317 
318 	/*
319 	 * Trying to read from a closed pipe should not trigger EVFILT_READ
320 	 * edges.
321 	 */
322 
323 	char c;
324 	ATF_REQUIRE(read(p[0], &c, 1) == 0);
325 
326 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
327 	    &(struct timespec) { 0, 0 }) == 0);
328 
329 	ATF_REQUIRE(close(kq) == 0);
330 	ATF_REQUIRE(close(p[0]) == 0);
331 }
332 
333 ATF_TC_WITHOUT_HEAD(fifo_kqueue__read_eof_state_when_reconnecting);
334 ATF_TC_BODY(fifo_kqueue__read_eof_state_when_reconnecting, tc)
335 {
336 	int p[2] = { -1, -1 };
337 
338 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
339 
340 	ATF_REQUIRE((p[0] = open("testfifo",
341 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
342 	ATF_REQUIRE((p[1] = open("testfifo",
343 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
344 
345 	int kq = kqueue();
346 	ATF_REQUIRE(kq >= 0);
347 
348 	struct kevent kev[32];
349 
350 	EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
351 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, NULL) == 0);
352 
353 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
354 	    &(struct timespec) { 0, 0 }) == 0);
355 
356 	/*
357 	 * Closing the writer must trigger a EVFILT_READ edge with EV_EOF set.
358 	 */
359 
360 	ATF_REQUIRE(close(p[1]) == 0);
361 
362 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
363 	    &(struct timespec) { 0, 0 }) == 1);
364 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
365 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
366 	ATF_REQUIRE(kev[0].flags == (EV_EOF | EV_CLEAR));
367 	ATF_REQUIRE(kev[0].fflags == 0);
368 	ATF_REQUIRE(kev[0].data == 0);
369 	ATF_REQUIRE(kev[0].udata == 0);
370 
371 	/* A new reader shouldn't see the EOF flag. */
372 
373 	{
374 		int new_reader;
375 		ATF_REQUIRE((new_reader = open("testfifo",
376 		    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
377 
378 		int new_kq = kqueue();
379 		ATF_REQUIRE(new_kq >= 0);
380 
381 		struct kevent new_kev[32];
382 		EV_SET(&new_kev[0], new_reader, EVFILT_READ, EV_ADD | EV_CLEAR,
383 		    0, 0, 0);
384 		ATF_REQUIRE(kevent(new_kq, new_kev, 1, NULL, 0, NULL) == 0);
385 
386 		ATF_REQUIRE(kevent(new_kq, NULL, 0, new_kev, nitems(new_kev),
387 		    &(struct timespec) { 0, 0 }) == 0);
388 
389 		ATF_REQUIRE(close(new_kq) == 0);
390 		ATF_REQUIRE(close(new_reader) == 0);
391 	}
392 
393 	/*
394 	 * Simply reopening the writer does not trigger the EVFILT_READ again --
395 	 * EV_EOF should be cleared, but there is no data yet so the filter
396 	 * does not trigger.
397 	 */
398 
399 	ATF_REQUIRE((p[1] = open("testfifo",
400 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
401 
402 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
403 	    &(struct timespec) { 0, 0 }) == 0);
404 
405 	/* Writing a byte should trigger a EVFILT_READ. */
406 
407 	char c = 0;
408 	ATF_REQUIRE(write(p[1], &c, 1) == 1);
409 
410 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
411 	    &(struct timespec) { 0, 0 }) == 1);
412 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
413 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
414 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
415 	ATF_REQUIRE(kev[0].fflags == 0);
416 	ATF_REQUIRE(kev[0].data == 1);
417 	ATF_REQUIRE(kev[0].udata == 0);
418 
419 	ATF_REQUIRE(close(kq) == 0);
420 	ATF_REQUIRE(close(p[0]) == 0);
421 	ATF_REQUIRE(close(p[1]) == 0);
422 }
423 
424 ATF_TP_ADD_TCS(tp)
425 {
426 	ATF_TP_ADD_TC(tp, fifo_kqueue__writes);
427 	ATF_TP_ADD_TC(tp, fifo_kqueue__connecting_reader);
428 	ATF_TP_ADD_TC(tp, fifo_kqueue__reads);
429 	ATF_TP_ADD_TC(tp, fifo_kqueue__read_eof_wakeups);
430 	ATF_TP_ADD_TC(tp, fifo_kqueue__read_eof_state_when_reconnecting);
431 
432 	return atf_no_error();
433 }
434