xref: /freebsd-src/tests/sys/fifo/fifo_kqueue.c (revision 6dced2c6358e467ac1dccd99f6f648d4f71957a8)
1344d411cSMark Johnston /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3344d411cSMark Johnston  *
4344d411cSMark Johnston  * Copyright (c) 2020 Jan Kokemüller
5344d411cSMark Johnston  *
6344d411cSMark Johnston  * Redistribution and use in source and binary forms, with or without
7344d411cSMark Johnston  * modification, are permitted provided that the following conditions
8344d411cSMark Johnston  * are met:
9344d411cSMark Johnston  * 1. Redistributions of source code must retain the above copyright
10344d411cSMark Johnston  *    notice, this list of conditions and the following disclaimer.
11344d411cSMark Johnston  * 2. Redistributions in binary form must reproduce the above copyright
12344d411cSMark Johnston  *    notice, this list of conditions and the following disclaimer in the
13344d411cSMark Johnston  *    documentation and/or other materials provided with the distribution.
14344d411cSMark Johnston  *
15344d411cSMark Johnston  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16344d411cSMark Johnston  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17344d411cSMark Johnston  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18344d411cSMark Johnston  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19344d411cSMark Johnston  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20344d411cSMark Johnston  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21344d411cSMark Johnston  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22344d411cSMark Johnston  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23344d411cSMark Johnston  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24344d411cSMark Johnston  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25344d411cSMark Johnston  * SUCH DAMAGE.
26344d411cSMark Johnston  */
27344d411cSMark Johnston 
28344d411cSMark Johnston #include <sys/param.h>
29344d411cSMark Johnston #include <sys/event.h>
30344d411cSMark Johnston #include <sys/stat.h>
31344d411cSMark Johnston 
32344d411cSMark Johnston #include <errno.h>
33344d411cSMark Johnston #include <fcntl.h>
34344d411cSMark Johnston #include <limits.h>
35344d411cSMark Johnston #include <poll.h>
36344d411cSMark Johnston #include <stdio.h>
37344d411cSMark Johnston #include <stdlib.h>
38344d411cSMark Johnston #include <time.h>
39344d411cSMark Johnston #include <unistd.h>
40344d411cSMark Johnston 
41344d411cSMark Johnston #include <atf-c.h>
42344d411cSMark Johnston 
43344d411cSMark Johnston ATF_TC_WITHOUT_HEAD(fifo_kqueue__writes);
ATF_TC_BODY(fifo_kqueue__writes,tc)44344d411cSMark Johnston ATF_TC_BODY(fifo_kqueue__writes, tc)
45344d411cSMark Johnston {
46344d411cSMark Johnston 	int p[2] = { -1, -1 };
47344d411cSMark Johnston 
48344d411cSMark Johnston 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
49344d411cSMark Johnston 
50344d411cSMark Johnston 	ATF_REQUIRE((p[0] = open("testfifo",
51344d411cSMark Johnston 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
52344d411cSMark Johnston 	ATF_REQUIRE((p[1] = open("testfifo",
53344d411cSMark Johnston 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
54344d411cSMark Johnston 
55344d411cSMark Johnston 	int kq = kqueue();
56344d411cSMark Johnston 	ATF_REQUIRE(kq >= 0);
57344d411cSMark Johnston 
58344d411cSMark Johnston 	struct kevent kev[32];
59344d411cSMark Johnston 	EV_SET(&kev[0], p[1], EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, 0);
60344d411cSMark Johnston 	EV_SET(&kev[1], p[1], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
61344d411cSMark Johnston 
62344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, kev, 2, NULL, 0, NULL) == 0);
63344d411cSMark Johnston 
64344d411cSMark Johnston 	/* A new writer should immediately get a EVFILT_WRITE event. */
65344d411cSMark Johnston 
66344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
67344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 1);
68344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
69344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
70344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
71344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
72344d411cSMark Johnston 	ATF_REQUIRE(kev[0].data == 16384);
73344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
74344d411cSMark Johnston 
75344d411cSMark Johnston 	/* Filling up the pipe should make the EVFILT_WRITE disappear. */
76344d411cSMark Johnston 
77344d411cSMark Johnston 	char c = 0;
78344d411cSMark Johnston 	ssize_t r;
79344d411cSMark Johnston 	while ((r = write(p[1], &c, 1)) == 1) {
80344d411cSMark Johnston 	}
81344d411cSMark Johnston 	ATF_REQUIRE(r < 0);
82344d411cSMark Johnston 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
83344d411cSMark Johnston 
84344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
85344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
86344d411cSMark Johnston 
87344d411cSMark Johnston 	/* Reading (PIPE_BUF - 1) bytes will not trigger a EVFILT_WRITE yet. */
88344d411cSMark Johnston 
89344d411cSMark Johnston 	for (int i = 0; i < PIPE_BUF - 1; ++i) {
90344d411cSMark Johnston 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
91344d411cSMark Johnston 	}
92344d411cSMark Johnston 
93344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
94344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
95344d411cSMark Johnston 
96344d411cSMark Johnston 	/* Reading one additional byte triggers the EVFILT_WRITE. */
97344d411cSMark Johnston 
98344d411cSMark Johnston 	ATF_REQUIRE(read(p[0], &c, 1) == 1);
99344d411cSMark Johnston 
100344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
101344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 1);
102344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
103344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
104344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
105344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
106344d411cSMark Johnston 	ATF_REQUIRE(kev[0].data == PIPE_BUF);
107344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
108344d411cSMark Johnston 
109344d411cSMark Johnston 	/*
110344d411cSMark Johnston 	 * Reading another byte triggers the EVFILT_WRITE again with a changed
111344d411cSMark Johnston 	 * 'data' field.
112344d411cSMark Johnston 	 */
113344d411cSMark Johnston 
114344d411cSMark Johnston 	ATF_REQUIRE(read(p[0], &c, 1) == 1);
115344d411cSMark Johnston 
116344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
117344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 1);
118344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
119344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
120344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
121344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
122344d411cSMark Johnston 	ATF_REQUIRE(kev[0].data == PIPE_BUF + 1);
123344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
124344d411cSMark Johnston 
125344d411cSMark Johnston 	/*
126344d411cSMark Johnston 	 * Closing the read end should make a EV_EOF appear but leave the 'data'
127344d411cSMark Johnston 	 * field unchanged.
128344d411cSMark Johnston 	 */
129344d411cSMark Johnston 
130344d411cSMark Johnston 	ATF_REQUIRE(close(p[0]) == 0);
131344d411cSMark Johnston 
132344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev), NULL) == 1);
133344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
134344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
135344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == (EV_CLEAR | EV_EOF));
136344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
137344d411cSMark Johnston 	ATF_REQUIRE(kev[0].data == PIPE_BUF + 1);
138344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
139344d411cSMark Johnston 
140344d411cSMark Johnston 	ATF_REQUIRE(close(kq) == 0);
141344d411cSMark Johnston 	ATF_REQUIRE(close(p[1]) == 0);
142344d411cSMark Johnston }
143344d411cSMark Johnston 
144344d411cSMark Johnston ATF_TC_WITHOUT_HEAD(fifo_kqueue__connecting_reader);
ATF_TC_BODY(fifo_kqueue__connecting_reader,tc)145344d411cSMark Johnston ATF_TC_BODY(fifo_kqueue__connecting_reader, tc)
146344d411cSMark Johnston {
147344d411cSMark Johnston 	int p[2] = { -1, -1 };
148344d411cSMark Johnston 
149344d411cSMark Johnston 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
150344d411cSMark Johnston 
151344d411cSMark Johnston 	ATF_REQUIRE((p[0] = open("testfifo",
152344d411cSMark Johnston 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
153344d411cSMark Johnston 	ATF_REQUIRE((p[1] = open("testfifo",
154344d411cSMark Johnston 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
155344d411cSMark Johnston 
156344d411cSMark Johnston 	int kq = kqueue();
157344d411cSMark Johnston 	ATF_REQUIRE(kq >= 0);
158344d411cSMark Johnston 
159344d411cSMark Johnston 	struct kevent kev[32];
160344d411cSMark Johnston 	EV_SET(&kev[0], p[1], EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, 0);
161344d411cSMark Johnston 	EV_SET(&kev[1], p[1], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
162344d411cSMark Johnston 
163344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, kev, 2, NULL, 0, NULL) == 0);
164344d411cSMark Johnston 
165344d411cSMark Johnston 	/* A new writer should immediately get a EVFILT_WRITE event. */
166344d411cSMark Johnston 
167344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
168344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 1);
169344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
170344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
171344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
172344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
173344d411cSMark Johnston 
174344d411cSMark Johnston 	/*
175344d411cSMark Johnston 	 * Filling the pipe, reading (PIPE_BUF + 1) bytes, then closing the
176344d411cSMark Johnston 	 * read end leads to a EVFILT_WRITE with EV_EOF set.
177344d411cSMark Johnston 	 */
178344d411cSMark Johnston 
179344d411cSMark Johnston 	char c = 0;
180344d411cSMark Johnston 	ssize_t r;
181344d411cSMark Johnston 	while ((r = write(p[1], &c, 1)) == 1) {
182344d411cSMark Johnston 	}
183344d411cSMark Johnston 	ATF_REQUIRE(r < 0);
184344d411cSMark Johnston 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
185344d411cSMark Johnston 
186344d411cSMark Johnston 	for (int i = 0; i < PIPE_BUF + 1; ++i) {
187344d411cSMark Johnston 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
188344d411cSMark Johnston 	}
189344d411cSMark Johnston 
190344d411cSMark Johnston 	ATF_REQUIRE(close(p[0]) == 0);
191344d411cSMark Johnston 
192344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev), NULL) == 1);
193344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
194344d411cSMark Johnston 	ATF_REQUIRE((kev[0].flags & EV_EOF) != 0);
195344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
196344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
197344d411cSMark Johnston 
198344d411cSMark Johnston 	/* Opening the reader again must trigger the EVFILT_WRITE. */
199344d411cSMark Johnston 
200344d411cSMark Johnston 	ATF_REQUIRE((p[0] = open("testfifo",
201344d411cSMark Johnston 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
202344d411cSMark Johnston 
203344d411cSMark Johnston 	r = kevent(kq, NULL, 0, kev, nitems(kev), &(struct timespec) { 1, 0 });
204344d411cSMark Johnston 	ATF_REQUIRE(r == 1);
205344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[1]);
206344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_WRITE);
207344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
208344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
209344d411cSMark Johnston 	ATF_REQUIRE(kev[0].data == PIPE_BUF + 1);
210344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
211344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
212344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
213344d411cSMark Johnston 
214344d411cSMark Johnston 	ATF_REQUIRE(close(kq) == 0);
215344d411cSMark Johnston 	ATF_REQUIRE(close(p[0]) == 0);
216344d411cSMark Johnston 	ATF_REQUIRE(close(p[1]) == 0);
217344d411cSMark Johnston }
218344d411cSMark Johnston 
2199bf12bb9SMark Johnston /* Check that EVFILT_READ behaves sensibly on a FIFO reader. */
220344d411cSMark Johnston ATF_TC_WITHOUT_HEAD(fifo_kqueue__reads);
ATF_TC_BODY(fifo_kqueue__reads,tc)221344d411cSMark Johnston ATF_TC_BODY(fifo_kqueue__reads, tc)
222344d411cSMark Johnston {
2239bf12bb9SMark Johnston 	struct kevent kev[32];
2249bf12bb9SMark Johnston 	ssize_t bytes, i, n;
2259bf12bb9SMark Johnston 	int kq, p[2];
2269bf12bb9SMark Johnston 	char c;
227344d411cSMark Johnston 
228344d411cSMark Johnston 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
229344d411cSMark Johnston 
230344d411cSMark Johnston 	ATF_REQUIRE((p[0] = open("testfifo",
231344d411cSMark Johnston 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
232344d411cSMark Johnston 	ATF_REQUIRE((p[1] = open("testfifo",
233344d411cSMark Johnston 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
234344d411cSMark Johnston 
2359bf12bb9SMark Johnston 	bytes = 0;
2369bf12bb9SMark Johnston 	c = 0;
2379bf12bb9SMark Johnston 	while ((n = write(p[1], &c, 1)) == 1)
2389bf12bb9SMark Johnston 		bytes++;
2399bf12bb9SMark Johnston 	ATF_REQUIRE(n < 0);
240344d411cSMark Johnston 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
2419bf12bb9SMark Johnston 	ATF_REQUIRE(bytes > 1);
242344d411cSMark Johnston 
2439bf12bb9SMark Johnston 	for (i = 0; i < bytes / 2; i++)
244344d411cSMark Johnston 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
2459bf12bb9SMark Johnston 	bytes -= i;
246344d411cSMark Johnston 
2479bf12bb9SMark Johnston 	kq = kqueue();
248344d411cSMark Johnston 	ATF_REQUIRE(kq >= 0);
249344d411cSMark Johnston 
250344d411cSMark Johnston 	EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
251344d411cSMark Johnston 
252344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, NULL) == 0);
253344d411cSMark Johnston 
254344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
255344d411cSMark Johnston 	    &(struct timespec){ 0, 0 }) == 1);
256344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
257344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
258344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
259344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
2609bf12bb9SMark Johnston 	ATF_REQUIRE(kev[0].data == bytes);
261344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
262344d411cSMark Johnston 
2639bf12bb9SMark Johnston 	while (bytes-- > 0)
2649bf12bb9SMark Johnston 		ATF_REQUIRE(read(p[0], &c, 1) == 1);
2659bf12bb9SMark Johnston 	n = read(p[0], &c, 1);
2669bf12bb9SMark Johnston 	ATF_REQUIRE(n < 0);
267344d411cSMark Johnston 	ATF_REQUIRE(errno == EAGAIN || errno == EWOULDBLOCK);
268344d411cSMark Johnston 
269344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
270344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
271344d411cSMark Johnston 
272344d411cSMark Johnston 	ATF_REQUIRE(close(kq) == 0);
273344d411cSMark Johnston 	ATF_REQUIRE(close(p[0]) == 0);
274344d411cSMark Johnston 	ATF_REQUIRE(close(p[1]) == 0);
275344d411cSMark Johnston }
276344d411cSMark Johnston 
277344d411cSMark Johnston ATF_TC_WITHOUT_HEAD(fifo_kqueue__read_eof_wakeups);
ATF_TC_BODY(fifo_kqueue__read_eof_wakeups,tc)278344d411cSMark Johnston ATF_TC_BODY(fifo_kqueue__read_eof_wakeups, tc)
279344d411cSMark Johnston {
280344d411cSMark Johnston 	int p[2] = { -1, -1 };
281344d411cSMark Johnston 
282344d411cSMark Johnston 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
283344d411cSMark Johnston 
284344d411cSMark Johnston 	ATF_REQUIRE((p[0] = open("testfifo",
285344d411cSMark Johnston 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
286344d411cSMark Johnston 	ATF_REQUIRE((p[1] = open("testfifo",
287344d411cSMark Johnston 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
288344d411cSMark Johnston 
289344d411cSMark Johnston 	int kq = kqueue();
290344d411cSMark Johnston 	ATF_REQUIRE(kq >= 0);
291344d411cSMark Johnston 
292344d411cSMark Johnston 	struct kevent kev[32];
293344d411cSMark Johnston 
294344d411cSMark Johnston 	EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
295344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, NULL) == 0);
296344d411cSMark Johnston 
297344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
298344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
299344d411cSMark Johnston 
300344d411cSMark Johnston 	/*
301344d411cSMark Johnston 	 * Closing the writer must trigger a EVFILT_READ edge with EV_EOF set.
302344d411cSMark Johnston 	 */
303344d411cSMark Johnston 
304344d411cSMark Johnston 	ATF_REQUIRE(close(p[1]) == 0);
305344d411cSMark Johnston 
306344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
307344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 1);
308344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
309344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
310344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == (EV_EOF | EV_CLEAR));
311344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
312344d411cSMark Johnston 	ATF_REQUIRE(kev[0].data == 0);
313344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
314344d411cSMark Johnston 
315344d411cSMark Johnston 	/*
316344d411cSMark Johnston 	 * Trying to read from a closed pipe should not trigger EVFILT_READ
317344d411cSMark Johnston 	 * edges.
318344d411cSMark Johnston 	 */
319344d411cSMark Johnston 
320344d411cSMark Johnston 	char c;
321344d411cSMark Johnston 	ATF_REQUIRE(read(p[0], &c, 1) == 0);
322344d411cSMark Johnston 
323344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
324344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
325344d411cSMark Johnston 
326344d411cSMark Johnston 	ATF_REQUIRE(close(kq) == 0);
327344d411cSMark Johnston 	ATF_REQUIRE(close(p[0]) == 0);
328344d411cSMark Johnston }
329344d411cSMark Johnston 
330344d411cSMark Johnston ATF_TC_WITHOUT_HEAD(fifo_kqueue__read_eof_state_when_reconnecting);
ATF_TC_BODY(fifo_kqueue__read_eof_state_when_reconnecting,tc)331344d411cSMark Johnston ATF_TC_BODY(fifo_kqueue__read_eof_state_when_reconnecting, tc)
332344d411cSMark Johnston {
333344d411cSMark Johnston 	int p[2] = { -1, -1 };
334344d411cSMark Johnston 
335344d411cSMark Johnston 	ATF_REQUIRE(mkfifo("testfifo", 0600) == 0);
336344d411cSMark Johnston 
337344d411cSMark Johnston 	ATF_REQUIRE((p[0] = open("testfifo",
338344d411cSMark Johnston 	    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
339344d411cSMark Johnston 	ATF_REQUIRE((p[1] = open("testfifo",
340344d411cSMark Johnston 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
341344d411cSMark Johnston 
342344d411cSMark Johnston 	int kq = kqueue();
343344d411cSMark Johnston 	ATF_REQUIRE(kq >= 0);
344344d411cSMark Johnston 
345344d411cSMark Johnston 	struct kevent kev[32];
346344d411cSMark Johnston 
347344d411cSMark Johnston 	EV_SET(&kev[0], p[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
348344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, NULL) == 0);
349344d411cSMark Johnston 
350344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
351344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
352344d411cSMark Johnston 
353344d411cSMark Johnston 	/*
354344d411cSMark Johnston 	 * Closing the writer must trigger a EVFILT_READ edge with EV_EOF set.
355344d411cSMark Johnston 	 */
356344d411cSMark Johnston 
357344d411cSMark Johnston 	ATF_REQUIRE(close(p[1]) == 0);
358344d411cSMark Johnston 
359344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
360344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 1);
361344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
362344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
363344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == (EV_EOF | EV_CLEAR));
364344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
365344d411cSMark Johnston 	ATF_REQUIRE(kev[0].data == 0);
366344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
367344d411cSMark Johnston 
368344d411cSMark Johnston 	/* A new reader shouldn't see the EOF flag. */
369344d411cSMark Johnston 
370344d411cSMark Johnston 	{
371344d411cSMark Johnston 		int new_reader;
372344d411cSMark Johnston 		ATF_REQUIRE((new_reader = open("testfifo",
373344d411cSMark Johnston 		    O_RDONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
374344d411cSMark Johnston 
375344d411cSMark Johnston 		int new_kq = kqueue();
376344d411cSMark Johnston 		ATF_REQUIRE(new_kq >= 0);
377344d411cSMark Johnston 
378344d411cSMark Johnston 		struct kevent new_kev[32];
379344d411cSMark Johnston 		EV_SET(&new_kev[0], new_reader, EVFILT_READ, EV_ADD | EV_CLEAR,
380344d411cSMark Johnston 		    0, 0, 0);
381344d411cSMark Johnston 		ATF_REQUIRE(kevent(new_kq, new_kev, 1, NULL, 0, NULL) == 0);
382344d411cSMark Johnston 
383344d411cSMark Johnston 		ATF_REQUIRE(kevent(new_kq, NULL, 0, new_kev, nitems(new_kev),
384344d411cSMark Johnston 		    &(struct timespec) { 0, 0 }) == 0);
385344d411cSMark Johnston 
386344d411cSMark Johnston 		ATF_REQUIRE(close(new_kq) == 0);
387344d411cSMark Johnston 		ATF_REQUIRE(close(new_reader) == 0);
388344d411cSMark Johnston 	}
389344d411cSMark Johnston 
390344d411cSMark Johnston 	/*
391344d411cSMark Johnston 	 * Simply reopening the writer does not trigger the EVFILT_READ again --
392344d411cSMark Johnston 	 * EV_EOF should be cleared, but there is no data yet so the filter
393344d411cSMark Johnston 	 * does not trigger.
394344d411cSMark Johnston 	 */
395344d411cSMark Johnston 
396344d411cSMark Johnston 	ATF_REQUIRE((p[1] = open("testfifo",
397344d411cSMark Johnston 	    O_WRONLY | O_CLOEXEC | O_NONBLOCK)) >= 0);
398344d411cSMark Johnston 
399344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
400344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 0);
401344d411cSMark Johnston 
402344d411cSMark Johnston 	/* Writing a byte should trigger a EVFILT_READ. */
403344d411cSMark Johnston 
404344d411cSMark Johnston 	char c = 0;
405344d411cSMark Johnston 	ATF_REQUIRE(write(p[1], &c, 1) == 1);
406344d411cSMark Johnston 
407344d411cSMark Johnston 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, nitems(kev),
408344d411cSMark Johnston 	    &(struct timespec) { 0, 0 }) == 1);
409344d411cSMark Johnston 	ATF_REQUIRE(kev[0].ident == (uintptr_t)p[0]);
410344d411cSMark Johnston 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
411344d411cSMark Johnston 	ATF_REQUIRE(kev[0].flags == EV_CLEAR);
412344d411cSMark Johnston 	ATF_REQUIRE(kev[0].fflags == 0);
413344d411cSMark Johnston 	ATF_REQUIRE(kev[0].data == 1);
414344d411cSMark Johnston 	ATF_REQUIRE(kev[0].udata == 0);
415344d411cSMark Johnston 
416344d411cSMark Johnston 	ATF_REQUIRE(close(kq) == 0);
417344d411cSMark Johnston 	ATF_REQUIRE(close(p[0]) == 0);
418344d411cSMark Johnston 	ATF_REQUIRE(close(p[1]) == 0);
419344d411cSMark Johnston }
420344d411cSMark Johnston 
ATF_TP_ADD_TCS(tp)421344d411cSMark Johnston ATF_TP_ADD_TCS(tp)
422344d411cSMark Johnston {
423344d411cSMark Johnston 	ATF_TP_ADD_TC(tp, fifo_kqueue__writes);
424344d411cSMark Johnston 	ATF_TP_ADD_TC(tp, fifo_kqueue__connecting_reader);
425344d411cSMark Johnston 	ATF_TP_ADD_TC(tp, fifo_kqueue__reads);
426344d411cSMark Johnston 	ATF_TP_ADD_TC(tp, fifo_kqueue__read_eof_wakeups);
427344d411cSMark Johnston 	ATF_TP_ADD_TC(tp, fifo_kqueue__read_eof_state_when_reconnecting);
428344d411cSMark Johnston 
429344d411cSMark Johnston 	return atf_no_error();
430344d411cSMark Johnston }
431