1150022Srwatson/*-
2150022Srwatson * Copyright (c) 2005 Robert N. M. Watson
3150022Srwatson * All rights reserved.
4150022Srwatson *
5150022Srwatson * Redistribution and use in source and binary forms, with or without
6150022Srwatson * modification, are permitted provided that the following conditions
7150022Srwatson * are met:
8150022Srwatson * 1. Redistributions of source code must retain the above copyright
9150022Srwatson *    notice, this list of conditions and the following disclaimer.
10150022Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11150022Srwatson *    notice, this list of conditions and the following disclaimer in the
12150022Srwatson *    documentation and/or other materials provided with the distribution.
13150022Srwatson *
14150022Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15150022Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16150022Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17150022Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18150022Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19150022Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20150022Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21150022Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22150022Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23150022Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24150022Srwatson * SUCH DAMAGE.
25150022Srwatson *
26150022Srwatson * $FreeBSD$
27150022Srwatson */
28150022Srwatson
29150059Srwatson#include <sys/types.h>
30150059Srwatson#include <sys/event.h>
31150091Srwatson#include <sys/ioctl.h>
32150022Srwatson#include <sys/select.h>
33150022Srwatson#include <sys/stat.h>
34150059Srwatson#include <sys/time.h>
35150022Srwatson
36150022Srwatson#include <err.h>
37150022Srwatson#include <errno.h>
38150022Srwatson#include <fcntl.h>
39150022Srwatson#include <limits.h>
40150022Srwatson#include <poll.h>
41150022Srwatson#include <signal.h>
42150022Srwatson#include <stdio.h>
43150022Srwatson#include <stdlib.h>
44150022Srwatson#include <string.h>
45150022Srwatson#include <unistd.h>
46150022Srwatson
47150022Srwatson/*
48150022Srwatson * Regression test to exercise POSIX fifo I/O.
49150022Srwatson *
50150022Srwatson * We test a number of aspect of behavior, including:
51150022Srwatson *
52150022Srwatson * - If there's no data to read, then for blocking fifos, we block, and for
53150022Srwatson *   non-blocking, we return EAGAIN.
54150022Srwatson *
55150022Srwatson * - If we write ten bytes, ten bytes can be read, and they're the same
56150022Srwatson *   bytes, in the same order.
57150022Srwatson *
58150022Srwatson * - If we write two batches of five bytes, we can read the same ten bytes in
59150022Srwatson *   one read of ten bytes.
60150022Srwatson *
61150022Srwatson * - If we write ten bytes, we can read the same ten bytes in two reads of
62150022Srwatson *   five bytes each.
63150022Srwatson *
64150022Srwatson * - If we over-fill a buffer (by writing 512k, which we take to be a large
65150022Srwatson *   number above default buffer sizes), we block if there is no reader.
66150022Srwatson *
67150022Srwatson * - That once 512k (ish) is read from the other end, the blocked writer
68150022Srwatson *   wakes up.
69150022Srwatson *
70150091Srwatson * - When a fifo is empty, poll, select, kqueue, and fionread report it is
71150091Srwatson *   writable but not readable.
72150022Srwatson *
73150091Srwatson * - When a fifo has data in it, poll, select, and kqueue report that it is
74150091Srwatson *   writable.
75150022Srwatson *
76150022Srwatson * - XXX: blocked reader semantics?
77150022Srwatson *
78150091Srwatson * - XXX: event behavior on remote close?
79150093Srwatson *
80150093Srwatson * Although behavior of O_RDWR isn't defined for fifos by POSIX, we expect
81150093Srwatson * "reasonable" behavior, and run some additional tests relating to event
82150093Srwatson * management on O_RDWR fifo descriptors.
83150022Srwatson */
84150022Srwatson
85150093Srwatson#define	KQUEUE_MAX_EVENT	8
86150093Srwatson
87150022Srwatson/*
88150022Srwatson * All activity occurs within a temporary directory created early in the
89150022Srwatson * test.
90150022Srwatson */
91281450Sngiestatic char	temp_dir[PATH_MAX];
92150022Srwatson
93150022Srwatsonstatic void __unused
94150022Srwatsonatexit_temp_dir(void)
95150022Srwatson{
96150022Srwatson
97150022Srwatson	rmdir(temp_dir);
98150022Srwatson}
99150022Srwatson
100150022Srwatsonstatic void
101150022Srwatsonmakefifo(const char *fifoname, const char *testname)
102150022Srwatson{
103150022Srwatson
104150022Srwatson	if (mkfifo(fifoname, 0700) < 0)
105150022Srwatson		err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname);
106150022Srwatson}
107150022Srwatson
108150022Srwatsonstatic void
109150093Srwatsoncleanfifo2(const char *fifoname, int fd1, int fd2)
110150022Srwatson{
111150022Srwatson
112150022Srwatson	if (fd1 != -1)
113150022Srwatson		close(fd1);
114150022Srwatson	if (fd2 != -1)
115150022Srwatson		close(fd2);
116150022Srwatson	(void)unlink(fifoname);
117150022Srwatson}
118150022Srwatson
119150059Srwatsonstatic void
120150093Srwatsoncleanfifo3(const char *fifoname, int fd1, int fd2, int fd3)
121150059Srwatson{
122150059Srwatson
123150059Srwatson	if (fd3 != -1)
124150059Srwatson		close(fd3);
125150093Srwatson	cleanfifo2(fifoname, fd1, fd2);
126150059Srwatson}
127150059Srwatson
128150093Srwatson/*
129150093Srwatson * Open two different file descriptors for a fifo: one read, one write.  Do
130150093Srwatson * so using non-blocking opens in order to avoid deadlocking the process.
131150093Srwatson */
132150022Srwatsonstatic int
133281450Sngieopenfifo(const char *fifoname, int *reader_fdp, int *writer_fdp)
134150022Srwatson{
135150022Srwatson	int error, fd1, fd2;
136150022Srwatson
137150022Srwatson	fd1 = open(fifoname, O_RDONLY | O_NONBLOCK);
138150022Srwatson	if (fd1 < 0)
139150022Srwatson		return (-1);
140150022Srwatson	fd2 = open(fifoname, O_WRONLY | O_NONBLOCK);
141150022Srwatson	if (fd2 < 0) {
142150022Srwatson		error = errno;
143150022Srwatson		close(fd1);
144150022Srwatson		errno = error;
145150022Srwatson		return (-1);
146150022Srwatson	}
147150022Srwatson	*reader_fdp = fd1;
148150022Srwatson	*writer_fdp = fd2;
149150022Srwatson
150150022Srwatson	return (0);
151150022Srwatson}
152150022Srwatson
153150093Srwatson/*
154150093Srwatson * Open one file descriptor for the fifo, supporting both read and write.
155150093Srwatson */
156150022Srwatsonstatic int
157281450Sngieopenfifo_rw(const char *fifoname, int *fdp)
158150093Srwatson{
159150093Srwatson	int fd;
160150093Srwatson
161150093Srwatson	fd = open(fifoname, O_RDWR);
162150093Srwatson	if (fd < 0)
163150093Srwatson		return (-1);
164150093Srwatson	*fdp = fd;
165150093Srwatson
166150093Srwatson	return (0);
167150093Srwatson}
168150093Srwatson
169150093Srwatsonstatic int
170150022Srwatsonset_nonblocking(int fd, const char *testname)
171150022Srwatson{
172150022Srwatson	int flags;
173150022Srwatson
174150022Srwatson	flags = fcntl(fd, F_GETFL);
175150022Srwatson	if (flags < 0) {
176150022Srwatson		warn("%s: fcntl(fd, F_GETFL)", testname);
177150022Srwatson		return(-1);
178150022Srwatson	}
179150022Srwatson
180150022Srwatson	flags |= O_NONBLOCK;
181150022Srwatson
182150022Srwatson	if (fcntl(fd, F_SETFL, flags) < 0) {
183150022Srwatson		warn("%s: fcntl(fd, 0x%x)", testname, flags);
184150022Srwatson		return (-1);
185150022Srwatson	}
186150022Srwatson
187150022Srwatson	return (0);
188150022Srwatson}
189150022Srwatson
190150022Srwatsonstatic int
191150022Srwatsonset_blocking(int fd, const char *testname)
192150022Srwatson{
193150022Srwatson	int flags;
194150022Srwatson
195150022Srwatson	flags = fcntl(fd, F_GETFL);
196150022Srwatson	if (flags < 0) {
197150022Srwatson		warn("%s: fcntl(fd, F_GETFL)", testname);
198150022Srwatson		return(-1);
199150022Srwatson	}
200150022Srwatson
201150022Srwatson	flags &= ~O_NONBLOCK;
202150022Srwatson
203150022Srwatson	if (fcntl(fd, F_SETFL, flags) < 0) {
204150022Srwatson		warn("%s: fcntl(fd, 0x%x)", testname, flags);
205150022Srwatson		return (-1);
206150022Srwatson	}
207150022Srwatson
208150022Srwatson	return (0);
209150022Srwatson}
210150022Srwatson
211150022Srwatson/*
212150022Srwatson * Drain a file descriptor (fifo) of any readable data.  Note: resets the
213150022Srwatson * blocking state.
214150022Srwatson */
215150022Srwatsonstatic int
216150022Srwatsondrain_fd(int fd, const char *testname)
217150022Srwatson{
218150022Srwatson	ssize_t len;
219150022Srwatson	u_char ch;
220150022Srwatson
221150022Srwatson	if (set_nonblocking(fd, testname) < 0)
222150022Srwatson		return (-1);
223150022Srwatson
224150022Srwatson	while ((len = read(fd, &ch, sizeof(ch))) > 0);
225150022Srwatson	if (len < 0) {
226150022Srwatson		switch (errno) {
227150022Srwatson		case EAGAIN:
228150022Srwatson			return (0);
229150022Srwatson		default:
230150022Srwatson			warn("%s: drain_fd: read", testname);
231150022Srwatson			return (-1);
232150022Srwatson		}
233150022Srwatson	}
234150022Srwatson	warn("%s: drain_fd: read: returned 0 bytes", testname);
235150022Srwatson	return (-1);
236150022Srwatson}
237150022Srwatson
238150022Srwatson/*
239150022Srwatson * Simple I/O test: write ten integers, and make sure we get back the same
240150022Srwatson * integers in the same order.  This assumes a minimum fifo buffer > 10
241150022Srwatson * bytes in order to not block and deadlock.
242150022Srwatson */
243150022Srwatsonstatic void
244150022Srwatsontest_simpleio(void)
245150022Srwatson{
246150022Srwatson	int i, reader_fd, writer_fd;
247150022Srwatson	u_char buffer[10];
248150022Srwatson	ssize_t len;
249150022Srwatson
250150022Srwatson	makefifo("testfifo", __func__);
251281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd)
252150022Srwatson	    < 0) {
253150022Srwatson		warn("test_simpleio: openfifo: testfifo");
254150093Srwatson		cleanfifo2("testfifo", -1, -1);
255150022Srwatson		exit(-1);
256150022Srwatson	}
257150022Srwatson
258150022Srwatson	for (i = 0; i < 10; i++)
259150022Srwatson		buffer[i] = i;
260150022Srwatson
261150022Srwatson	len = write(writer_fd, (char *)buffer, sizeof(buffer));
262150022Srwatson	if (len < 0) {
263150022Srwatson		warn("test_simpleio: write");
264150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
265150022Srwatson		exit(-1);
266150022Srwatson	}
267150022Srwatson	if (len != sizeof(buffer)) {
268164083Sjkim		warnx("test_simplio: tried %zu but wrote %zd", sizeof(buffer),
269150022Srwatson		    len);
270150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
271150022Srwatson		exit(-1);
272150022Srwatson	}
273150022Srwatson
274150022Srwatson	len = read(reader_fd, (char *)buffer, sizeof(buffer));
275150022Srwatson	if (len < 0) {
276150022Srwatson		warn("test_simpleio: read");
277150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
278150022Srwatson		exit(-1);
279150022Srwatson	}
280150022Srwatson	if (len != sizeof(buffer)) {
281164083Sjkim		warnx("test_simpleio: tried %zu but read %zd", sizeof(buffer),
282150022Srwatson		    len);
283150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
284150022Srwatson		exit(-1);
285150022Srwatson	}
286150022Srwatson	for (i = 0; i < 10; i++) {
287150022Srwatson		if (buffer[i] == i)
288150022Srwatson			continue;
289150022Srwatson		warnx("test_simpleio: write byte %d as 0x%02x, but read "
290150022Srwatson		    "0x%02x", i, i, buffer[i]);
291150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
292150022Srwatson		exit(-1);
293150022Srwatson	}
294150022Srwatson
295150093Srwatson	cleanfifo2("testfifo", reader_fd, writer_fd);
296150022Srwatson}
297150022Srwatson
298281450Sngiestatic volatile int alarm_fired;
299150022Srwatson/*
300150022Srwatson * Non-destructive SIGALRM handler.
301150022Srwatson */
302150022Srwatsonstatic void
303281450Sngiesigalarm(int signum __unused)
304150022Srwatson{
305150022Srwatson
306150022Srwatson	alarm_fired = 1;
307150022Srwatson}
308150022Srwatson
309150022Srwatson/*
310150022Srwatson * Wrapper function for write, which uses a timer to interrupt any blocking.
311150022Srwatson * Because we can't reliably detect EINTR for blocking I/O, we also track
312150022Srwatson * whether or not our timeout fired.
313150022Srwatson */
314150022Srwatsonstatic int __unused
315150022Srwatsontimed_write(int fd, void *data, size_t len, ssize_t *written_lenp,
316150022Srwatson    int timeout, int *timedoutp, const char *testname)
317150022Srwatson{
318150022Srwatson	struct sigaction act, oact;
319150022Srwatson	ssize_t written_len;
320150022Srwatson	int error;
321150022Srwatson
322150022Srwatson	alarm_fired = 0;
323150022Srwatson	bzero(&act, sizeof(oact));
324150022Srwatson	act.sa_handler = sigalarm;
325150022Srwatson	if (sigaction(SIGALRM, &act, &oact) < 0) {
326150022Srwatson	 	warn("%s: timed_write: sigaction", testname);
327150022Srwatson		return (-1);
328150022Srwatson	}
329150022Srwatson	alarm(timeout);
330150022Srwatson	written_len = write(fd, data, len);
331150022Srwatson	error = errno;
332150022Srwatson	alarm(0);
333150022Srwatson	if (sigaction(SIGALRM, &oact, NULL) < 0) {
334150022Srwatson	 	warn("%s: timed_write: sigaction", testname);
335150022Srwatson		return (-1);
336150022Srwatson	}
337150022Srwatson	if (alarm_fired)
338150022Srwatson		*timedoutp = 1;
339150022Srwatson	else
340150022Srwatson		*timedoutp = 0;
341150022Srwatson
342150022Srwatson	errno = error;
343150022Srwatson	if (written_len < 0)
344150022Srwatson		return (-1);
345150022Srwatson	*written_lenp = written_len;
346150022Srwatson	return (0);
347150022Srwatson}
348150022Srwatson
349150022Srwatson/*
350150022Srwatson * Wrapper function for read, which uses a timer to interrupt any blocking.
351150022Srwatson * Because we can't reliably detect EINTR for blocking I/O, we also track
352150022Srwatson * whether or not our timeout fired.
353150022Srwatson */
354150022Srwatsonstatic int
355150022Srwatsontimed_read(int fd, void *data, size_t len, ssize_t *read_lenp,
356150022Srwatson    int timeout, int *timedoutp, const char *testname)
357150022Srwatson{
358150022Srwatson	struct sigaction act, oact;
359150022Srwatson	ssize_t read_len;
360150022Srwatson	int error;
361150022Srwatson
362150022Srwatson	alarm_fired = 0;
363150022Srwatson	bzero(&act, sizeof(oact));
364150022Srwatson	act.sa_handler = sigalarm;
365150022Srwatson	if (sigaction(SIGALRM, &act, &oact) < 0) {
366150022Srwatson	 	warn("%s: timed_write: sigaction", testname);
367150022Srwatson		return (-1);
368150022Srwatson	}
369150022Srwatson	alarm(timeout);
370150022Srwatson	read_len = read(fd, data, len);
371150022Srwatson	error = errno;
372150022Srwatson	alarm(0);
373150022Srwatson	if (sigaction(SIGALRM, &oact, NULL) < 0) {
374150022Srwatson	 	warn("%s: timed_write: sigaction", testname);
375150022Srwatson		return (-1);
376150022Srwatson	}
377150022Srwatson	if (alarm_fired)
378150022Srwatson		*timedoutp = 1;
379150022Srwatson	else
380150022Srwatson		*timedoutp = 0;
381150022Srwatson
382150022Srwatson	errno = error;
383150022Srwatson	if (read_len < 0)
384150022Srwatson		return (-1);
385150022Srwatson	*read_lenp = read_len;
386150022Srwatson	return (0);
387150022Srwatson}
388150022Srwatson
389150022Srwatson/*
390150022Srwatson * This test operates on blocking and non-blocking fifo file descriptors, in
391150022Srwatson * order to determine whether they block at good moments or not.  By good we
392150022Srwatson * mean: don't block for non-blocking sockets, and do block for blocking
393150022Srwatson * ones, assuming there isn't I/O buffer to satisfy the request.
394150022Srwatson *
395150022Srwatson * We use a timeout of 5 seconds, concluding that in 5 seconds either all I/O
396150022Srwatson * that can take place will, and that if we reach the end of the timeout,
397228975Suqs * then blocking has occurred.
398150022Srwatson *
399150022Srwatson * We assume that the buffer size on a fifo is <512K, and as such, that
400150022Srwatson * writing that much data without an active reader will result in blocking.
401150022Srwatson */
402150022Srwatsonstatic void
403150022Srwatsontest_blocking_read_empty(void)
404150022Srwatson{
405150022Srwatson	int reader_fd, ret, timedout, writer_fd;
406150022Srwatson	ssize_t len;
407150022Srwatson	u_char ch;
408150022Srwatson
409150022Srwatson	makefifo("testfifo", __func__);
410281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd)
411150022Srwatson	    < 0) {
412150022Srwatson		warn("test_blocking_read_empty: openfifo: testfifo");
413150093Srwatson		cleanfifo2("testfifo", -1, -1);
414150022Srwatson		exit(-1);
415150022Srwatson	}
416150022Srwatson
417150022Srwatson	/*
418150022Srwatson	 * Read one byte from an empty blocking fifo, block as there is no
419150022Srwatson	 * data.
420150022Srwatson	 */
421150022Srwatson	if (set_blocking(reader_fd, __func__) < 0) {
422150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
423150022Srwatson		exit(-1);
424150022Srwatson	}
425150022Srwatson
426150022Srwatson	ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout,
427150022Srwatson	    __func__);
428150022Srwatson	if (ret != -1) {
429150022Srwatson		warnx("test_blocking_read_empty: timed_read: returned "
430150022Srwatson		    "success");
431150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
432150022Srwatson		exit(-1);
433150022Srwatson	}
434150022Srwatson	if (errno != EINTR) {
435150022Srwatson		warn("test_blocking_read_empty: timed_read");
436150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
437150022Srwatson		exit(-1);
438150022Srwatson	}
439150022Srwatson
440150022Srwatson	/*
441150022Srwatson	 * Read one byte from an empty non-blocking fifo, return EAGAIN as
442150022Srwatson	 * there is no data.
443150022Srwatson	 */
444150022Srwatson	if (set_nonblocking(reader_fd, __func__) < 0) {
445150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
446150022Srwatson		exit(-1);
447150022Srwatson	}
448150022Srwatson
449150022Srwatson	ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout,
450150022Srwatson	    __func__);
451150022Srwatson	if (ret != -1) {
452150022Srwatson		warnx("test_blocking_read_empty: timed_read: returned "
453150022Srwatson		    "success");
454150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
455150022Srwatson		exit(-1);
456150022Srwatson	}
457150022Srwatson	if (errno != EAGAIN) {
458150022Srwatson		warn("test_blocking_read_empty: timed_read");
459150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
460150022Srwatson		exit(-1);
461150022Srwatson	}
462150022Srwatson
463150093Srwatson	cleanfifo2("testfifo", reader_fd, writer_fd);
464150022Srwatson}
465150022Srwatson
466150022Srwatson/*
467150022Srwatson * Write one byte to an empty fifo, then try to read one byte and make sure
468150022Srwatson * we don't block in either the write or the read.  This tests both for
469150022Srwatson * improper blocking in the send and receive code.
470150022Srwatson */
471150022Srwatsonstatic void
472150022Srwatsontest_blocking_one_byte(void)
473150022Srwatson{
474150022Srwatson	int reader_fd, ret, timedout, writer_fd;
475150022Srwatson	ssize_t len;
476150022Srwatson	u_char ch;
477150022Srwatson
478150022Srwatson	makefifo("testfifo", __func__);
479281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
480150022Srwatson		warn("test_blocking: openfifo: testfifo");
481150093Srwatson		cleanfifo2("testfifo", -1, -1);
482150022Srwatson		exit(-1);
483150022Srwatson	}
484150022Srwatson
485150022Srwatson	if (set_blocking(writer_fd, __func__) < 0) {
486150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
487150022Srwatson		exit(-1);
488150022Srwatson	}
489150022Srwatson	if (set_blocking(reader_fd, __func__) < 0) {
490150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
491150022Srwatson		exit(-1);
492150022Srwatson	}
493150022Srwatson
494150022Srwatson	ch = 0xfe;
495150022Srwatson	ret = timed_write(writer_fd, &ch, sizeof(ch), &len, 5, &timedout,
496150022Srwatson	    __func__);
497150022Srwatson	if (ret < 0) {
498150022Srwatson		warn("test_blocking_one_byte: timed_write");
499150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
500150022Srwatson		exit(-1);
501150022Srwatson	}
502150022Srwatson	if (len != sizeof(ch)) {
503150022Srwatson		warnx("test_blocking_one_byte: timed_write: tried to write "
504164083Sjkim		    "%zu, wrote %zd", sizeof(ch), len);
505150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
506150022Srwatson		exit(-1);
507150022Srwatson	}
508150022Srwatson
509150022Srwatson	ch = 0xab;
510150022Srwatson	ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout,
511150022Srwatson	    __func__);
512150022Srwatson	if (ret < 0) {
513150022Srwatson		warn("test_blocking_one_byte: timed_read");
514150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
515150022Srwatson		exit(-1);
516150022Srwatson	}
517150022Srwatson	if (len != sizeof(ch)) {
518164083Sjkim		warnx("test_blocking_one_byte: timed_read: wanted %zu, "
519164083Sjkim		    "read %zd", sizeof(ch), len);
520150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
521150022Srwatson		exit(-1);
522150022Srwatson	}
523150022Srwatson	if (ch != 0xfe) {
524150022Srwatson		warnx("test_blocking_one_byte: timed_read: expected to read "
525150022Srwatson		    "0x%02x, read 0x%02x", 0xfe, ch);
526150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
527150022Srwatson		exit(-1);
528150022Srwatson	}
529150022Srwatson
530150093Srwatson	cleanfifo2("testfifo", reader_fd, writer_fd);
531150022Srwatson}
532150022Srwatson
533150022Srwatson/*
534150022Srwatson * Write one byte to an empty fifo, then try to read one byte and make sure
535150022Srwatson * we don't get back EAGAIN.
536150022Srwatson */
537150022Srwatsonstatic void
538150022Srwatsontest_nonblocking_one_byte(void)
539150022Srwatson{
540150022Srwatson	int reader_fd, ret, timedout, writer_fd;
541150022Srwatson	ssize_t len;
542150022Srwatson	u_char ch;
543150022Srwatson
544150022Srwatson	makefifo("testfifo", __func__);
545281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
546150022Srwatson		warn("test_nonblocking: openfifo: testfifo");
547150093Srwatson		cleanfifo2("testfifo", -1, -1);
548150022Srwatson		exit(-1);
549150022Srwatson	}
550150022Srwatson
551150022Srwatson	if (set_nonblocking(reader_fd, __func__) < 0) {
552150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
553150022Srwatson		exit(-1);
554150022Srwatson	}
555150022Srwatson
556150022Srwatson	ch = 0xfe;
557150022Srwatson	ret = timed_write(writer_fd, &ch, sizeof(ch), &len, 5, &timedout,
558150022Srwatson	    __func__);
559150022Srwatson	if (ret < 0) {
560150022Srwatson		warn("test_nonblocking_one_byte: timed_write");
561150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
562150022Srwatson		exit(-1);
563150022Srwatson	}
564150022Srwatson	if (len != sizeof(ch)) {
565150022Srwatson		warnx("test_nonblocking_one_byte: timed_write: tried to write "
566164083Sjkim		    "%zu, wrote %zd", sizeof(ch), len);
567150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
568150022Srwatson		exit(-1);
569150022Srwatson	}
570150022Srwatson
571150022Srwatson	ch = 0xab;
572150022Srwatson	ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout,
573150022Srwatson	    __func__);
574150022Srwatson	if (ret < 0) {
575150022Srwatson		warn("test_nonblocking_one_byte: timed_read");
576150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
577150022Srwatson		exit(-1);
578150022Srwatson	}
579150022Srwatson	if (len != sizeof(ch)) {
580164083Sjkim		warnx("test_nonblocking_one_byte: timed_read: wanted %zu, read "
581164083Sjkim		    "%zd", sizeof(ch), len);
582150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
583150022Srwatson		exit(-1);
584150022Srwatson	}
585150022Srwatson	if (ch != 0xfe) {
586150022Srwatson		warnx("test_nonblocking_one_byte: timed_read: expected to read "
587150022Srwatson		    "0x%02x, read 0x%02x", 0xfe, ch);
588150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
589150022Srwatson		exit(-1);
590150022Srwatson	}
591150022Srwatson
592150093Srwatson	cleanfifo2("testfifo", reader_fd, writer_fd);
593150022Srwatson}
594150022Srwatson
595150022Srwatson/*
596150022Srwatson * First of two test cases involving a 512K buffer: write the buffer into a
597150022Srwatson * blocking file descriptor.  We'd like to know it blocks, but the closest we
598150022Srwatson * can get is to see if SIGALRM fired during the I/O resulting in a partial
599150022Srwatson * write.
600150022Srwatson */
601150022Srwatsonstatic void
602150022Srwatsontest_blocking_partial_write(void)
603150022Srwatson{
604150022Srwatson	int reader_fd, ret, timedout, writer_fd;
605150022Srwatson	u_char *buffer;
606150022Srwatson	ssize_t len;
607150022Srwatson
608150022Srwatson	makefifo("testfifo", __func__);
609281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
610150022Srwatson		warn("test_blocking_partial_write: openfifo: testfifo");
611150093Srwatson		cleanfifo2("testfifo", -1, -1);
612150022Srwatson		exit(-1);
613150022Srwatson	}
614150022Srwatson
615150022Srwatson	if (set_blocking(writer_fd, __func__) < 0) {
616150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
617150022Srwatson		exit(-1);
618150022Srwatson	}
619150022Srwatson
620150022Srwatson	buffer = malloc(512*1024);
621150022Srwatson	if (buffer == NULL) {
622150022Srwatson		warn("test_blocking_partial_write: malloc");
623150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
624150022Srwatson		exit(-1);
625150022Srwatson	}
626150022Srwatson	bzero(buffer, 512*1024);
627150022Srwatson
628150022Srwatson	ret = timed_write(writer_fd, buffer, 512*1024, &len, 5, &timedout,
629150022Srwatson	    __func__);
630150022Srwatson	if (ret < 0) {
631150022Srwatson		warn("test_blocking_partial_write: timed_write");
632150022Srwatson		free(buffer);
633150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
634150022Srwatson		exit(-1);
635150022Srwatson	}
636150022Srwatson
637150022Srwatson	if (!timedout) {
638150022Srwatson		warnx("test_blocking_partial_write: timed_write: blocking "
639150022Srwatson		    "socket didn't time out");
640150022Srwatson		free(buffer);
641150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
642150022Srwatson		exit(-1);
643150022Srwatson	}
644150022Srwatson
645150022Srwatson	free(buffer);
646150022Srwatson
647150022Srwatson	if (drain_fd(reader_fd, __func__) < 0) {
648150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
649150022Srwatson		exit(-1);
650150022Srwatson	}
651150022Srwatson
652150093Srwatson	cleanfifo2("testfifo", reader_fd, writer_fd);
653150022Srwatson}
654150022Srwatson
655150022Srwatson/*
656150022Srwatson * Write a 512K buffer to an empty fifo using a non-blocking file descriptor,
657150022Srwatson * and make sure it doesn't block.
658150022Srwatson */
659150022Srwatsonstatic void
660150022Srwatsontest_nonblocking_partial_write(void)
661150022Srwatson{
662150022Srwatson	int reader_fd, ret, timedout, writer_fd;
663150022Srwatson	u_char *buffer;
664150022Srwatson	ssize_t len;
665150022Srwatson
666150022Srwatson	makefifo("testfifo", __func__);
667281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
668150022Srwatson		warn("test_blocking_partial_write: openfifo: testfifo");
669150093Srwatson		cleanfifo2("testfifo", -1, -1);
670150022Srwatson		exit(-1);
671150022Srwatson	}
672150022Srwatson
673150022Srwatson	if (set_nonblocking(writer_fd, __func__) < 0) {
674150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
675150022Srwatson		exit(-1);
676150022Srwatson	}
677150022Srwatson
678150022Srwatson	buffer = malloc(512*1024);
679150022Srwatson	if (buffer == NULL) {
680150022Srwatson		warn("test_blocking_partial_write: malloc");
681150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
682150022Srwatson		exit(-1);
683150022Srwatson	}
684150022Srwatson	bzero(buffer, 512*1024);
685150022Srwatson
686150022Srwatson	ret = timed_write(writer_fd, buffer, 512*1024, &len, 5, &timedout,
687150022Srwatson	    __func__);
688150022Srwatson	if (ret < 0) {
689150022Srwatson		warn("test_blocking_partial_write: timed_write");
690150022Srwatson		free(buffer);
691150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
692150022Srwatson		exit(-1);
693150022Srwatson	}
694150022Srwatson
695150022Srwatson	if (timedout) {
696150022Srwatson		warnx("test_blocking_partial_write: timed_write: "
697150022Srwatson		    "non-blocking socket timed out");
698150022Srwatson		free(buffer);
699150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
700150022Srwatson		exit(-1);
701150022Srwatson	}
702150022Srwatson
703150022Srwatson	if (len == 0 || len >= 512*1024) {
704150022Srwatson		warnx("test_blocking_partial_write: timed_write: requested "
705164083Sjkim		    "%d, sent %zd", 512*1024, len);
706150022Srwatson		free(buffer);
707150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
708150022Srwatson		exit(-1);
709150022Srwatson	}
710150022Srwatson
711150022Srwatson	free(buffer);
712150022Srwatson
713150022Srwatson	if (drain_fd(reader_fd, __func__) < 0) {
714150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
715150022Srwatson		exit(-1);
716150022Srwatson	}
717150022Srwatson
718150093Srwatson	cleanfifo2("testfifo", reader_fd, writer_fd);
719150022Srwatson}
720150022Srwatson
721150022Srwatson/*
722150022Srwatson * test_coalesce_big_read() verifies that data mingles in the fifo across
723150022Srwatson * message boundaries by performing two small writes, then a bigger read
724150022Srwatson * that should return data from both writes.
725150022Srwatson */
726150022Srwatsonstatic void
727150022Srwatsontest_coalesce_big_read(void)
728150022Srwatson{
729150022Srwatson	int i, reader_fd, writer_fd;
730150022Srwatson	u_char buffer[10];
731150022Srwatson	ssize_t len;
732150022Srwatson
733150022Srwatson	makefifo("testfifo", __func__);
734281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
735150022Srwatson		warn("test_coalesce_big_read: openfifo: testfifo");
736150093Srwatson		cleanfifo2("testfifo", -1, -1);
737150022Srwatson		exit(-1);
738150022Srwatson	}
739150022Srwatson
740150022Srwatson	/* Write five, write five, read ten. */
741150022Srwatson	for (i = 0; i < 10; i++)
742150022Srwatson		buffer[i] = i;
743150022Srwatson
744150022Srwatson	len = write(writer_fd, buffer, 5);
745150022Srwatson	if (len < 0) {
746150022Srwatson		warn("test_coalesce_big_read: write 5");
747150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
748150022Srwatson		exit(-1);
749150022Srwatson	}
750150022Srwatson	if (len != 5) {
751164083Sjkim		warnx("test_coalesce_big_read: write 5 wrote %zd", len);
752150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
753150022Srwatson		exit(-1);
754150022Srwatson	}
755150022Srwatson
756150022Srwatson	len = write(writer_fd, buffer + 5, 5);
757150022Srwatson	if (len < 0) {
758150022Srwatson		warn("test_coalesce_big_read: write 5");
759150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
760150022Srwatson		exit(-1);
761150022Srwatson	}
762150022Srwatson	if (len != 5) {
763164083Sjkim		warnx("test_coalesce_big_read: write 5 wrote %zd", len);
764150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
765150022Srwatson		exit(-1);
766150022Srwatson	}
767150022Srwatson
768150022Srwatson	len = read(reader_fd, buffer, 10);
769150022Srwatson	if (len < 0) {
770150022Srwatson		warn("test_coalesce_big_read: read 10");
771150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
772150022Srwatson		exit(-1);
773150022Srwatson	}
774150022Srwatson	if (len != 10) {
775164083Sjkim		warnx("test_coalesce_big_read: read 10 read %zd", len);
776150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
777150022Srwatson		exit(-1);
778150022Srwatson	}
779150022Srwatson
780150022Srwatson	for (i = 0; i < 10; i++) {
781150022Srwatson		if (buffer[i] == i)
782150022Srwatson			continue;
783150022Srwatson		warnx("test_coalesce_big_read: expected to read 0x%02x, "
784150022Srwatson		    "read 0x%02x", i, buffer[i]);
785150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
786150022Srwatson		exit(-1);
787150022Srwatson	}
788150022Srwatson
789150093Srwatson	cleanfifo2("testfifo", -1, -1);
790150022Srwatson}
791150022Srwatson
792150022Srwatson/*
793150022Srwatson * test_coalesce_big_write() verifies that data mingles in the fifo across
794150022Srwatson * message boundaries by performing one big write, then two smaller reads
795150022Srwatson * that should return sequential elements of data from the write.
796150022Srwatson */
797150022Srwatsonstatic void
798150022Srwatsontest_coalesce_big_write(void)
799150022Srwatson{
800150022Srwatson	int i, reader_fd, writer_fd;
801150022Srwatson	u_char buffer[10];
802150022Srwatson	ssize_t len;
803150022Srwatson
804150022Srwatson	makefifo("testfifo", __func__);
805281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
806150022Srwatson		warn("test_coalesce_big_write: openfifo: testfifo");
807150093Srwatson		cleanfifo2("testfifo", -1, -1);
808150022Srwatson		exit(-1);
809150022Srwatson	}
810150022Srwatson
811150022Srwatson	/* Write ten, read five, read five. */
812150022Srwatson	for (i = 0; i < 10; i++)
813150022Srwatson		buffer[i] = i;
814150022Srwatson
815150022Srwatson	len = write(writer_fd, buffer, 10);
816150022Srwatson	if (len < 0) {
817150022Srwatson		warn("test_coalesce_big_write: write 10");
818150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
819150022Srwatson		exit(-1);
820150022Srwatson	}
821150022Srwatson	if (len != 10) {
822164083Sjkim		warnx("test_coalesce_big_write: write 10 wrote %zd", len);
823150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
824150022Srwatson		exit(-1);
825150022Srwatson	}
826150022Srwatson
827150022Srwatson	len = read(reader_fd, buffer, 5);
828150022Srwatson	if (len < 0) {
829150022Srwatson		warn("test_coalesce_big_write: read 5");
830150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
831150022Srwatson		exit(-1);
832150022Srwatson	}
833150022Srwatson	if (len != 5) {
834164083Sjkim		warnx("test_coalesce_big_write: read 5 read %zd", len);
835150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
836150022Srwatson		exit(-1);
837150022Srwatson	}
838150022Srwatson
839150022Srwatson	len = read(reader_fd, buffer + 5, 5);
840150022Srwatson	if (len < 0) {
841150022Srwatson		warn("test_coalesce_big_write: read 5");
842150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
843150022Srwatson		exit(-1);
844150022Srwatson	}
845150022Srwatson	if (len != 5) {
846164083Sjkim		warnx("test_coalesce_big_write: read 5 read %zd", len);
847150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
848150022Srwatson		exit(-1);
849150022Srwatson	}
850150022Srwatson
851150022Srwatson	for (i = 0; i < 10; i++) {
852150022Srwatson		if (buffer[i] == i)
853150022Srwatson			continue;
854150022Srwatson		warnx("test_coalesce_big_write: expected to read 0x%02x, "
855150022Srwatson		    "read 0x%02x", i, buffer[i]);
856150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
857150022Srwatson		exit(-1);
858150022Srwatson	}
859150022Srwatson
860150093Srwatson	cleanfifo2("testfifo", -1, -1);
861150022Srwatson}
862150022Srwatson
863150022Srwatsonstatic int
864150022Srwatsonpoll_status(int fd, int *readable, int *writable, int *exception,
865150022Srwatson    const char *testname)
866150022Srwatson{
867150022Srwatson	struct pollfd fds[1];
868150022Srwatson
869150022Srwatson	fds[0].fd = fd;
870150022Srwatson	fds[0].events = POLLIN | POLLOUT | POLLERR;
871150022Srwatson	fds[0].revents = 0;
872150022Srwatson
873150022Srwatson	if (poll(fds, 1, 0) < 0) {
874150022Srwatson		warn("%s: poll", testname);
875150022Srwatson		return (-1);
876150022Srwatson	}
877150022Srwatson	*readable = (fds[0].revents & POLLIN) ? 1 : 0;
878150022Srwatson	*writable = (fds[0].revents & POLLOUT) ? 1 : 0;
879150022Srwatson	*exception = (fds[0].revents & POLLERR) ? 1 : 0;
880150022Srwatson	return (0);
881150022Srwatson}
882150022Srwatson
883150022Srwatsonstatic int
884150022Srwatsonselect_status(int fd, int *readable, int *writable, int *exception,
885150022Srwatson    const char *testname)
886150022Srwatson{
887150022Srwatson	struct fd_set readfds, writefds, exceptfds;
888150022Srwatson	struct timeval timeout;
889150022Srwatson
890150022Srwatson	FD_ZERO(&readfds);
891150022Srwatson	FD_ZERO(&writefds);
892150022Srwatson	FD_ZERO(&exceptfds);
893150022Srwatson	FD_SET(fd, &readfds);
894150022Srwatson	FD_SET(fd, &writefds);
895150022Srwatson	FD_SET(fd, &exceptfds);
896150022Srwatson	timeout.tv_sec = 0;
897150022Srwatson	timeout.tv_usec = 0;
898150059Srwatson	if (select(fd+1, &readfds, &writefds, &exceptfds, &timeout) < 0) {
899150022Srwatson		warn("%s: select", testname);
900150022Srwatson		return (-1);
901150022Srwatson	}
902150022Srwatson	*readable = FD_ISSET(fd, &readfds) ? 1 : 0;
903150022Srwatson	*writable = FD_ISSET(fd, &writefds) ? 1 : 0;
904150022Srwatson	*exception = FD_ISSET(fd, &exceptfds) ? 1 : 0;
905150022Srwatson	return (0);
906150022Srwatson}
907150022Srwatson
908150093Srwatson/*
909150093Srwatson * Given an existing kqueue, set up read and write event filters for the
910150093Srwatson * passed file descriptor.  Typically called once for the read endpoint, and
911150093Srwatson * once for the write endpoint.
912150093Srwatson */
913150059Srwatsonstatic int
914150093Srwatsonkqueue_setup(int kqueue_fd, int fd, const char *testname)
915150059Srwatson{
916150093Srwatson	struct kevent kevent_changelist[2];
917150093Srwatson	struct kevent kevent_eventlist[KQUEUE_MAX_EVENT], *kp;
918150059Srwatson	struct timespec timeout;
919150093Srwatson	int i, ret;
920150059Srwatson
921150059Srwatson	timeout.tv_sec = 0;
922150059Srwatson	timeout.tv_nsec = 0;
923150059Srwatson
924150059Srwatson	bzero(&kevent_changelist, sizeof(kevent_changelist));
925150093Srwatson	EV_SET(&kevent_changelist[0], fd, EVFILT_READ, EV_ADD, 0, 0, 0);
926150093Srwatson	EV_SET(&kevent_changelist[1], fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
927150059Srwatson
928150059Srwatson	bzero(&kevent_eventlist, sizeof(kevent_eventlist));
929150093Srwatson	ret = kevent(kqueue_fd, kevent_changelist, 2, kevent_eventlist,
930150093Srwatson	    KQUEUE_MAX_EVENT, &timeout);
931150059Srwatson	if (ret < 0) {
932150093Srwatson		warn("%s:%s: kevent initial register", testname, __func__);
933150093Srwatson		return (-1);
934150059Srwatson	}
935150059Srwatson
936150059Srwatson	/*
937150093Srwatson	 * Verify that the events registered alright.
938150059Srwatson	 */
939150059Srwatson	for (i = 0; i < ret; i++) {
940150059Srwatson		kp = &kevent_eventlist[i];
941150059Srwatson		if (kp->flags != EV_ERROR)
942150059Srwatson			continue;
943150059Srwatson		errno = kp->data;
944150093Srwatson		warn("%s:%s: kevent register index %d", testname, __func__,
945150093Srwatson		    i);
946150093Srwatson		return (-1);
947150059Srwatson	}
948150059Srwatson
949150059Srwatson	return (0);
950150059Srwatson}
951150059Srwatson
952150059Srwatsonstatic int
953150059Srwatsonkqueue_status(int kqueue_fd, int fd, int *readable, int *writable,
954150059Srwatson    int *exception, const char *testname)
955150059Srwatson{
956150093Srwatson	struct kevent kevent_eventlist[KQUEUE_MAX_EVENT], *kp;
957150059Srwatson	struct timespec timeout;
958150093Srwatson	int i, ret;
959150059Srwatson
960150059Srwatson	timeout.tv_sec = 0;
961150059Srwatson	timeout.tv_nsec = 0;
962150059Srwatson
963150093Srwatson	ret = kevent(kqueue_fd, NULL, 0, kevent_eventlist, KQUEUE_MAX_EVENT,
964150093Srwatson	    &timeout);
965150093Srwatson	if (ret < 0) {
966150093Srwatson		warn("%s: %s: kevent", testname, __func__);
967150059Srwatson		return (-1);
968150059Srwatson	}
969150059Srwatson
970150059Srwatson	*readable = *writable = *exception = 0;
971150093Srwatson	for (i = 0; i < ret; i++) {
972150059Srwatson		kp = &kevent_eventlist[i];
973150059Srwatson		if (kp->ident != (u_int)fd)
974150059Srwatson			continue;
975150059Srwatson		if (kp->filter == EVFILT_READ)
976150059Srwatson			*readable = 1;
977150059Srwatson		if (kp->filter == EVFILT_WRITE)
978150059Srwatson			*writable = 1;
979150059Srwatson	}
980150059Srwatson
981150059Srwatson	return (0);
982150059Srwatson}
983150059Srwatson
984150091Srwatsonstatic int
985150091Srwatsonfionread_status(int fd, int *readable, const char *testname)
986150091Srwatson{
987150091Srwatson	int i;
988150091Srwatson
989150091Srwatson	if (ioctl(fd, FIONREAD, &i) < 0) {
990150091Srwatson		warn("%s: ioctl(FIONREAD)", testname);
991150091Srwatson		return (-1);
992150091Srwatson	}
993150091Srwatson
994150091Srwatson	if (i > 0)
995150091Srwatson		*readable = 1;
996150091Srwatson	else
997150091Srwatson		*readable = 0;
998150091Srwatson	return (0);
999150091Srwatson}
1000150091Srwatson
1001150093Srwatson#define	READABLE	1
1002150093Srwatson#define	WRITABLE	1
1003150093Srwatson#define	EXCEPTION	1
1004150093Srwatson
1005150093Srwatson#define	NOT_READABLE	0
1006150093Srwatson#define	NOT_WRITABLE	0
1007150093Srwatson#define	NOT_EXCEPTION	0
1008150093Srwatson
1009150093Srwatsonstatic int
1010150093Srwatsonassert_status(int fd, int kqueue_fd, int assert_readable,
1011150093Srwatson    int assert_writable, int assert_exception, const char *testname,
1012150093Srwatson    const char *conditionname, const char *fdname)
1013150093Srwatson{
1014150093Srwatson	int readable, writable, exception;
1015150093Srwatson
1016150093Srwatson	if (poll_status(fd, &readable, &writable, &exception, testname) < 0)
1017150093Srwatson		return (-1);
1018150093Srwatson
1019150093Srwatson	if (readable != assert_readable || writable != assert_writable ||
1020150093Srwatson	    exception != assert_exception) {
1021150093Srwatson		warnx("%s: %s polls r:%d, w:%d, e:%d on %s", testname,
1022150093Srwatson		    fdname, readable, writable, exception, conditionname);
1023150093Srwatson		return (-1);
1024150093Srwatson	}
1025150093Srwatson
1026150093Srwatson	if (select_status(fd, &readable, &writable, &exception, testname) < 0)
1027150093Srwatson		return (-1);
1028150093Srwatson
1029150093Srwatson	if (readable != assert_readable || writable != assert_writable ||
1030150093Srwatson	    exception != assert_exception) {
1031150093Srwatson		warnx("%s: %s selects r:%d, w:%d, e:%d on %s", testname,
1032150093Srwatson		    fdname, readable, writable, exception, conditionname);
1033150093Srwatson		return (-1);
1034150093Srwatson	}
1035150093Srwatson
1036150093Srwatson	if (kqueue_status(kqueue_fd, fd, &readable, &writable, &exception,
1037150093Srwatson	    testname) < 0)
1038150093Srwatson		return (-1);
1039150093Srwatson
1040150093Srwatson	if (readable != assert_readable || writable != assert_writable ||
1041150093Srwatson	    exception != assert_exception) {
1042150093Srwatson		warnx("%s: %s kevent r:%d, w:%d, e:%d on %s", testname,
1043150093Srwatson		    fdname, readable, writable, exception, conditionname);
1044150093Srwatson		return (-1);
1045150093Srwatson	}
1046150093Srwatson
1047150093Srwatson	if (fionread_status(fd, &readable, __func__) < 0)
1048150093Srwatson		return (-1);
1049150093Srwatson
1050150093Srwatson	if (readable != assert_readable) {
1051150093Srwatson		warnx("%s: %s fionread r:%d on %s", testname, fdname,
1052150093Srwatson		    readable, conditionname);
1053150093Srwatson		return (-1);
1054150093Srwatson	}
1055150093Srwatson
1056150093Srwatson	return (0);
1057150093Srwatson}
1058150093Srwatson
1059150022Srwatson/*
1060150059Srwatson * test_events() uses poll(), select(), and kevent() to query the status of
1061150059Srwatson * fifo file descriptors and determine whether they match expected state
1062150059Srwatson * based on earlier semantic tests: specifically, whether or not poll/select/
1063150059Srwatson * kevent will correctly inform on readable/writable state following I/O.
1064150022Srwatson *
1065150059Srwatson * It would be nice to also test status changes as a result of closing of one
1066150059Srwatson * or another fifo endpoint.
1067150022Srwatson */
1068150022Srwatsonstatic void
1069150022Srwatsontest_events_outofbox(void)
1070150022Srwatson{
1071150059Srwatson	int kqueue_fd, reader_fd, writer_fd;
1072150022Srwatson
1073150022Srwatson	makefifo("testfifo", __func__);
1074281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
1075150022Srwatson		warn("test_events_outofbox: openfifo: testfifo");
1076150093Srwatson		cleanfifo2("testfifo", -1, -1);
1077150022Srwatson		exit(-1);
1078150022Srwatson	}
1079150022Srwatson
1080150093Srwatson	kqueue_fd = kqueue();
1081150093Srwatson	if (kqueue_fd < 0) {
1082150093Srwatson		warn("%s: kqueue", __func__);
1083150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
1084150059Srwatson		exit(-1);
1085150059Srwatson	}
1086150059Srwatson
1087150093Srwatson	if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) {
1088150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1089150093Srwatson		exit(-1);
1090150093Srwatson	}
1091150093Srwatson
1092150093Srwatson	if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) {
1093150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1094150093Srwatson		exit(-1);
1095150093Srwatson	}
1096150093Srwatson
1097150022Srwatson	/*
1098150022Srwatson	 * Make sure that fresh, out-of-the-box fifo file descriptors have
1099150022Srwatson	 * good initial states.  The reader_fd should have no active state,
1100150022Srwatson	 * since it will not be readable (no data in pipe), writable (it's
1101150022Srwatson	 * a read-only descriptor), and there's no reason for error yet.
1102150022Srwatson	 */
1103150093Srwatson	if (assert_status(reader_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE,
1104150093Srwatson	    NOT_EXCEPTION, __func__, "create", "reader_fd") < 0) {
1105150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1106150022Srwatson		exit(-1);
1107150022Srwatson	}
1108150022Srwatson
1109150022Srwatson	/*
1110150022Srwatson	 * Make sure that fresh, out-of-the-box fifo file descriptors have
1111150022Srwatson	 * good initial states.  The writer_fd should be ready to write.
1112150022Srwatson	 */
1113150093Srwatson	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE,
1114150093Srwatson	    NOT_EXCEPTION, __func__, "create", "writer_fd") < 0) {
1115150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1116150022Srwatson		exit(-1);
1117150022Srwatson	}
1118150022Srwatson
1119150093Srwatson	cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1120150022Srwatson}
1121150022Srwatson
1122150022Srwatsonstatic void
1123150022Srwatsontest_events_write_read_byte(void)
1124150022Srwatson{
1125150059Srwatson	int kqueue_fd, reader_fd, writer_fd;
1126150022Srwatson	ssize_t len;
1127150022Srwatson	u_char ch;
1128150022Srwatson
1129150022Srwatson	makefifo("testfifo", __func__);
1130281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
1131150022Srwatson		warn("test_events_write_read_byte: openfifo: testfifo");
1132150093Srwatson		cleanfifo2("testfifo", -1, -1);
1133150022Srwatson		exit(-1);
1134150022Srwatson	}
1135150022Srwatson
1136150093Srwatson	kqueue_fd = kqueue();
1137150093Srwatson	if (kqueue_fd < 0) {
1138150093Srwatson		warn("%s: kqueue", __func__);
1139150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
1140150059Srwatson		exit(-1);
1141150059Srwatson	}
1142150059Srwatson
1143150093Srwatson	if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) {
1144150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1145150093Srwatson		exit(-1);
1146150093Srwatson	}
1147150093Srwatson
1148150093Srwatson	if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) {
1149150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1150150093Srwatson		exit(-1);
1151150093Srwatson	}
1152150093Srwatson
1153150022Srwatson	/*
1154150022Srwatson	 * Write a byte to the fifo, and make sure that the read end becomes
1155150022Srwatson	 * readable, and that the write end remains writable (small write).
1156150022Srwatson	 */
1157150022Srwatson	ch = 0x00;
1158150022Srwatson	len = write(writer_fd, &ch, sizeof(ch));
1159150022Srwatson	if (len < 0) {
1160150093Srwatson		warn("%s: write", __func__);
1161150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1162150022Srwatson		exit(-1);
1163150022Srwatson	}
1164150022Srwatson
1165150093Srwatson	if (assert_status(reader_fd, kqueue_fd, READABLE, NOT_WRITABLE,
1166150093Srwatson	    NOT_EXCEPTION, __func__, "write", "reader_fd") < 0) {
1167150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1168150022Srwatson		exit(-1);
1169150022Srwatson	}
1170150022Srwatson
1171150022Srwatson	/*
1172150093Srwatson	 * the writer_fd should remain writable.
1173150022Srwatson	 */
1174150093Srwatson	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE,
1175150093Srwatson	    NOT_EXCEPTION, __func__, "write", "writer_fd") < 0) {
1176150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1177150022Srwatson		exit(-1);
1178150022Srwatson	}
1179150022Srwatson
1180150022Srwatson	/*
1181150022Srwatson	 * Read the byte from the reader_fd, and now confirm that that fifo
1182150022Srwatson	 * becomes unreadable.
1183150022Srwatson	 */
1184150022Srwatson	len = read(reader_fd, &ch, sizeof(ch));
1185150022Srwatson	if (len < 0) {
1186150093Srwatson		warn("%s: read", __func__);
1187150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1188150022Srwatson		exit(-1);
1189150022Srwatson	}
1190150022Srwatson
1191150093Srwatson	if (assert_status(reader_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE,
1192150093Srwatson	    NOT_EXCEPTION, __func__, "write+read", "reader_fd") < 0) {
1193150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1194150022Srwatson		exit(-1);
1195150022Srwatson	}
1196150022Srwatson
1197150022Srwatson	/*
1198150093Srwatson	 * The writer_fd should remain writable.
1199150022Srwatson	 */
1200150093Srwatson	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE,
1201150093Srwatson	    NOT_EXCEPTION, __func__, "write+read", "writer_fd") < 0) {
1202150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1203150022Srwatson		exit(-1);
1204150022Srwatson	}
1205150022Srwatson
1206150093Srwatson	cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1207150022Srwatson}
1208150022Srwatson
1209150059Srwatson/*
1210150059Srwatson * Write a 512k buffer to the fifo in non-blocking mode, and make sure that
1211150059Srwatson * the write end becomes un-writable as a result of a partial write that
1212150059Srwatson * fills the fifo buffer.
1213150059Srwatson */
1214150022Srwatsonstatic void
1215150022Srwatsontest_events_partial_write(void)
1216150022Srwatson{
1217150059Srwatson	int kqueue_fd, reader_fd, writer_fd;
1218150022Srwatson	u_char *buffer;
1219150022Srwatson	ssize_t len;
1220150022Srwatson
1221150022Srwatson	makefifo("testfifo", __func__);
1222281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
1223150022Srwatson		warn("test_events_partial_write: openfifo: testfifo");
1224150093Srwatson		cleanfifo2("testfifo", -1, -1);
1225150022Srwatson		exit(-1);
1226150022Srwatson	}
1227150022Srwatson
1228150093Srwatson	kqueue_fd = kqueue();
1229150093Srwatson	if (kqueue_fd < 0) {
1230150093Srwatson		warn("%s: kqueue", __func__);
1231150093Srwatson		cleanfifo2("testfifo", reader_fd, writer_fd);
1232150022Srwatson		exit(-1);
1233150022Srwatson	}
1234150022Srwatson
1235150093Srwatson	if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) {
1236150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1237150093Srwatson		exit(-1);
1238150093Srwatson	}
1239150093Srwatson
1240150093Srwatson	if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) {
1241150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1242150093Srwatson		exit(-1);
1243150093Srwatson	}
1244150093Srwatson
1245150059Srwatson	if (set_nonblocking(writer_fd, "test_events") < 0) {
1246150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1247150059Srwatson		exit(-1);
1248150059Srwatson	}
1249150059Srwatson
1250150022Srwatson	buffer = malloc(512*1024);
1251150022Srwatson	if (buffer == NULL) {
1252150022Srwatson		warn("test_events_partial_write: malloc");
1253150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1254150022Srwatson		exit(-1);
1255150022Srwatson	}
1256150022Srwatson	bzero(buffer, 512*1024);
1257150022Srwatson
1258150022Srwatson	len = write(writer_fd, buffer, 512*1024);
1259150022Srwatson	if (len < 0) {
1260150022Srwatson		warn("test_events_partial_write: write");
1261150022Srwatson		free(buffer);
1262150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1263150022Srwatson		exit(-1);
1264150022Srwatson	}
1265150022Srwatson
1266150022Srwatson	free(buffer);
1267150022Srwatson
1268150093Srwatson	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE,
1269150093Srwatson	    NOT_EXCEPTION, __func__, "big write", "writer_fd") < 0) {
1270150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1271150022Srwatson		exit(-1);
1272150022Srwatson	}
1273150022Srwatson
1274150093Srwatson	if (drain_fd(reader_fd, "test_events") < 0) {
1275150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1276150022Srwatson		exit(-1);
1277150022Srwatson	}
1278150022Srwatson
1279150093Srwatson	/*
1280150093Srwatson	 * Test that the writer_fd has been restored to writable state after
1281150093Srwatson	 * draining.
1282150093Srwatson	 */
1283150093Srwatson	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE,
1284150093Srwatson	    NOT_EXCEPTION, __func__, "big write + drain", "writer_fd") < 0) {
1285150093Srwatson		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1286150022Srwatson		exit(-1);
1287150022Srwatson	}
1288150022Srwatson
1289150093Srwatson	cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
1290150093Srwatson}
1291150022Srwatson
1292150093Srwatson/*
1293150093Srwatson * We don't comprehensively test O_RDWR file descriptors, but do run a couple
1294150093Srwatson * of event tests to make sure that the fifo implementation doesn't mixed up
1295150093Srwatson * status checks.  In particular, at least one past FreeBSD bug exists in
1296150093Srwatson * which the FIONREAD test was performed on the wrong socket implementing the
1297150093Srwatson * fifo, resulting in the fifo never returning readable.
1298150093Srwatson */
1299150093Srwatsonstatic void
1300150093Srwatsontest_events_rdwr(void)
1301150093Srwatson{
1302150093Srwatson	int fd, kqueue_fd;
1303150093Srwatson	ssize_t len;
1304150093Srwatson	char ch;
1305150093Srwatson
1306150093Srwatson	makefifo("testfifo", __func__);
1307281450Sngie	if (openfifo_rw("testfifo", &fd) < 0) {
1308150093Srwatson		warn("%s: openfifo_rw: testfifo", __func__);
1309150093Srwatson		cleanfifo2("testfifo", -1, -1);
1310150059Srwatson		exit(-1);
1311150059Srwatson	}
1312150059Srwatson
1313150093Srwatson	kqueue_fd = kqueue();
1314150093Srwatson	if (kqueue_fd < 0) {
1315150093Srwatson		warn("%s: kqueue", __func__);
1316150093Srwatson		cleanfifo2("testifo", fd, -1);
1317150059Srwatson		exit(-1);
1318150059Srwatson	}
1319150059Srwatson
1320150093Srwatson	if (kqueue_setup(kqueue_fd, fd, __func__) < 0) {
1321150093Srwatson		cleanfifo2("testfifo", fd, kqueue_fd);
1322150022Srwatson		exit(-1);
1323150022Srwatson	}
1324150022Srwatson
1325150022Srwatson	/*
1326150093Srwatson	 * On first creation, the O_RDWR descriptor should be writable but
1327150093Srwatson	 * not readable.
1328150022Srwatson	 */
1329150093Srwatson	if (assert_status(fd, kqueue_fd, NOT_READABLE, WRITABLE,
1330150093Srwatson	    NOT_EXCEPTION, __func__, "create", "fd") < 0) {
1331150093Srwatson		cleanfifo2("testfifo", fd, kqueue_fd);
1332150022Srwatson		exit(-1);
1333150022Srwatson	}
1334150022Srwatson
1335150093Srwatson	/*
1336150093Srwatson	 * Write a byte, which should cause the file descriptor to become
1337150093Srwatson	 * readable and writable.
1338150093Srwatson	 */
1339150093Srwatson	ch = 0x00;
1340150093Srwatson	len = write(fd, &ch, sizeof(ch));
1341150093Srwatson	if (len < 0) {
1342150093Srwatson		warn("%s: write", __func__);
1343150093Srwatson		cleanfifo2("testfifo", fd, kqueue_fd);
1344150022Srwatson		exit(-1);
1345150022Srwatson	}
1346150022Srwatson
1347150093Srwatson	if (assert_status(fd, kqueue_fd, READABLE, WRITABLE, NOT_EXCEPTION,
1348150093Srwatson	    __func__, "write", "fd") < 0) {
1349150093Srwatson		cleanfifo2("testfifo", fd, kqueue_fd);
1350150022Srwatson		exit(-1);
1351150022Srwatson	}
1352150022Srwatson
1353150093Srwatson	/*
1354150093Srwatson	 * Read a byte, which should cause the file descriptor to return to
1355150093Srwatson	 * simply being writable.
1356150093Srwatson	 */
1357150093Srwatson	len = read(fd, &ch, sizeof(ch));
1358150093Srwatson	if (len < 0) {
1359150093Srwatson		warn("%s: read", __func__);
1360150093Srwatson		cleanfifo2("testfifo", fd, kqueue_fd);
1361150022Srwatson		exit(-1);
1362150022Srwatson	}
1363150059Srwatson
1364150093Srwatson	if (assert_status(fd, kqueue_fd, NOT_READABLE, WRITABLE,
1365150093Srwatson	    NOT_EXCEPTION, __func__, "write+read", "fd") < 0) {
1366150093Srwatson		cleanfifo2("testfifo", fd, kqueue_fd);
1367150059Srwatson		exit(-1);
1368150059Srwatson	}
1369150059Srwatson
1370150093Srwatson	cleanfifo2("testfifo", fd, kqueue_fd);
1371150022Srwatson}
1372150059Srwatson
1373150022Srwatsonint
1374281450Sngiemain(void)
1375150022Srwatson{
1376150022Srwatson
1377281450Sngie	strcpy(temp_dir, "fifo_io.XXXXXXXXXXX");
1378150022Srwatson	if (mkdtemp(temp_dir) == NULL)
1379150022Srwatson		err(-1, "mkdtemp");
1380150022Srwatson	atexit(atexit_temp_dir);
1381150022Srwatson
1382150022Srwatson	if (chdir(temp_dir) < 0)
1383150022Srwatson		err(-1, "chdir %s", temp_dir);
1384150022Srwatson
1385150022Srwatson	test_simpleio();
1386150022Srwatson	test_blocking_read_empty();
1387150022Srwatson	test_blocking_one_byte();
1388150022Srwatson	test_nonblocking_one_byte();
1389150022Srwatson	test_blocking_partial_write();
1390150022Srwatson	test_nonblocking_partial_write();
1391150022Srwatson	test_coalesce_big_read();
1392150022Srwatson	test_coalesce_big_write();
1393150022Srwatson	test_events_outofbox();
1394150022Srwatson	test_events_write_read_byte();
1395150022Srwatson	test_events_partial_write();
1396150093Srwatson	test_events_rdwr();
1397150022Srwatson
1398150022Srwatson	return (0);
1399150022Srwatson}
1400