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