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