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