2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2020 Jan Kokemüller
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/event.h>
46 ATF_TC_WITHOUT_HEAD(fifo_kqueue__writes);
47 ATF_TC_BODY(fifo_kqueue__writes, tc)
49 int p[2] = { -1, -1 };
51 ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
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);
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);
65 ATF_REQUIRE(kevent(kq, kev, 2, NULL, 0, NULL) == 0);
67 /* A new writer should immediately get a EVFILT_WRITE event. */
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);
78 /* Filling up the pipe should make the EVFILT_WRITE disappear. */
82 while ((r = write(p[1], &c, 1)) == 1) {
85 ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
87 ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
88 &(struct timespec) { 0, 0 }) == 0);
90 /* Reading (PIPE_BUF - 1) bytes will not trigger a EVFILT_WRITE yet. */
92 for (int i = 0; i < PIPE_BUF - 1; ++i) {
93 ATF_REQUIRE(read(p[0], &c, 1) == 1);
96 ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
97 &(struct timespec) { 0, 0 }) == 0);
99 /* Reading one additional byte triggers the EVFILT_WRITE. */
101 ATF_REQUIRE(read(p[0], &c, 1) == 1);
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);
113 * Reading another byte triggers the EVFILT_WRITE again with a changed
117 ATF_REQUIRE(read(p[0], &c, 1) == 1);
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);
129 * Closing the read end should make a EV_EOF appear but leave the 'data'
133 ATF_REQUIRE(close(p[0]) == 0);
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);
143 ATF_REQUIRE(close(kq) == 0);
144 ATF_REQUIRE(close(p[1]) == 0);
147 ATF_TC_WITHOUT_HEAD(fifo_kqueue__connecting_reader);
148 ATF_TC_BODY(fifo_kqueue__connecting_reader, tc)
150 int p[2] = { -1, -1 };
152 ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
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);
160 ATF_REQUIRE(kq >= 0);
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);
166 ATF_REQUIRE(kevent(kq, kev, 2, NULL, 0, NULL) == 0);
168 /* A new writer should immediately get a EVFILT_WRITE event. */
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);
178 * Filling the pipe, reading (PIPE_BUF + 1) bytes, then closing the
179 * read end leads to a EVFILT_WRITE with EV_EOF set.
184 while ((r = write(p[1], &c, 1)) == 1) {
187 ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
189 for (int i = 0; i < PIPE_BUF + 1; ++i) {
190 ATF_REQUIRE(read(p[0], &c, 1) == 1);
193 ATF_REQUIRE(close(p[0]) == 0);
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);
201 /* Opening the reader again must trigger the EVFILT_WRITE. */
203 ATF_REQUIRE((p[0] = open("testfifo",
204 O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
206 r = kevent(kq, NULL, 0, kev, nitems(kev), &(struct timespec) { 1, 0 });
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);
217 ATF_REQUIRE(close(kq) == 0);
218 ATF_REQUIRE(close(p[0]) == 0);
219 ATF_REQUIRE(close(p[1]) == 0);
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)
226 struct kevent kev[32];
231 ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
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);
240 while ((n = write(p[1], &c, 1)) == 1)
243 ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
244 ATF_REQUIRE(bytes > 1);
246 for (i = 0; i < bytes / 2; i++)
247 ATF_REQUIRE(read(p[0], &c, 1) == 1);
251 ATF_REQUIRE(kq >= 0);
253 EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
255 ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, NULL) == 0);
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);
267 ATF_REQUIRE(read(p[0], &c, 1) == 1);
268 n = read(p[0], &c, 1);
270 ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
272 ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
273 &(struct timespec) { 0, 0 }) == 0);
275 ATF_REQUIRE(close(kq) == 0);
276 ATF_REQUIRE(close(p[0]) == 0);
277 ATF_REQUIRE(close(p[1]) == 0);
280 ATF_TC_WITHOUT_HEAD(fifo_kqueue__read_eof_wakeups);
281 ATF_TC_BODY(fifo_kqueue__read_eof_wakeups, tc)
283 int p[2] = { -1, -1 };
285 ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
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);
293 ATF_REQUIRE(kq >= 0);
295 struct kevent kev[32];
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);
300 ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
301 &(struct timespec) { 0, 0 }) == 0);
304 * Closing the writer must trigger a EVFILT_READ edge with EV_EOF set.
307 ATF_REQUIRE(close(p[1]) == 0);
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);
319 * Trying to read from a closed pipe should not trigger EVFILT_READ
324 ATF_REQUIRE(read(p[0], &c, 1) == 0);
326 ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
327 &(struct timespec) { 0, 0 }) == 0);
329 ATF_REQUIRE(close(kq) == 0);
330 ATF_REQUIRE(close(p[0]) == 0);
333 ATF_TC_WITHOUT_HEAD(fifo_kqueue__read_eof_state_when_reconnecting);
334 ATF_TC_BODY(fifo_kqueue__read_eof_state_when_reconnecting, tc)
336 int p[2] = { -1, -1 };
338 ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
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);
346 ATF_REQUIRE(kq >= 0);
348 struct kevent kev[32];
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);
353 ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
354 &(struct timespec) { 0, 0 }) == 0);
357 * Closing the writer must trigger a EVFILT_READ edge with EV_EOF set.
360 ATF_REQUIRE(close(p[1]) == 0);
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);
371 /* A new reader shouldn't see the EOF flag. */
375 ATF_REQUIRE((new_reader = open("testfifo",
376 O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
378 int new_kq = kqueue();
379 ATF_REQUIRE(new_kq >= 0);
381 struct kevent new_kev[32];
382 EV_SET(&new_kev[0], new_reader, EVFILT_READ, EV_ADD | EV_CLEAR,
384 ATF_REQUIRE(kevent(new_kq, new_kev, 1, NULL, 0, NULL) == 0);
386 ATF_REQUIRE(kevent(new_kq, NULL, 0, new_kev, nitems(new_kev),
387 &(struct timespec) { 0, 0 }) == 0);
389 ATF_REQUIRE(close(new_kq) == 0);
390 ATF_REQUIRE(close(new_reader) == 0);
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
399 ATF_REQUIRE((p[1] = open("testfifo",
400 O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
402 ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
403 &(struct timespec) { 0, 0 }) == 0);
405 /* Writing a byte should trigger a EVFILT_READ. */
408 ATF_REQUIRE(write(p[1], &c, 1) == 1);
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);
419 ATF_REQUIRE(close(kq) == 0);
420 ATF_REQUIRE(close(p[0]) == 0);
421 ATF_REQUIRE(close(p[1]) == 0);
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);
432 return atf_no_error();