xref: /freebsd/tests/sys/fifo/fifo_io.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
13cedbec3SEnji Cooper /*-
23cedbec3SEnji Cooper  * Copyright (c) 2005 Robert N. M. Watson
33cedbec3SEnji Cooper  * All rights reserved.
43cedbec3SEnji Cooper  *
53cedbec3SEnji Cooper  * Redistribution and use in source and binary forms, with or without
63cedbec3SEnji Cooper  * modification, are permitted provided that the following conditions
73cedbec3SEnji Cooper  * are met:
83cedbec3SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
93cedbec3SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
103cedbec3SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
113cedbec3SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
123cedbec3SEnji Cooper  *    documentation and/or other materials provided with the distribution.
133cedbec3SEnji Cooper  *
143cedbec3SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153cedbec3SEnji Cooper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163cedbec3SEnji Cooper  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173cedbec3SEnji Cooper  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183cedbec3SEnji Cooper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193cedbec3SEnji Cooper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203cedbec3SEnji Cooper  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213cedbec3SEnji Cooper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223cedbec3SEnji Cooper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233cedbec3SEnji Cooper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243cedbec3SEnji Cooper  * SUCH DAMAGE.
253cedbec3SEnji Cooper  */
263cedbec3SEnji Cooper 
273cedbec3SEnji Cooper #include <sys/types.h>
283cedbec3SEnji Cooper #include <sys/event.h>
293cedbec3SEnji Cooper #include <sys/ioctl.h>
303cedbec3SEnji Cooper #include <sys/select.h>
313cedbec3SEnji Cooper #include <sys/stat.h>
323cedbec3SEnji Cooper #include <sys/time.h>
333cedbec3SEnji Cooper 
343cedbec3SEnji Cooper #include <err.h>
353cedbec3SEnji Cooper #include <errno.h>
363cedbec3SEnji Cooper #include <fcntl.h>
373cedbec3SEnji Cooper #include <limits.h>
383cedbec3SEnji Cooper #include <poll.h>
393cedbec3SEnji Cooper #include <signal.h>
403cedbec3SEnji Cooper #include <stdio.h>
413cedbec3SEnji Cooper #include <stdlib.h>
423cedbec3SEnji Cooper #include <string.h>
433cedbec3SEnji Cooper #include <unistd.h>
443cedbec3SEnji Cooper 
453cedbec3SEnji Cooper /*
463cedbec3SEnji Cooper  * Regression test to exercise POSIX fifo I/O.
473cedbec3SEnji Cooper  *
483cedbec3SEnji Cooper  * We test a number of aspect of behavior, including:
493cedbec3SEnji Cooper  *
503cedbec3SEnji Cooper  * - If there's no data to read, then for blocking fifos, we block, and for
513cedbec3SEnji Cooper  *   non-blocking, we return EAGAIN.
523cedbec3SEnji Cooper  *
533cedbec3SEnji Cooper  * - If we write ten bytes, ten bytes can be read, and they're the same
543cedbec3SEnji Cooper  *   bytes, in the same order.
553cedbec3SEnji Cooper  *
563cedbec3SEnji Cooper  * - If we write two batches of five bytes, we can read the same ten bytes in
573cedbec3SEnji Cooper  *   one read of ten bytes.
583cedbec3SEnji Cooper  *
593cedbec3SEnji Cooper  * - If we write ten bytes, we can read the same ten bytes in two reads of
603cedbec3SEnji Cooper  *   five bytes each.
613cedbec3SEnji Cooper  *
623cedbec3SEnji Cooper  * - If we over-fill a buffer (by writing 512k, which we take to be a large
633cedbec3SEnji Cooper  *   number above default buffer sizes), we block if there is no reader.
643cedbec3SEnji Cooper  *
653cedbec3SEnji Cooper  * - That once 512k (ish) is read from the other end, the blocked writer
663cedbec3SEnji Cooper  *   wakes up.
673cedbec3SEnji Cooper  *
683cedbec3SEnji Cooper  * - When a fifo is empty, poll, select, kqueue, and fionread report it is
693cedbec3SEnji Cooper  *   writable but not readable.
703cedbec3SEnji Cooper  *
713cedbec3SEnji Cooper  * - When a fifo has data in it, poll, select, and kqueue report that it is
723cedbec3SEnji Cooper  *   writable.
733cedbec3SEnji Cooper  *
743cedbec3SEnji Cooper  * - XXX: blocked reader semantics?
753cedbec3SEnji Cooper  *
763cedbec3SEnji Cooper  * - XXX: event behavior on remote close?
773cedbec3SEnji Cooper  *
783cedbec3SEnji Cooper  * Although behavior of O_RDWR isn't defined for fifos by POSIX, we expect
793cedbec3SEnji Cooper  * "reasonable" behavior, and run some additional tests relating to event
803cedbec3SEnji Cooper  * management on O_RDWR fifo descriptors.
813cedbec3SEnji Cooper  */
823cedbec3SEnji Cooper 
833cedbec3SEnji Cooper #define	KQUEUE_MAX_EVENT	8
843cedbec3SEnji Cooper 
853cedbec3SEnji Cooper /*
863cedbec3SEnji Cooper  * All activity occurs within a temporary directory created early in the
873cedbec3SEnji Cooper  * test.
883cedbec3SEnji Cooper  */
893cedbec3SEnji Cooper static char	temp_dir[PATH_MAX];
903cedbec3SEnji Cooper 
913cedbec3SEnji Cooper static void __unused
atexit_temp_dir(void)923cedbec3SEnji Cooper atexit_temp_dir(void)
933cedbec3SEnji Cooper {
943cedbec3SEnji Cooper 
953cedbec3SEnji Cooper 	rmdir(temp_dir);
963cedbec3SEnji Cooper }
973cedbec3SEnji Cooper 
983cedbec3SEnji Cooper static void
makefifo(const char * fifoname,const char * testname)993cedbec3SEnji Cooper makefifo(const char *fifoname, const char *testname)
1003cedbec3SEnji Cooper {
1013cedbec3SEnji Cooper 
1023cedbec3SEnji Cooper 	if (mkfifo(fifoname, 0700) < 0)
1033cedbec3SEnji Cooper 		err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname);
1043cedbec3SEnji Cooper }
1053cedbec3SEnji Cooper 
1063cedbec3SEnji Cooper static void
cleanfifo2(const char * fifoname,int fd1,int fd2)1073cedbec3SEnji Cooper cleanfifo2(const char *fifoname, int fd1, int fd2)
1083cedbec3SEnji Cooper {
1093cedbec3SEnji Cooper 
1103cedbec3SEnji Cooper 	if (fd1 != -1)
1113cedbec3SEnji Cooper 		close(fd1);
1123cedbec3SEnji Cooper 	if (fd2 != -1)
1133cedbec3SEnji Cooper 		close(fd2);
1143cedbec3SEnji Cooper 	(void)unlink(fifoname);
1153cedbec3SEnji Cooper }
1163cedbec3SEnji Cooper 
1173cedbec3SEnji Cooper static void
cleanfifo3(const char * fifoname,int fd1,int fd2,int fd3)1183cedbec3SEnji Cooper cleanfifo3(const char *fifoname, int fd1, int fd2, int fd3)
1193cedbec3SEnji Cooper {
1203cedbec3SEnji Cooper 
1213cedbec3SEnji Cooper 	if (fd3 != -1)
1223cedbec3SEnji Cooper 		close(fd3);
1233cedbec3SEnji Cooper 	cleanfifo2(fifoname, fd1, fd2);
1243cedbec3SEnji Cooper }
1253cedbec3SEnji Cooper 
1263cedbec3SEnji Cooper /*
1273cedbec3SEnji Cooper  * Open two different file descriptors for a fifo: one read, one write.  Do
1283cedbec3SEnji Cooper  * so using non-blocking opens in order to avoid deadlocking the process.
1293cedbec3SEnji Cooper  */
1303cedbec3SEnji Cooper static int
openfifo(const char * fifoname,int * reader_fdp,int * writer_fdp)1313cedbec3SEnji Cooper openfifo(const char *fifoname, int *reader_fdp, int *writer_fdp)
1323cedbec3SEnji Cooper {
1333cedbec3SEnji Cooper 	int error, fd1, fd2;
1343cedbec3SEnji Cooper 
1353cedbec3SEnji Cooper 	fd1 = open(fifoname, O_RDONLY | O_NONBLOCK);
1363cedbec3SEnji Cooper 	if (fd1 < 0)
1373cedbec3SEnji Cooper 		return (-1);
1383cedbec3SEnji Cooper 	fd2 = open(fifoname, O_WRONLY | O_NONBLOCK);
1393cedbec3SEnji Cooper 	if (fd2 < 0) {
1403cedbec3SEnji Cooper 		error = errno;
1413cedbec3SEnji Cooper 		close(fd1);
1423cedbec3SEnji Cooper 		errno = error;
1433cedbec3SEnji Cooper 		return (-1);
1443cedbec3SEnji Cooper 	}
1453cedbec3SEnji Cooper 	*reader_fdp = fd1;
1463cedbec3SEnji Cooper 	*writer_fdp = fd2;
1473cedbec3SEnji Cooper 
1483cedbec3SEnji Cooper 	return (0);
1493cedbec3SEnji Cooper }
1503cedbec3SEnji Cooper 
1513cedbec3SEnji Cooper /*
1523cedbec3SEnji Cooper  * Open one file descriptor for the fifo, supporting both read and write.
1533cedbec3SEnji Cooper  */
1543cedbec3SEnji Cooper static int
openfifo_rw(const char * fifoname,int * fdp)1553cedbec3SEnji Cooper openfifo_rw(const char *fifoname, int *fdp)
1563cedbec3SEnji Cooper {
1573cedbec3SEnji Cooper 	int fd;
1583cedbec3SEnji Cooper 
1593cedbec3SEnji Cooper 	fd = open(fifoname, O_RDWR);
1603cedbec3SEnji Cooper 	if (fd < 0)
1613cedbec3SEnji Cooper 		return (-1);
1623cedbec3SEnji Cooper 	*fdp = fd;
1633cedbec3SEnji Cooper 
1643cedbec3SEnji Cooper 	return (0);
1653cedbec3SEnji Cooper }
1663cedbec3SEnji Cooper 
1673cedbec3SEnji Cooper static int
set_nonblocking(int fd,const char * testname)1683cedbec3SEnji Cooper set_nonblocking(int fd, const char *testname)
1693cedbec3SEnji Cooper {
1703cedbec3SEnji Cooper 	int flags;
1713cedbec3SEnji Cooper 
1723cedbec3SEnji Cooper 	flags = fcntl(fd, F_GETFL);
1733cedbec3SEnji Cooper 	if (flags < 0) {
1743cedbec3SEnji Cooper 		warn("%s: fcntl(fd, F_GETFL)", testname);
1753cedbec3SEnji Cooper 		return(-1);
1763cedbec3SEnji Cooper 	}
1773cedbec3SEnji Cooper 
1783cedbec3SEnji Cooper 	flags |= O_NONBLOCK;
1793cedbec3SEnji Cooper 
1803cedbec3SEnji Cooper 	if (fcntl(fd, F_SETFL, flags) < 0) {
1813cedbec3SEnji Cooper 		warn("%s: fcntl(fd, 0x%x)", testname, flags);
1823cedbec3SEnji Cooper 		return (-1);
1833cedbec3SEnji Cooper 	}
1843cedbec3SEnji Cooper 
1853cedbec3SEnji Cooper 	return (0);
1863cedbec3SEnji Cooper }
1873cedbec3SEnji Cooper 
1883cedbec3SEnji Cooper static int
set_blocking(int fd,const char * testname)1893cedbec3SEnji Cooper set_blocking(int fd, const char *testname)
1903cedbec3SEnji Cooper {
1913cedbec3SEnji Cooper 	int flags;
1923cedbec3SEnji Cooper 
1933cedbec3SEnji Cooper 	flags = fcntl(fd, F_GETFL);
1943cedbec3SEnji Cooper 	if (flags < 0) {
1953cedbec3SEnji Cooper 		warn("%s: fcntl(fd, F_GETFL)", testname);
1963cedbec3SEnji Cooper 		return(-1);
1973cedbec3SEnji Cooper 	}
1983cedbec3SEnji Cooper 
1993cedbec3SEnji Cooper 	flags &= ~O_NONBLOCK;
2003cedbec3SEnji Cooper 
2013cedbec3SEnji Cooper 	if (fcntl(fd, F_SETFL, flags) < 0) {
2023cedbec3SEnji Cooper 		warn("%s: fcntl(fd, 0x%x)", testname, flags);
2033cedbec3SEnji Cooper 		return (-1);
2043cedbec3SEnji Cooper 	}
2053cedbec3SEnji Cooper 
2063cedbec3SEnji Cooper 	return (0);
2073cedbec3SEnji Cooper }
2083cedbec3SEnji Cooper 
2093cedbec3SEnji Cooper /*
2103cedbec3SEnji Cooper  * Drain a file descriptor (fifo) of any readable data.  Note: resets the
2113cedbec3SEnji Cooper  * blocking state.
2123cedbec3SEnji Cooper  */
2133cedbec3SEnji Cooper static int
drain_fd(int fd,const char * testname)2143cedbec3SEnji Cooper drain_fd(int fd, const char *testname)
2153cedbec3SEnji Cooper {
2163cedbec3SEnji Cooper 	ssize_t len;
2173cedbec3SEnji Cooper 	u_char ch;
2183cedbec3SEnji Cooper 
2193cedbec3SEnji Cooper 	if (set_nonblocking(fd, testname) < 0)
2203cedbec3SEnji Cooper 		return (-1);
2213cedbec3SEnji Cooper 
2223cedbec3SEnji Cooper 	while ((len = read(fd, &ch, sizeof(ch))) > 0);
2233cedbec3SEnji Cooper 	if (len < 0) {
2243cedbec3SEnji Cooper 		switch (errno) {
2253cedbec3SEnji Cooper 		case EAGAIN:
2263cedbec3SEnji Cooper 			return (0);
2273cedbec3SEnji Cooper 		default:
2283cedbec3SEnji Cooper 			warn("%s: drain_fd: read", testname);
2293cedbec3SEnji Cooper 			return (-1);
2303cedbec3SEnji Cooper 		}
2313cedbec3SEnji Cooper 	}
2323cedbec3SEnji Cooper 	warn("%s: drain_fd: read: returned 0 bytes", testname);
2333cedbec3SEnji Cooper 	return (-1);
2343cedbec3SEnji Cooper }
2353cedbec3SEnji Cooper 
2363cedbec3SEnji Cooper /*
2373cedbec3SEnji Cooper  * Simple I/O test: write ten integers, and make sure we get back the same
2383cedbec3SEnji Cooper  * integers in the same order.  This assumes a minimum fifo buffer > 10
2393cedbec3SEnji Cooper  * bytes in order to not block and deadlock.
2403cedbec3SEnji Cooper  */
2413cedbec3SEnji Cooper static void
test_simpleio(void)2423cedbec3SEnji Cooper test_simpleio(void)
2433cedbec3SEnji Cooper {
2443cedbec3SEnji Cooper 	int i, reader_fd, writer_fd;
2453cedbec3SEnji Cooper 	u_char buffer[10];
2463cedbec3SEnji Cooper 	ssize_t len;
2473cedbec3SEnji Cooper 
2483cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
2493cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd)
2503cedbec3SEnji Cooper 	    < 0) {
2513cedbec3SEnji Cooper 		warn("test_simpleio: openfifo: testfifo");
2523cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
2533cedbec3SEnji Cooper 		exit(-1);
2543cedbec3SEnji Cooper 	}
2553cedbec3SEnji Cooper 
2563cedbec3SEnji Cooper 	for (i = 0; i < 10; i++)
2573cedbec3SEnji Cooper 		buffer[i] = i;
2583cedbec3SEnji Cooper 
2593cedbec3SEnji Cooper 	len = write(writer_fd, (char *)buffer, sizeof(buffer));
2603cedbec3SEnji Cooper 	if (len < 0) {
2613cedbec3SEnji Cooper 		warn("test_simpleio: write");
2623cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
2633cedbec3SEnji Cooper 		exit(-1);
2643cedbec3SEnji Cooper 	}
2653cedbec3SEnji Cooper 	if (len != sizeof(buffer)) {
2663cedbec3SEnji Cooper 		warnx("test_simplio: tried %zu but wrote %zd", sizeof(buffer),
2673cedbec3SEnji Cooper 		    len);
2683cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
2693cedbec3SEnji Cooper 		exit(-1);
2703cedbec3SEnji Cooper 	}
2713cedbec3SEnji Cooper 
2723cedbec3SEnji Cooper 	len = read(reader_fd, (char *)buffer, sizeof(buffer));
2733cedbec3SEnji Cooper 	if (len < 0) {
2743cedbec3SEnji Cooper 		warn("test_simpleio: read");
2753cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
2763cedbec3SEnji Cooper 		exit(-1);
2773cedbec3SEnji Cooper 	}
2783cedbec3SEnji Cooper 	if (len != sizeof(buffer)) {
2793cedbec3SEnji Cooper 		warnx("test_simpleio: tried %zu but read %zd", sizeof(buffer),
2803cedbec3SEnji Cooper 		    len);
2813cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
2823cedbec3SEnji Cooper 		exit(-1);
2833cedbec3SEnji Cooper 	}
2843cedbec3SEnji Cooper 	for (i = 0; i < 10; i++) {
2853cedbec3SEnji Cooper 		if (buffer[i] == i)
2863cedbec3SEnji Cooper 			continue;
2873cedbec3SEnji Cooper 		warnx("test_simpleio: write byte %d as 0x%02x, but read "
2883cedbec3SEnji Cooper 		    "0x%02x", i, i, buffer[i]);
2893cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
2903cedbec3SEnji Cooper 		exit(-1);
2913cedbec3SEnji Cooper 	}
2923cedbec3SEnji Cooper 
2933cedbec3SEnji Cooper 	cleanfifo2("testfifo", reader_fd, writer_fd);
2943cedbec3SEnji Cooper }
2953cedbec3SEnji Cooper 
2963cedbec3SEnji Cooper static volatile int alarm_fired;
2973cedbec3SEnji Cooper /*
2983cedbec3SEnji Cooper  * Non-destructive SIGALRM handler.
2993cedbec3SEnji Cooper  */
3003cedbec3SEnji Cooper static void
sigalarm(int signum __unused)3013cedbec3SEnji Cooper sigalarm(int signum __unused)
3023cedbec3SEnji Cooper {
3033cedbec3SEnji Cooper 
3043cedbec3SEnji Cooper 	alarm_fired = 1;
3053cedbec3SEnji Cooper }
3063cedbec3SEnji Cooper 
3073cedbec3SEnji Cooper /*
3083cedbec3SEnji Cooper  * Wrapper function for write, which uses a timer to interrupt any blocking.
3093cedbec3SEnji Cooper  * Because we can't reliably detect EINTR for blocking I/O, we also track
3103cedbec3SEnji Cooper  * whether or not our timeout fired.
3113cedbec3SEnji Cooper  */
3123cedbec3SEnji Cooper static int __unused
timed_write(int fd,void * data,size_t len,ssize_t * written_lenp,int timeout,int * timedoutp,const char * testname)3133cedbec3SEnji Cooper timed_write(int fd, void *data, size_t len, ssize_t *written_lenp,
3143cedbec3SEnji Cooper     int timeout, int *timedoutp, const char *testname)
3153cedbec3SEnji Cooper {
3163cedbec3SEnji Cooper 	struct sigaction act, oact;
3173cedbec3SEnji Cooper 	ssize_t written_len;
3183cedbec3SEnji Cooper 	int error;
3193cedbec3SEnji Cooper 
3203cedbec3SEnji Cooper 	alarm_fired = 0;
3213cedbec3SEnji Cooper 	bzero(&act, sizeof(oact));
3223cedbec3SEnji Cooper 	act.sa_handler = sigalarm;
3233cedbec3SEnji Cooper 	if (sigaction(SIGALRM, &act, &oact) < 0) {
3243cedbec3SEnji Cooper 	 	warn("%s: timed_write: sigaction", testname);
3253cedbec3SEnji Cooper 		return (-1);
3263cedbec3SEnji Cooper 	}
3273cedbec3SEnji Cooper 	alarm(timeout);
3283cedbec3SEnji Cooper 	written_len = write(fd, data, len);
3293cedbec3SEnji Cooper 	error = errno;
3303cedbec3SEnji Cooper 	alarm(0);
3313cedbec3SEnji Cooper 	if (sigaction(SIGALRM, &oact, NULL) < 0) {
3323cedbec3SEnji Cooper 	 	warn("%s: timed_write: sigaction", testname);
3333cedbec3SEnji Cooper 		return (-1);
3343cedbec3SEnji Cooper 	}
3353cedbec3SEnji Cooper 	if (alarm_fired)
3363cedbec3SEnji Cooper 		*timedoutp = 1;
3373cedbec3SEnji Cooper 	else
3383cedbec3SEnji Cooper 		*timedoutp = 0;
3393cedbec3SEnji Cooper 
3403cedbec3SEnji Cooper 	errno = error;
3413cedbec3SEnji Cooper 	if (written_len < 0)
3423cedbec3SEnji Cooper 		return (-1);
3433cedbec3SEnji Cooper 	*written_lenp = written_len;
3443cedbec3SEnji Cooper 	return (0);
3453cedbec3SEnji Cooper }
3463cedbec3SEnji Cooper 
3473cedbec3SEnji Cooper /*
3483cedbec3SEnji Cooper  * Wrapper function for read, which uses a timer to interrupt any blocking.
3493cedbec3SEnji Cooper  * Because we can't reliably detect EINTR for blocking I/O, we also track
3503cedbec3SEnji Cooper  * whether or not our timeout fired.
3513cedbec3SEnji Cooper  */
3523cedbec3SEnji Cooper static int
timed_read(int fd,void * data,size_t len,ssize_t * read_lenp,int timeout,int * timedoutp,const char * testname)3533cedbec3SEnji Cooper timed_read(int fd, void *data, size_t len, ssize_t *read_lenp,
3543cedbec3SEnji Cooper     int timeout, int *timedoutp, const char *testname)
3553cedbec3SEnji Cooper {
3563cedbec3SEnji Cooper 	struct sigaction act, oact;
3573cedbec3SEnji Cooper 	ssize_t read_len;
3583cedbec3SEnji Cooper 	int error;
3593cedbec3SEnji Cooper 
3603cedbec3SEnji Cooper 	alarm_fired = 0;
3613cedbec3SEnji Cooper 	bzero(&act, sizeof(oact));
3623cedbec3SEnji Cooper 	act.sa_handler = sigalarm;
3633cedbec3SEnji Cooper 	if (sigaction(SIGALRM, &act, &oact) < 0) {
3643cedbec3SEnji Cooper 	 	warn("%s: timed_write: sigaction", testname);
3653cedbec3SEnji Cooper 		return (-1);
3663cedbec3SEnji Cooper 	}
3673cedbec3SEnji Cooper 	alarm(timeout);
3683cedbec3SEnji Cooper 	read_len = read(fd, data, len);
3693cedbec3SEnji Cooper 	error = errno;
3703cedbec3SEnji Cooper 	alarm(0);
3713cedbec3SEnji Cooper 	if (sigaction(SIGALRM, &oact, NULL) < 0) {
3723cedbec3SEnji Cooper 	 	warn("%s: timed_write: sigaction", testname);
3733cedbec3SEnji Cooper 		return (-1);
3743cedbec3SEnji Cooper 	}
3753cedbec3SEnji Cooper 	if (alarm_fired)
3763cedbec3SEnji Cooper 		*timedoutp = 1;
3773cedbec3SEnji Cooper 	else
3783cedbec3SEnji Cooper 		*timedoutp = 0;
3793cedbec3SEnji Cooper 
3803cedbec3SEnji Cooper 	errno = error;
3813cedbec3SEnji Cooper 	if (read_len < 0)
3823cedbec3SEnji Cooper 		return (-1);
3833cedbec3SEnji Cooper 	*read_lenp = read_len;
3843cedbec3SEnji Cooper 	return (0);
3853cedbec3SEnji Cooper }
3863cedbec3SEnji Cooper 
3873cedbec3SEnji Cooper /*
3883cedbec3SEnji Cooper  * This test operates on blocking and non-blocking fifo file descriptors, in
3893cedbec3SEnji Cooper  * order to determine whether they block at good moments or not.  By good we
3903cedbec3SEnji Cooper  * mean: don't block for non-blocking sockets, and do block for blocking
3913cedbec3SEnji Cooper  * ones, assuming there isn't I/O buffer to satisfy the request.
3923cedbec3SEnji Cooper  *
3933cedbec3SEnji Cooper  * We use a timeout of 5 seconds, concluding that in 5 seconds either all I/O
3943cedbec3SEnji Cooper  * that can take place will, and that if we reach the end of the timeout,
3953cedbec3SEnji Cooper  * then blocking has occurred.
3963cedbec3SEnji Cooper  *
3973cedbec3SEnji Cooper  * We assume that the buffer size on a fifo is <512K, and as such, that
3983cedbec3SEnji Cooper  * writing that much data without an active reader will result in blocking.
3993cedbec3SEnji Cooper  */
4003cedbec3SEnji Cooper static void
test_blocking_read_empty(void)4013cedbec3SEnji Cooper test_blocking_read_empty(void)
4023cedbec3SEnji Cooper {
4033cedbec3SEnji Cooper 	int reader_fd, ret, timedout, writer_fd;
4043cedbec3SEnji Cooper 	ssize_t len;
4053cedbec3SEnji Cooper 	u_char ch;
4063cedbec3SEnji Cooper 
4073cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
4083cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd)
4093cedbec3SEnji Cooper 	    < 0) {
4103cedbec3SEnji Cooper 		warn("test_blocking_read_empty: openfifo: testfifo");
4113cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
4123cedbec3SEnji Cooper 		exit(-1);
4133cedbec3SEnji Cooper 	}
4143cedbec3SEnji Cooper 
4153cedbec3SEnji Cooper 	/*
4163cedbec3SEnji Cooper 	 * Read one byte from an empty blocking fifo, block as there is no
4173cedbec3SEnji Cooper 	 * data.
4183cedbec3SEnji Cooper 	 */
4193cedbec3SEnji Cooper 	if (set_blocking(reader_fd, __func__) < 0) {
4203cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4213cedbec3SEnji Cooper 		exit(-1);
4223cedbec3SEnji Cooper 	}
4233cedbec3SEnji Cooper 
4243cedbec3SEnji Cooper 	ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout,
4253cedbec3SEnji Cooper 	    __func__);
4263cedbec3SEnji Cooper 	if (ret != -1) {
4273cedbec3SEnji Cooper 		warnx("test_blocking_read_empty: timed_read: returned "
4283cedbec3SEnji Cooper 		    "success");
4293cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4303cedbec3SEnji Cooper 		exit(-1);
4313cedbec3SEnji Cooper 	}
4323cedbec3SEnji Cooper 	if (errno != EINTR) {
4333cedbec3SEnji Cooper 		warn("test_blocking_read_empty: timed_read");
4343cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4353cedbec3SEnji Cooper 		exit(-1);
4363cedbec3SEnji Cooper 	}
4373cedbec3SEnji Cooper 
4383cedbec3SEnji Cooper 	/*
4393cedbec3SEnji Cooper 	 * Read one byte from an empty non-blocking fifo, return EAGAIN as
4403cedbec3SEnji Cooper 	 * there is no data.
4413cedbec3SEnji Cooper 	 */
4423cedbec3SEnji Cooper 	if (set_nonblocking(reader_fd, __func__) < 0) {
4433cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4443cedbec3SEnji Cooper 		exit(-1);
4453cedbec3SEnji Cooper 	}
4463cedbec3SEnji Cooper 
4473cedbec3SEnji Cooper 	ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout,
4483cedbec3SEnji Cooper 	    __func__);
4493cedbec3SEnji Cooper 	if (ret != -1) {
4503cedbec3SEnji Cooper 		warnx("test_blocking_read_empty: timed_read: returned "
4513cedbec3SEnji Cooper 		    "success");
4523cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4533cedbec3SEnji Cooper 		exit(-1);
4543cedbec3SEnji Cooper 	}
4553cedbec3SEnji Cooper 	if (errno != EAGAIN) {
4563cedbec3SEnji Cooper 		warn("test_blocking_read_empty: timed_read");
4573cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4583cedbec3SEnji Cooper 		exit(-1);
4593cedbec3SEnji Cooper 	}
4603cedbec3SEnji Cooper 
4613cedbec3SEnji Cooper 	cleanfifo2("testfifo", reader_fd, writer_fd);
4623cedbec3SEnji Cooper }
4633cedbec3SEnji Cooper 
4643cedbec3SEnji Cooper /*
4653cedbec3SEnji Cooper  * Write one byte to an empty fifo, then try to read one byte and make sure
4663cedbec3SEnji Cooper  * we don't block in either the write or the read.  This tests both for
4673cedbec3SEnji Cooper  * improper blocking in the send and receive code.
4683cedbec3SEnji Cooper  */
4693cedbec3SEnji Cooper static void
test_blocking_one_byte(void)4703cedbec3SEnji Cooper test_blocking_one_byte(void)
4713cedbec3SEnji Cooper {
4723cedbec3SEnji Cooper 	int reader_fd, ret, timedout, writer_fd;
4733cedbec3SEnji Cooper 	ssize_t len;
4743cedbec3SEnji Cooper 	u_char ch;
4753cedbec3SEnji Cooper 
4763cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
4773cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
4783cedbec3SEnji Cooper 		warn("test_blocking: openfifo: testfifo");
4793cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
4803cedbec3SEnji Cooper 		exit(-1);
4813cedbec3SEnji Cooper 	}
4823cedbec3SEnji Cooper 
4833cedbec3SEnji Cooper 	if (set_blocking(writer_fd, __func__) < 0) {
4843cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4853cedbec3SEnji Cooper 		exit(-1);
4863cedbec3SEnji Cooper 	}
4873cedbec3SEnji Cooper 	if (set_blocking(reader_fd, __func__) < 0) {
4883cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4893cedbec3SEnji Cooper 		exit(-1);
4903cedbec3SEnji Cooper 	}
4913cedbec3SEnji Cooper 
4923cedbec3SEnji Cooper 	ch = 0xfe;
4933cedbec3SEnji Cooper 	ret = timed_write(writer_fd, &ch, sizeof(ch), &len, 5, &timedout,
4943cedbec3SEnji Cooper 	    __func__);
4953cedbec3SEnji Cooper 	if (ret < 0) {
4963cedbec3SEnji Cooper 		warn("test_blocking_one_byte: timed_write");
4973cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
4983cedbec3SEnji Cooper 		exit(-1);
4993cedbec3SEnji Cooper 	}
5003cedbec3SEnji Cooper 	if (len != sizeof(ch)) {
5013cedbec3SEnji Cooper 		warnx("test_blocking_one_byte: timed_write: tried to write "
5023cedbec3SEnji Cooper 		    "%zu, wrote %zd", sizeof(ch), len);
5033cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5043cedbec3SEnji Cooper 		exit(-1);
5053cedbec3SEnji Cooper 	}
5063cedbec3SEnji Cooper 
5073cedbec3SEnji Cooper 	ch = 0xab;
5083cedbec3SEnji Cooper 	ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout,
5093cedbec3SEnji Cooper 	    __func__);
5103cedbec3SEnji Cooper 	if (ret < 0) {
5113cedbec3SEnji Cooper 		warn("test_blocking_one_byte: timed_read");
5123cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5133cedbec3SEnji Cooper 		exit(-1);
5143cedbec3SEnji Cooper 	}
5153cedbec3SEnji Cooper 	if (len != sizeof(ch)) {
5163cedbec3SEnji Cooper 		warnx("test_blocking_one_byte: timed_read: wanted %zu, "
5173cedbec3SEnji Cooper 		    "read %zd", sizeof(ch), len);
5183cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5193cedbec3SEnji Cooper 		exit(-1);
5203cedbec3SEnji Cooper 	}
5213cedbec3SEnji Cooper 	if (ch != 0xfe) {
5223cedbec3SEnji Cooper 		warnx("test_blocking_one_byte: timed_read: expected to read "
5233cedbec3SEnji Cooper 		    "0x%02x, read 0x%02x", 0xfe, ch);
5243cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5253cedbec3SEnji Cooper 		exit(-1);
5263cedbec3SEnji Cooper 	}
5273cedbec3SEnji Cooper 
5283cedbec3SEnji Cooper 	cleanfifo2("testfifo", reader_fd, writer_fd);
5293cedbec3SEnji Cooper }
5303cedbec3SEnji Cooper 
5313cedbec3SEnji Cooper /*
5323cedbec3SEnji Cooper  * Write one byte to an empty fifo, then try to read one byte and make sure
5333cedbec3SEnji Cooper  * we don't get back EAGAIN.
5343cedbec3SEnji Cooper  */
5353cedbec3SEnji Cooper static void
test_nonblocking_one_byte(void)5363cedbec3SEnji Cooper test_nonblocking_one_byte(void)
5373cedbec3SEnji Cooper {
5383cedbec3SEnji Cooper 	int reader_fd, ret, timedout, writer_fd;
5393cedbec3SEnji Cooper 	ssize_t len;
5403cedbec3SEnji Cooper 	u_char ch;
5413cedbec3SEnji Cooper 
5423cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
5433cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
5443cedbec3SEnji Cooper 		warn("test_nonblocking: openfifo: testfifo");
5453cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
5463cedbec3SEnji Cooper 		exit(-1);
5473cedbec3SEnji Cooper 	}
5483cedbec3SEnji Cooper 
5493cedbec3SEnji Cooper 	if (set_nonblocking(reader_fd, __func__) < 0) {
5503cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5513cedbec3SEnji Cooper 		exit(-1);
5523cedbec3SEnji Cooper 	}
5533cedbec3SEnji Cooper 
5543cedbec3SEnji Cooper 	ch = 0xfe;
5553cedbec3SEnji Cooper 	ret = timed_write(writer_fd, &ch, sizeof(ch), &len, 5, &timedout,
5563cedbec3SEnji Cooper 	    __func__);
5573cedbec3SEnji Cooper 	if (ret < 0) {
5583cedbec3SEnji Cooper 		warn("test_nonblocking_one_byte: timed_write");
5593cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5603cedbec3SEnji Cooper 		exit(-1);
5613cedbec3SEnji Cooper 	}
5623cedbec3SEnji Cooper 	if (len != sizeof(ch)) {
5633cedbec3SEnji Cooper 		warnx("test_nonblocking_one_byte: timed_write: tried to write "
5643cedbec3SEnji Cooper 		    "%zu, wrote %zd", sizeof(ch), len);
5653cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5663cedbec3SEnji Cooper 		exit(-1);
5673cedbec3SEnji Cooper 	}
5683cedbec3SEnji Cooper 
5693cedbec3SEnji Cooper 	ch = 0xab;
5703cedbec3SEnji Cooper 	ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout,
5713cedbec3SEnji Cooper 	    __func__);
5723cedbec3SEnji Cooper 	if (ret < 0) {
5733cedbec3SEnji Cooper 		warn("test_nonblocking_one_byte: timed_read");
5743cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5753cedbec3SEnji Cooper 		exit(-1);
5763cedbec3SEnji Cooper 	}
5773cedbec3SEnji Cooper 	if (len != sizeof(ch)) {
5783cedbec3SEnji Cooper 		warnx("test_nonblocking_one_byte: timed_read: wanted %zu, read "
5793cedbec3SEnji Cooper 		    "%zd", sizeof(ch), len);
5803cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5813cedbec3SEnji Cooper 		exit(-1);
5823cedbec3SEnji Cooper 	}
5833cedbec3SEnji Cooper 	if (ch != 0xfe) {
5843cedbec3SEnji Cooper 		warnx("test_nonblocking_one_byte: timed_read: expected to read "
5853cedbec3SEnji Cooper 		    "0x%02x, read 0x%02x", 0xfe, ch);
5863cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
5873cedbec3SEnji Cooper 		exit(-1);
5883cedbec3SEnji Cooper 	}
5893cedbec3SEnji Cooper 
5903cedbec3SEnji Cooper 	cleanfifo2("testfifo", reader_fd, writer_fd);
5913cedbec3SEnji Cooper }
5923cedbec3SEnji Cooper 
5933cedbec3SEnji Cooper /*
5943cedbec3SEnji Cooper  * First of two test cases involving a 512K buffer: write the buffer into a
5953cedbec3SEnji Cooper  * blocking file descriptor.  We'd like to know it blocks, but the closest we
5963cedbec3SEnji Cooper  * can get is to see if SIGALRM fired during the I/O resulting in a partial
5973cedbec3SEnji Cooper  * write.
5983cedbec3SEnji Cooper  */
5993cedbec3SEnji Cooper static void
test_blocking_partial_write(void)6003cedbec3SEnji Cooper test_blocking_partial_write(void)
6013cedbec3SEnji Cooper {
6023cedbec3SEnji Cooper 	int reader_fd, ret, timedout, writer_fd;
6033cedbec3SEnji Cooper 	u_char *buffer;
6043cedbec3SEnji Cooper 	ssize_t len;
6053cedbec3SEnji Cooper 
6063cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
6073cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
6083cedbec3SEnji Cooper 		warn("test_blocking_partial_write: openfifo: testfifo");
6093cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
6103cedbec3SEnji Cooper 		exit(-1);
6113cedbec3SEnji Cooper 	}
6123cedbec3SEnji Cooper 
6133cedbec3SEnji Cooper 	if (set_blocking(writer_fd, __func__) < 0) {
6143cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6153cedbec3SEnji Cooper 		exit(-1);
6163cedbec3SEnji Cooper 	}
6173cedbec3SEnji Cooper 
6183cedbec3SEnji Cooper 	buffer = malloc(512*1024);
6193cedbec3SEnji Cooper 	if (buffer == NULL) {
6203cedbec3SEnji Cooper 		warn("test_blocking_partial_write: malloc");
6213cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6223cedbec3SEnji Cooper 		exit(-1);
6233cedbec3SEnji Cooper 	}
6243cedbec3SEnji Cooper 	bzero(buffer, 512*1024);
6253cedbec3SEnji Cooper 
6263cedbec3SEnji Cooper 	ret = timed_write(writer_fd, buffer, 512*1024, &len, 5, &timedout,
6273cedbec3SEnji Cooper 	    __func__);
6283cedbec3SEnji Cooper 	if (ret < 0) {
6293cedbec3SEnji Cooper 		warn("test_blocking_partial_write: timed_write");
6303cedbec3SEnji Cooper 		free(buffer);
6313cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6323cedbec3SEnji Cooper 		exit(-1);
6333cedbec3SEnji Cooper 	}
6343cedbec3SEnji Cooper 
6353cedbec3SEnji Cooper 	if (!timedout) {
6363cedbec3SEnji Cooper 		warnx("test_blocking_partial_write: timed_write: blocking "
6373cedbec3SEnji Cooper 		    "socket didn't time out");
6383cedbec3SEnji Cooper 		free(buffer);
6393cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6403cedbec3SEnji Cooper 		exit(-1);
6413cedbec3SEnji Cooper 	}
6423cedbec3SEnji Cooper 
6433cedbec3SEnji Cooper 	free(buffer);
6443cedbec3SEnji Cooper 
6453cedbec3SEnji Cooper 	if (drain_fd(reader_fd, __func__) < 0) {
6463cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6473cedbec3SEnji Cooper 		exit(-1);
6483cedbec3SEnji Cooper 	}
6493cedbec3SEnji Cooper 
6503cedbec3SEnji Cooper 	cleanfifo2("testfifo", reader_fd, writer_fd);
6513cedbec3SEnji Cooper }
6523cedbec3SEnji Cooper 
6533cedbec3SEnji Cooper /*
6543cedbec3SEnji Cooper  * Write a 512K buffer to an empty fifo using a non-blocking file descriptor,
6553cedbec3SEnji Cooper  * and make sure it doesn't block.
6563cedbec3SEnji Cooper  */
6573cedbec3SEnji Cooper static void
test_nonblocking_partial_write(void)6583cedbec3SEnji Cooper test_nonblocking_partial_write(void)
6593cedbec3SEnji Cooper {
6603cedbec3SEnji Cooper 	int reader_fd, ret, timedout, writer_fd;
6613cedbec3SEnji Cooper 	u_char *buffer;
6623cedbec3SEnji Cooper 	ssize_t len;
6633cedbec3SEnji Cooper 
6643cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
6653cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
6663cedbec3SEnji Cooper 		warn("test_blocking_partial_write: openfifo: testfifo");
6673cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
6683cedbec3SEnji Cooper 		exit(-1);
6693cedbec3SEnji Cooper 	}
6703cedbec3SEnji Cooper 
6713cedbec3SEnji Cooper 	if (set_nonblocking(writer_fd, __func__) < 0) {
6723cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6733cedbec3SEnji Cooper 		exit(-1);
6743cedbec3SEnji Cooper 	}
6753cedbec3SEnji Cooper 
6763cedbec3SEnji Cooper 	buffer = malloc(512*1024);
6773cedbec3SEnji Cooper 	if (buffer == NULL) {
6783cedbec3SEnji Cooper 		warn("test_blocking_partial_write: malloc");
6793cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6803cedbec3SEnji Cooper 		exit(-1);
6813cedbec3SEnji Cooper 	}
6823cedbec3SEnji Cooper 	bzero(buffer, 512*1024);
6833cedbec3SEnji Cooper 
6843cedbec3SEnji Cooper 	ret = timed_write(writer_fd, buffer, 512*1024, &len, 5, &timedout,
6853cedbec3SEnji Cooper 	    __func__);
6863cedbec3SEnji Cooper 	if (ret < 0) {
6873cedbec3SEnji Cooper 		warn("test_blocking_partial_write: timed_write");
6883cedbec3SEnji Cooper 		free(buffer);
6893cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6903cedbec3SEnji Cooper 		exit(-1);
6913cedbec3SEnji Cooper 	}
6923cedbec3SEnji Cooper 
6933cedbec3SEnji Cooper 	if (timedout) {
6943cedbec3SEnji Cooper 		warnx("test_blocking_partial_write: timed_write: "
6953cedbec3SEnji Cooper 		    "non-blocking socket timed out");
6963cedbec3SEnji Cooper 		free(buffer);
6973cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
6983cedbec3SEnji Cooper 		exit(-1);
6993cedbec3SEnji Cooper 	}
7003cedbec3SEnji Cooper 
7013cedbec3SEnji Cooper 	if (len == 0 || len >= 512*1024) {
7023cedbec3SEnji Cooper 		warnx("test_blocking_partial_write: timed_write: requested "
7033cedbec3SEnji Cooper 		    "%d, sent %zd", 512*1024, len);
7043cedbec3SEnji Cooper 		free(buffer);
7053cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7063cedbec3SEnji Cooper 		exit(-1);
7073cedbec3SEnji Cooper 	}
7083cedbec3SEnji Cooper 
7093cedbec3SEnji Cooper 	free(buffer);
7103cedbec3SEnji Cooper 
7113cedbec3SEnji Cooper 	if (drain_fd(reader_fd, __func__) < 0) {
7123cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7133cedbec3SEnji Cooper 		exit(-1);
7143cedbec3SEnji Cooper 	}
7153cedbec3SEnji Cooper 
7163cedbec3SEnji Cooper 	cleanfifo2("testfifo", reader_fd, writer_fd);
7173cedbec3SEnji Cooper }
7183cedbec3SEnji Cooper 
7193cedbec3SEnji Cooper /*
7203cedbec3SEnji Cooper  * test_coalesce_big_read() verifies that data mingles in the fifo across
7213cedbec3SEnji Cooper  * message boundaries by performing two small writes, then a bigger read
7223cedbec3SEnji Cooper  * that should return data from both writes.
7233cedbec3SEnji Cooper  */
7243cedbec3SEnji Cooper static void
test_coalesce_big_read(void)7253cedbec3SEnji Cooper test_coalesce_big_read(void)
7263cedbec3SEnji Cooper {
7273cedbec3SEnji Cooper 	int i, reader_fd, writer_fd;
7283cedbec3SEnji Cooper 	u_char buffer[10];
7293cedbec3SEnji Cooper 	ssize_t len;
7303cedbec3SEnji Cooper 
7313cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
7323cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
7333cedbec3SEnji Cooper 		warn("test_coalesce_big_read: openfifo: testfifo");
7343cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
7353cedbec3SEnji Cooper 		exit(-1);
7363cedbec3SEnji Cooper 	}
7373cedbec3SEnji Cooper 
7383cedbec3SEnji Cooper 	/* Write five, write five, read ten. */
7393cedbec3SEnji Cooper 	for (i = 0; i < 10; i++)
7403cedbec3SEnji Cooper 		buffer[i] = i;
7413cedbec3SEnji Cooper 
7423cedbec3SEnji Cooper 	len = write(writer_fd, buffer, 5);
7433cedbec3SEnji Cooper 	if (len < 0) {
7443cedbec3SEnji Cooper 		warn("test_coalesce_big_read: write 5");
7453cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7463cedbec3SEnji Cooper 		exit(-1);
7473cedbec3SEnji Cooper 	}
7483cedbec3SEnji Cooper 	if (len != 5) {
7493cedbec3SEnji Cooper 		warnx("test_coalesce_big_read: write 5 wrote %zd", len);
7503cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7513cedbec3SEnji Cooper 		exit(-1);
7523cedbec3SEnji Cooper 	}
7533cedbec3SEnji Cooper 
7543cedbec3SEnji Cooper 	len = write(writer_fd, buffer + 5, 5);
7553cedbec3SEnji Cooper 	if (len < 0) {
7563cedbec3SEnji Cooper 		warn("test_coalesce_big_read: write 5");
7573cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7583cedbec3SEnji Cooper 		exit(-1);
7593cedbec3SEnji Cooper 	}
7603cedbec3SEnji Cooper 	if (len != 5) {
7613cedbec3SEnji Cooper 		warnx("test_coalesce_big_read: write 5 wrote %zd", len);
7623cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7633cedbec3SEnji Cooper 		exit(-1);
7643cedbec3SEnji Cooper 	}
7653cedbec3SEnji Cooper 
7663cedbec3SEnji Cooper 	len = read(reader_fd, buffer, 10);
7673cedbec3SEnji Cooper 	if (len < 0) {
7683cedbec3SEnji Cooper 		warn("test_coalesce_big_read: read 10");
7693cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7703cedbec3SEnji Cooper 		exit(-1);
7713cedbec3SEnji Cooper 	}
7723cedbec3SEnji Cooper 	if (len != 10) {
7733cedbec3SEnji Cooper 		warnx("test_coalesce_big_read: read 10 read %zd", len);
7743cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7753cedbec3SEnji Cooper 		exit(-1);
7763cedbec3SEnji Cooper 	}
7773cedbec3SEnji Cooper 
7783cedbec3SEnji Cooper 	for (i = 0; i < 10; i++) {
7793cedbec3SEnji Cooper 		if (buffer[i] == i)
7803cedbec3SEnji Cooper 			continue;
7813cedbec3SEnji Cooper 		warnx("test_coalesce_big_read: expected to read 0x%02x, "
7823cedbec3SEnji Cooper 		    "read 0x%02x", i, buffer[i]);
7833cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
7843cedbec3SEnji Cooper 		exit(-1);
7853cedbec3SEnji Cooper 	}
7863cedbec3SEnji Cooper 
7873cedbec3SEnji Cooper 	cleanfifo2("testfifo", -1, -1);
7883cedbec3SEnji Cooper }
7893cedbec3SEnji Cooper 
7903cedbec3SEnji Cooper /*
7913cedbec3SEnji Cooper  * test_coalesce_big_write() verifies that data mingles in the fifo across
7923cedbec3SEnji Cooper  * message boundaries by performing one big write, then two smaller reads
7933cedbec3SEnji Cooper  * that should return sequential elements of data from the write.
7943cedbec3SEnji Cooper  */
7953cedbec3SEnji Cooper static void
test_coalesce_big_write(void)7963cedbec3SEnji Cooper test_coalesce_big_write(void)
7973cedbec3SEnji Cooper {
7983cedbec3SEnji Cooper 	int i, reader_fd, writer_fd;
7993cedbec3SEnji Cooper 	u_char buffer[10];
8003cedbec3SEnji Cooper 	ssize_t len;
8013cedbec3SEnji Cooper 
8023cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
8033cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
8043cedbec3SEnji Cooper 		warn("test_coalesce_big_write: openfifo: testfifo");
8053cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
8063cedbec3SEnji Cooper 		exit(-1);
8073cedbec3SEnji Cooper 	}
8083cedbec3SEnji Cooper 
8093cedbec3SEnji Cooper 	/* Write ten, read five, read five. */
8103cedbec3SEnji Cooper 	for (i = 0; i < 10; i++)
8113cedbec3SEnji Cooper 		buffer[i] = i;
8123cedbec3SEnji Cooper 
8133cedbec3SEnji Cooper 	len = write(writer_fd, buffer, 10);
8143cedbec3SEnji Cooper 	if (len < 0) {
8153cedbec3SEnji Cooper 		warn("test_coalesce_big_write: write 10");
8163cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
8173cedbec3SEnji Cooper 		exit(-1);
8183cedbec3SEnji Cooper 	}
8193cedbec3SEnji Cooper 	if (len != 10) {
8203cedbec3SEnji Cooper 		warnx("test_coalesce_big_write: write 10 wrote %zd", len);
8213cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
8223cedbec3SEnji Cooper 		exit(-1);
8233cedbec3SEnji Cooper 	}
8243cedbec3SEnji Cooper 
8253cedbec3SEnji Cooper 	len = read(reader_fd, buffer, 5);
8263cedbec3SEnji Cooper 	if (len < 0) {
8273cedbec3SEnji Cooper 		warn("test_coalesce_big_write: read 5");
8283cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
8293cedbec3SEnji Cooper 		exit(-1);
8303cedbec3SEnji Cooper 	}
8313cedbec3SEnji Cooper 	if (len != 5) {
8323cedbec3SEnji Cooper 		warnx("test_coalesce_big_write: read 5 read %zd", len);
8333cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
8343cedbec3SEnji Cooper 		exit(-1);
8353cedbec3SEnji Cooper 	}
8363cedbec3SEnji Cooper 
8373cedbec3SEnji Cooper 	len = read(reader_fd, buffer + 5, 5);
8383cedbec3SEnji Cooper 	if (len < 0) {
8393cedbec3SEnji Cooper 		warn("test_coalesce_big_write: read 5");
8403cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
8413cedbec3SEnji Cooper 		exit(-1);
8423cedbec3SEnji Cooper 	}
8433cedbec3SEnji Cooper 	if (len != 5) {
8443cedbec3SEnji Cooper 		warnx("test_coalesce_big_write: read 5 read %zd", len);
8453cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
8463cedbec3SEnji Cooper 		exit(-1);
8473cedbec3SEnji Cooper 	}
8483cedbec3SEnji Cooper 
8493cedbec3SEnji Cooper 	for (i = 0; i < 10; i++) {
8503cedbec3SEnji Cooper 		if (buffer[i] == i)
8513cedbec3SEnji Cooper 			continue;
8523cedbec3SEnji Cooper 		warnx("test_coalesce_big_write: expected to read 0x%02x, "
8533cedbec3SEnji Cooper 		    "read 0x%02x", i, buffer[i]);
8543cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
8553cedbec3SEnji Cooper 		exit(-1);
8563cedbec3SEnji Cooper 	}
8573cedbec3SEnji Cooper 
8583cedbec3SEnji Cooper 	cleanfifo2("testfifo", -1, -1);
8593cedbec3SEnji Cooper }
8603cedbec3SEnji Cooper 
8613cedbec3SEnji Cooper static int
poll_status(int fd,int * readable,int * writable,int * exception,const char * testname)8623cedbec3SEnji Cooper poll_status(int fd, int *readable, int *writable, int *exception,
8633cedbec3SEnji Cooper     const char *testname)
8643cedbec3SEnji Cooper {
8653cedbec3SEnji Cooper 	struct pollfd fds[1];
8663cedbec3SEnji Cooper 
8673cedbec3SEnji Cooper 	fds[0].fd = fd;
8683cedbec3SEnji Cooper 	fds[0].events = POLLIN | POLLOUT | POLLERR;
8693cedbec3SEnji Cooper 	fds[0].revents = 0;
8703cedbec3SEnji Cooper 
8713cedbec3SEnji Cooper 	if (poll(fds, 1, 0) < 0) {
8723cedbec3SEnji Cooper 		warn("%s: poll", testname);
8733cedbec3SEnji Cooper 		return (-1);
8743cedbec3SEnji Cooper 	}
8753cedbec3SEnji Cooper 	*readable = (fds[0].revents & POLLIN) ? 1 : 0;
8763cedbec3SEnji Cooper 	*writable = (fds[0].revents & POLLOUT) ? 1 : 0;
8773cedbec3SEnji Cooper 	*exception = (fds[0].revents & POLLERR) ? 1 : 0;
8783cedbec3SEnji Cooper 	return (0);
8793cedbec3SEnji Cooper }
8803cedbec3SEnji Cooper 
8813cedbec3SEnji Cooper static int
select_status(int fd,int * readable,int * writable,int * exception,const char * testname)8823cedbec3SEnji Cooper select_status(int fd, int *readable, int *writable, int *exception,
8833cedbec3SEnji Cooper     const char *testname)
8843cedbec3SEnji Cooper {
8853cedbec3SEnji Cooper 	struct fd_set readfds, writefds, exceptfds;
8863cedbec3SEnji Cooper 	struct timeval timeout;
8873cedbec3SEnji Cooper 
8883cedbec3SEnji Cooper 	FD_ZERO(&readfds);
8893cedbec3SEnji Cooper 	FD_ZERO(&writefds);
8903cedbec3SEnji Cooper 	FD_ZERO(&exceptfds);
8913cedbec3SEnji Cooper 	FD_SET(fd, &readfds);
8923cedbec3SEnji Cooper 	FD_SET(fd, &writefds);
8933cedbec3SEnji Cooper 	FD_SET(fd, &exceptfds);
8943cedbec3SEnji Cooper 	timeout.tv_sec = 0;
8953cedbec3SEnji Cooper 	timeout.tv_usec = 0;
8963cedbec3SEnji Cooper 	if (select(fd+1, &readfds, &writefds, &exceptfds, &timeout) < 0) {
8973cedbec3SEnji Cooper 		warn("%s: select", testname);
8983cedbec3SEnji Cooper 		return (-1);
8993cedbec3SEnji Cooper 	}
9003cedbec3SEnji Cooper 	*readable = FD_ISSET(fd, &readfds) ? 1 : 0;
9013cedbec3SEnji Cooper 	*writable = FD_ISSET(fd, &writefds) ? 1 : 0;
9023cedbec3SEnji Cooper 	*exception = FD_ISSET(fd, &exceptfds) ? 1 : 0;
9033cedbec3SEnji Cooper 	return (0);
9043cedbec3SEnji Cooper }
9053cedbec3SEnji Cooper 
9063cedbec3SEnji Cooper /*
9073cedbec3SEnji Cooper  * Given an existing kqueue, set up read and write event filters for the
9083cedbec3SEnji Cooper  * passed file descriptor.  Typically called once for the read endpoint, and
9093cedbec3SEnji Cooper  * once for the write endpoint.
9103cedbec3SEnji Cooper  */
9113cedbec3SEnji Cooper static int
kqueue_setup(int kqueue_fd,int fd,const char * testname)9123cedbec3SEnji Cooper kqueue_setup(int kqueue_fd, int fd, const char *testname)
9133cedbec3SEnji Cooper {
9143cedbec3SEnji Cooper 	struct kevent kevent_changelist[2];
9153cedbec3SEnji Cooper 	struct kevent kevent_eventlist[KQUEUE_MAX_EVENT], *kp;
9163cedbec3SEnji Cooper 	struct timespec timeout;
9173cedbec3SEnji Cooper 	int i, ret;
9183cedbec3SEnji Cooper 
9193cedbec3SEnji Cooper 	timeout.tv_sec = 0;
9203cedbec3SEnji Cooper 	timeout.tv_nsec = 0;
9213cedbec3SEnji Cooper 
9223cedbec3SEnji Cooper 	bzero(&kevent_changelist, sizeof(kevent_changelist));
9233cedbec3SEnji Cooper 	EV_SET(&kevent_changelist[0], fd, EVFILT_READ, EV_ADD, 0, 0, 0);
9243cedbec3SEnji Cooper 	EV_SET(&kevent_changelist[1], fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
9253cedbec3SEnji Cooper 
9263cedbec3SEnji Cooper 	bzero(&kevent_eventlist, sizeof(kevent_eventlist));
9273cedbec3SEnji Cooper 	ret = kevent(kqueue_fd, kevent_changelist, 2, kevent_eventlist,
9283cedbec3SEnji Cooper 	    KQUEUE_MAX_EVENT, &timeout);
9293cedbec3SEnji Cooper 	if (ret < 0) {
9303cedbec3SEnji Cooper 		warn("%s:%s: kevent initial register", testname, __func__);
9313cedbec3SEnji Cooper 		return (-1);
9323cedbec3SEnji Cooper 	}
9333cedbec3SEnji Cooper 
9343cedbec3SEnji Cooper 	/*
9353cedbec3SEnji Cooper 	 * Verify that the events registered alright.
9363cedbec3SEnji Cooper 	 */
9373cedbec3SEnji Cooper 	for (i = 0; i < ret; i++) {
9383cedbec3SEnji Cooper 		kp = &kevent_eventlist[i];
9393cedbec3SEnji Cooper 		if (kp->flags != EV_ERROR)
9403cedbec3SEnji Cooper 			continue;
9413cedbec3SEnji Cooper 		errno = kp->data;
9423cedbec3SEnji Cooper 		warn("%s:%s: kevent register index %d", testname, __func__,
9433cedbec3SEnji Cooper 		    i);
9443cedbec3SEnji Cooper 		return (-1);
9453cedbec3SEnji Cooper 	}
9463cedbec3SEnji Cooper 
9473cedbec3SEnji Cooper 	return (0);
9483cedbec3SEnji Cooper }
9493cedbec3SEnji Cooper 
9503cedbec3SEnji Cooper static int
kqueue_status(int kqueue_fd,int fd,int * readable,int * writable,int * exception,const char * testname)9513cedbec3SEnji Cooper kqueue_status(int kqueue_fd, int fd, int *readable, int *writable,
9523cedbec3SEnji Cooper     int *exception, const char *testname)
9533cedbec3SEnji Cooper {
9543cedbec3SEnji Cooper 	struct kevent kevent_eventlist[KQUEUE_MAX_EVENT], *kp;
9553cedbec3SEnji Cooper 	struct timespec timeout;
9563cedbec3SEnji Cooper 	int i, ret;
9573cedbec3SEnji Cooper 
9583cedbec3SEnji Cooper 	timeout.tv_sec = 0;
9593cedbec3SEnji Cooper 	timeout.tv_nsec = 0;
9603cedbec3SEnji Cooper 
9613cedbec3SEnji Cooper 	ret = kevent(kqueue_fd, NULL, 0, kevent_eventlist, KQUEUE_MAX_EVENT,
9623cedbec3SEnji Cooper 	    &timeout);
9633cedbec3SEnji Cooper 	if (ret < 0) {
9643cedbec3SEnji Cooper 		warn("%s: %s: kevent", testname, __func__);
9653cedbec3SEnji Cooper 		return (-1);
9663cedbec3SEnji Cooper 	}
9673cedbec3SEnji Cooper 
9683cedbec3SEnji Cooper 	*readable = *writable = *exception = 0;
9693cedbec3SEnji Cooper 	for (i = 0; i < ret; i++) {
9703cedbec3SEnji Cooper 		kp = &kevent_eventlist[i];
9713cedbec3SEnji Cooper 		if (kp->ident != (u_int)fd)
9723cedbec3SEnji Cooper 			continue;
9733cedbec3SEnji Cooper 		if (kp->filter == EVFILT_READ)
9743cedbec3SEnji Cooper 			*readable = 1;
9753cedbec3SEnji Cooper 		if (kp->filter == EVFILT_WRITE)
9763cedbec3SEnji Cooper 			*writable = 1;
9773cedbec3SEnji Cooper 	}
9783cedbec3SEnji Cooper 
9793cedbec3SEnji Cooper 	return (0);
9803cedbec3SEnji Cooper }
9813cedbec3SEnji Cooper 
9823cedbec3SEnji Cooper static int
fionread_status(int fd,int * readable,const char * testname)9833cedbec3SEnji Cooper fionread_status(int fd, int *readable, const char *testname)
9843cedbec3SEnji Cooper {
9853cedbec3SEnji Cooper 	int i;
9863cedbec3SEnji Cooper 
9873cedbec3SEnji Cooper 	if (ioctl(fd, FIONREAD, &i) < 0) {
9883cedbec3SEnji Cooper 		warn("%s: ioctl(FIONREAD)", testname);
9893cedbec3SEnji Cooper 		return (-1);
9903cedbec3SEnji Cooper 	}
9913cedbec3SEnji Cooper 
9923cedbec3SEnji Cooper 	if (i > 0)
9933cedbec3SEnji Cooper 		*readable = 1;
9943cedbec3SEnji Cooper 	else
9953cedbec3SEnji Cooper 		*readable = 0;
9963cedbec3SEnji Cooper 	return (0);
9973cedbec3SEnji Cooper }
9983cedbec3SEnji Cooper 
9993cedbec3SEnji Cooper #define	READABLE	1
10003cedbec3SEnji Cooper #define	WRITABLE	1
10013cedbec3SEnji Cooper #define	EXCEPTION	1
10023cedbec3SEnji Cooper 
10033cedbec3SEnji Cooper #define	NOT_READABLE	0
10043cedbec3SEnji Cooper #define	NOT_WRITABLE	0
10053cedbec3SEnji Cooper #define	NOT_EXCEPTION	0
10063cedbec3SEnji Cooper 
10073cedbec3SEnji Cooper static int
assert_status(int fd,int kqueue_fd,int assert_readable,int assert_writable,int assert_exception,const char * testname,const char * conditionname,const char * fdname)10083cedbec3SEnji Cooper assert_status(int fd, int kqueue_fd, int assert_readable,
10093cedbec3SEnji Cooper     int assert_writable, int assert_exception, const char *testname,
10103cedbec3SEnji Cooper     const char *conditionname, const char *fdname)
10113cedbec3SEnji Cooper {
10123cedbec3SEnji Cooper 	int readable, writable, exception;
10133cedbec3SEnji Cooper 
10143cedbec3SEnji Cooper 	if (poll_status(fd, &readable, &writable, &exception, testname) < 0)
10153cedbec3SEnji Cooper 		return (-1);
10163cedbec3SEnji Cooper 
10173cedbec3SEnji Cooper 	if (readable != assert_readable || writable != assert_writable ||
10183cedbec3SEnji Cooper 	    exception != assert_exception) {
10193cedbec3SEnji Cooper 		warnx("%s: %s polls r:%d, w:%d, e:%d on %s", testname,
10203cedbec3SEnji Cooper 		    fdname, readable, writable, exception, conditionname);
10213cedbec3SEnji Cooper 		return (-1);
10223cedbec3SEnji Cooper 	}
10233cedbec3SEnji Cooper 
10243cedbec3SEnji Cooper 	if (select_status(fd, &readable, &writable, &exception, testname) < 0)
10253cedbec3SEnji Cooper 		return (-1);
10263cedbec3SEnji Cooper 
10273cedbec3SEnji Cooper 	if (readable != assert_readable || writable != assert_writable ||
10283cedbec3SEnji Cooper 	    exception != assert_exception) {
10293cedbec3SEnji Cooper 		warnx("%s: %s selects r:%d, w:%d, e:%d on %s", testname,
10303cedbec3SEnji Cooper 		    fdname, readable, writable, exception, conditionname);
10313cedbec3SEnji Cooper 		return (-1);
10323cedbec3SEnji Cooper 	}
10333cedbec3SEnji Cooper 
10343cedbec3SEnji Cooper 	if (kqueue_status(kqueue_fd, fd, &readable, &writable, &exception,
10353cedbec3SEnji Cooper 	    testname) < 0)
10363cedbec3SEnji Cooper 		return (-1);
10373cedbec3SEnji Cooper 
10383cedbec3SEnji Cooper 	if (readable != assert_readable || writable != assert_writable ||
10393cedbec3SEnji Cooper 	    exception != assert_exception) {
10403cedbec3SEnji Cooper 		warnx("%s: %s kevent r:%d, w:%d, e:%d on %s", testname,
10413cedbec3SEnji Cooper 		    fdname, readable, writable, exception, conditionname);
10423cedbec3SEnji Cooper 		return (-1);
10433cedbec3SEnji Cooper 	}
10443cedbec3SEnji Cooper 
10453cedbec3SEnji Cooper 	if (fionread_status(fd, &readable, __func__) < 0)
10463cedbec3SEnji Cooper 		return (-1);
10473cedbec3SEnji Cooper 
10483cedbec3SEnji Cooper 	if (readable != assert_readable) {
10493cedbec3SEnji Cooper 		warnx("%s: %s fionread r:%d on %s", testname, fdname,
10503cedbec3SEnji Cooper 		    readable, conditionname);
10513cedbec3SEnji Cooper 		return (-1);
10523cedbec3SEnji Cooper 	}
10533cedbec3SEnji Cooper 
10543cedbec3SEnji Cooper 	return (0);
10553cedbec3SEnji Cooper }
10563cedbec3SEnji Cooper 
10573cedbec3SEnji Cooper /*
10583cedbec3SEnji Cooper  * test_events() uses poll(), select(), and kevent() to query the status of
10593cedbec3SEnji Cooper  * fifo file descriptors and determine whether they match expected state
10603cedbec3SEnji Cooper  * based on earlier semantic tests: specifically, whether or not poll/select/
10613cedbec3SEnji Cooper  * kevent will correctly inform on readable/writable state following I/O.
10623cedbec3SEnji Cooper  *
10633cedbec3SEnji Cooper  * It would be nice to also test status changes as a result of closing of one
10643cedbec3SEnji Cooper  * or another fifo endpoint.
10653cedbec3SEnji Cooper  */
10663cedbec3SEnji Cooper static void
test_events_outofbox(void)10673cedbec3SEnji Cooper test_events_outofbox(void)
10683cedbec3SEnji Cooper {
10693cedbec3SEnji Cooper 	int kqueue_fd, reader_fd, writer_fd;
10703cedbec3SEnji Cooper 
10713cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
10723cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
10733cedbec3SEnji Cooper 		warn("test_events_outofbox: openfifo: testfifo");
10743cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
10753cedbec3SEnji Cooper 		exit(-1);
10763cedbec3SEnji Cooper 	}
10773cedbec3SEnji Cooper 
10783cedbec3SEnji Cooper 	kqueue_fd = kqueue();
10793cedbec3SEnji Cooper 	if (kqueue_fd < 0) {
10803cedbec3SEnji Cooper 		warn("%s: kqueue", __func__);
10813cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
10823cedbec3SEnji Cooper 		exit(-1);
10833cedbec3SEnji Cooper 	}
10843cedbec3SEnji Cooper 
10853cedbec3SEnji Cooper 	if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) {
10863cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
10873cedbec3SEnji Cooper 		exit(-1);
10883cedbec3SEnji Cooper 	}
10893cedbec3SEnji Cooper 
10903cedbec3SEnji Cooper 	if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) {
10913cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
10923cedbec3SEnji Cooper 		exit(-1);
10933cedbec3SEnji Cooper 	}
10943cedbec3SEnji Cooper 
10953cedbec3SEnji Cooper 	/*
10963cedbec3SEnji Cooper 	 * Make sure that fresh, out-of-the-box fifo file descriptors have
10973cedbec3SEnji Cooper 	 * good initial states.  The reader_fd should have no active state,
10983cedbec3SEnji Cooper 	 * since it will not be readable (no data in pipe), writable (it's
10993cedbec3SEnji Cooper 	 * a read-only descriptor), and there's no reason for error yet.
11003cedbec3SEnji Cooper 	 */
11013cedbec3SEnji Cooper 	if (assert_status(reader_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE,
11023cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "create", "reader_fd") < 0) {
11033cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11043cedbec3SEnji Cooper 		exit(-1);
11053cedbec3SEnji Cooper 	}
11063cedbec3SEnji Cooper 
11073cedbec3SEnji Cooper 	/*
11083cedbec3SEnji Cooper 	 * Make sure that fresh, out-of-the-box fifo file descriptors have
11093cedbec3SEnji Cooper 	 * good initial states.  The writer_fd should be ready to write.
11103cedbec3SEnji Cooper 	 */
11113cedbec3SEnji Cooper 	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE,
11123cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "create", "writer_fd") < 0) {
11133cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11143cedbec3SEnji Cooper 		exit(-1);
11153cedbec3SEnji Cooper 	}
11163cedbec3SEnji Cooper 
11173cedbec3SEnji Cooper 	cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11183cedbec3SEnji Cooper }
11193cedbec3SEnji Cooper 
11203cedbec3SEnji Cooper static void
test_events_write_read_byte(void)11213cedbec3SEnji Cooper test_events_write_read_byte(void)
11223cedbec3SEnji Cooper {
11233cedbec3SEnji Cooper 	int kqueue_fd, reader_fd, writer_fd;
11243cedbec3SEnji Cooper 	ssize_t len;
11253cedbec3SEnji Cooper 	u_char ch;
11263cedbec3SEnji Cooper 
11273cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
11283cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
11293cedbec3SEnji Cooper 		warn("test_events_write_read_byte: openfifo: testfifo");
11303cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
11313cedbec3SEnji Cooper 		exit(-1);
11323cedbec3SEnji Cooper 	}
11333cedbec3SEnji Cooper 
11343cedbec3SEnji Cooper 	kqueue_fd = kqueue();
11353cedbec3SEnji Cooper 	if (kqueue_fd < 0) {
11363cedbec3SEnji Cooper 		warn("%s: kqueue", __func__);
11373cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
11383cedbec3SEnji Cooper 		exit(-1);
11393cedbec3SEnji Cooper 	}
11403cedbec3SEnji Cooper 
11413cedbec3SEnji Cooper 	if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) {
11423cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11433cedbec3SEnji Cooper 		exit(-1);
11443cedbec3SEnji Cooper 	}
11453cedbec3SEnji Cooper 
11463cedbec3SEnji Cooper 	if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) {
11473cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11483cedbec3SEnji Cooper 		exit(-1);
11493cedbec3SEnji Cooper 	}
11503cedbec3SEnji Cooper 
11513cedbec3SEnji Cooper 	/*
11523cedbec3SEnji Cooper 	 * Write a byte to the fifo, and make sure that the read end becomes
11533cedbec3SEnji Cooper 	 * readable, and that the write end remains writable (small write).
11543cedbec3SEnji Cooper 	 */
11553cedbec3SEnji Cooper 	ch = 0x00;
11563cedbec3SEnji Cooper 	len = write(writer_fd, &ch, sizeof(ch));
11573cedbec3SEnji Cooper 	if (len < 0) {
11583cedbec3SEnji Cooper 		warn("%s: write", __func__);
11593cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11603cedbec3SEnji Cooper 		exit(-1);
11613cedbec3SEnji Cooper 	}
11623cedbec3SEnji Cooper 
11633cedbec3SEnji Cooper 	if (assert_status(reader_fd, kqueue_fd, READABLE, NOT_WRITABLE,
11643cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "write", "reader_fd") < 0) {
11653cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11663cedbec3SEnji Cooper 		exit(-1);
11673cedbec3SEnji Cooper 	}
11683cedbec3SEnji Cooper 
11693cedbec3SEnji Cooper 	/*
11703cedbec3SEnji Cooper 	 * the writer_fd should remain writable.
11713cedbec3SEnji Cooper 	 */
11723cedbec3SEnji Cooper 	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE,
11733cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "write", "writer_fd") < 0) {
11743cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11753cedbec3SEnji Cooper 		exit(-1);
11763cedbec3SEnji Cooper 	}
11773cedbec3SEnji Cooper 
11783cedbec3SEnji Cooper 	/*
1179*99144520SEitan Adler 	 * Read the byte from the reader_fd, and now confirm that the fifo
11803cedbec3SEnji Cooper 	 * becomes unreadable.
11813cedbec3SEnji Cooper 	 */
11823cedbec3SEnji Cooper 	len = read(reader_fd, &ch, sizeof(ch));
11833cedbec3SEnji Cooper 	if (len < 0) {
11843cedbec3SEnji Cooper 		warn("%s: read", __func__);
11853cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11863cedbec3SEnji Cooper 		exit(-1);
11873cedbec3SEnji Cooper 	}
11883cedbec3SEnji Cooper 
11893cedbec3SEnji Cooper 	if (assert_status(reader_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE,
11903cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "write+read", "reader_fd") < 0) {
11913cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
11923cedbec3SEnji Cooper 		exit(-1);
11933cedbec3SEnji Cooper 	}
11943cedbec3SEnji Cooper 
11953cedbec3SEnji Cooper 	/*
11963cedbec3SEnji Cooper 	 * The writer_fd should remain writable.
11973cedbec3SEnji Cooper 	 */
11983cedbec3SEnji Cooper 	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE,
11993cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "write+read", "writer_fd") < 0) {
12003cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12013cedbec3SEnji Cooper 		exit(-1);
12023cedbec3SEnji Cooper 	}
12033cedbec3SEnji Cooper 
12043cedbec3SEnji Cooper 	cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12053cedbec3SEnji Cooper }
12063cedbec3SEnji Cooper 
12073cedbec3SEnji Cooper /*
12083cedbec3SEnji Cooper  * Write a 512k buffer to the fifo in non-blocking mode, and make sure that
12093cedbec3SEnji Cooper  * the write end becomes un-writable as a result of a partial write that
12103cedbec3SEnji Cooper  * fills the fifo buffer.
12113cedbec3SEnji Cooper  */
12123cedbec3SEnji Cooper static void
test_events_partial_write(void)12133cedbec3SEnji Cooper test_events_partial_write(void)
12143cedbec3SEnji Cooper {
12153cedbec3SEnji Cooper 	int kqueue_fd, reader_fd, writer_fd;
12163cedbec3SEnji Cooper 	u_char *buffer;
12173cedbec3SEnji Cooper 	ssize_t len;
12183cedbec3SEnji Cooper 
12193cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
12203cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
12213cedbec3SEnji Cooper 		warn("test_events_partial_write: openfifo: testfifo");
12223cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
12233cedbec3SEnji Cooper 		exit(-1);
12243cedbec3SEnji Cooper 	}
12253cedbec3SEnji Cooper 
12263cedbec3SEnji Cooper 	kqueue_fd = kqueue();
12273cedbec3SEnji Cooper 	if (kqueue_fd < 0) {
12283cedbec3SEnji Cooper 		warn("%s: kqueue", __func__);
12293cedbec3SEnji Cooper 		cleanfifo2("testfifo", reader_fd, writer_fd);
12303cedbec3SEnji Cooper 		exit(-1);
12313cedbec3SEnji Cooper 	}
12323cedbec3SEnji Cooper 
12333cedbec3SEnji Cooper 	if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) {
12343cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12353cedbec3SEnji Cooper 		exit(-1);
12363cedbec3SEnji Cooper 	}
12373cedbec3SEnji Cooper 
12383cedbec3SEnji Cooper 	if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) {
12393cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12403cedbec3SEnji Cooper 		exit(-1);
12413cedbec3SEnji Cooper 	}
12423cedbec3SEnji Cooper 
12433cedbec3SEnji Cooper 	if (set_nonblocking(writer_fd, "test_events") < 0) {
12443cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12453cedbec3SEnji Cooper 		exit(-1);
12463cedbec3SEnji Cooper 	}
12473cedbec3SEnji Cooper 
12483cedbec3SEnji Cooper 	buffer = malloc(512*1024);
12493cedbec3SEnji Cooper 	if (buffer == NULL) {
12503cedbec3SEnji Cooper 		warn("test_events_partial_write: malloc");
12513cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12523cedbec3SEnji Cooper 		exit(-1);
12533cedbec3SEnji Cooper 	}
12543cedbec3SEnji Cooper 	bzero(buffer, 512*1024);
12553cedbec3SEnji Cooper 
12563cedbec3SEnji Cooper 	len = write(writer_fd, buffer, 512*1024);
12573cedbec3SEnji Cooper 	if (len < 0) {
12583cedbec3SEnji Cooper 		warn("test_events_partial_write: write");
12593cedbec3SEnji Cooper 		free(buffer);
12603cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12613cedbec3SEnji Cooper 		exit(-1);
12623cedbec3SEnji Cooper 	}
12633cedbec3SEnji Cooper 
12643cedbec3SEnji Cooper 	free(buffer);
12653cedbec3SEnji Cooper 
12663cedbec3SEnji Cooper 	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE,
12673cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "big write", "writer_fd") < 0) {
12683cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12693cedbec3SEnji Cooper 		exit(-1);
12703cedbec3SEnji Cooper 	}
12713cedbec3SEnji Cooper 
12723cedbec3SEnji Cooper 	if (drain_fd(reader_fd, "test_events") < 0) {
12733cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12743cedbec3SEnji Cooper 		exit(-1);
12753cedbec3SEnji Cooper 	}
12763cedbec3SEnji Cooper 
12773cedbec3SEnji Cooper 	/*
12783cedbec3SEnji Cooper 	 * Test that the writer_fd has been restored to writable state after
12793cedbec3SEnji Cooper 	 * draining.
12803cedbec3SEnji Cooper 	 */
12813cedbec3SEnji Cooper 	if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE,
12823cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "big write + drain", "writer_fd") < 0) {
12833cedbec3SEnji Cooper 		cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12843cedbec3SEnji Cooper 		exit(-1);
12853cedbec3SEnji Cooper 	}
12863cedbec3SEnji Cooper 
12873cedbec3SEnji Cooper 	cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd);
12883cedbec3SEnji Cooper }
12893cedbec3SEnji Cooper 
12903cedbec3SEnji Cooper /*
12913cedbec3SEnji Cooper  * We don't comprehensively test O_RDWR file descriptors, but do run a couple
12923cedbec3SEnji Cooper  * of event tests to make sure that the fifo implementation doesn't mixed up
12933cedbec3SEnji Cooper  * status checks.  In particular, at least one past FreeBSD bug exists in
12943cedbec3SEnji Cooper  * which the FIONREAD test was performed on the wrong socket implementing the
12953cedbec3SEnji Cooper  * fifo, resulting in the fifo never returning readable.
12963cedbec3SEnji Cooper  */
12973cedbec3SEnji Cooper static void
test_events_rdwr(void)12983cedbec3SEnji Cooper test_events_rdwr(void)
12993cedbec3SEnji Cooper {
13003cedbec3SEnji Cooper 	int fd, kqueue_fd;
13013cedbec3SEnji Cooper 	ssize_t len;
13023cedbec3SEnji Cooper 	char ch;
13033cedbec3SEnji Cooper 
13043cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
13053cedbec3SEnji Cooper 	if (openfifo_rw("testfifo", &fd) < 0) {
13063cedbec3SEnji Cooper 		warn("%s: openfifo_rw: testfifo", __func__);
13073cedbec3SEnji Cooper 		cleanfifo2("testfifo", -1, -1);
13083cedbec3SEnji Cooper 		exit(-1);
13093cedbec3SEnji Cooper 	}
13103cedbec3SEnji Cooper 
13113cedbec3SEnji Cooper 	kqueue_fd = kqueue();
13123cedbec3SEnji Cooper 	if (kqueue_fd < 0) {
13133cedbec3SEnji Cooper 		warn("%s: kqueue", __func__);
13143cedbec3SEnji Cooper 		cleanfifo2("testifo", fd, -1);
13153cedbec3SEnji Cooper 		exit(-1);
13163cedbec3SEnji Cooper 	}
13173cedbec3SEnji Cooper 
13183cedbec3SEnji Cooper 	if (kqueue_setup(kqueue_fd, fd, __func__) < 0) {
13193cedbec3SEnji Cooper 		cleanfifo2("testfifo", fd, kqueue_fd);
13203cedbec3SEnji Cooper 		exit(-1);
13213cedbec3SEnji Cooper 	}
13223cedbec3SEnji Cooper 
13233cedbec3SEnji Cooper 	/*
13243cedbec3SEnji Cooper 	 * On first creation, the O_RDWR descriptor should be writable but
13253cedbec3SEnji Cooper 	 * not readable.
13263cedbec3SEnji Cooper 	 */
13273cedbec3SEnji Cooper 	if (assert_status(fd, kqueue_fd, NOT_READABLE, WRITABLE,
13283cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "create", "fd") < 0) {
13293cedbec3SEnji Cooper 		cleanfifo2("testfifo", fd, kqueue_fd);
13303cedbec3SEnji Cooper 		exit(-1);
13313cedbec3SEnji Cooper 	}
13323cedbec3SEnji Cooper 
13333cedbec3SEnji Cooper 	/*
13343cedbec3SEnji Cooper 	 * Write a byte, which should cause the file descriptor to become
13353cedbec3SEnji Cooper 	 * readable and writable.
13363cedbec3SEnji Cooper 	 */
13373cedbec3SEnji Cooper 	ch = 0x00;
13383cedbec3SEnji Cooper 	len = write(fd, &ch, sizeof(ch));
13393cedbec3SEnji Cooper 	if (len < 0) {
13403cedbec3SEnji Cooper 		warn("%s: write", __func__);
13413cedbec3SEnji Cooper 		cleanfifo2("testfifo", fd, kqueue_fd);
13423cedbec3SEnji Cooper 		exit(-1);
13433cedbec3SEnji Cooper 	}
13443cedbec3SEnji Cooper 
13453cedbec3SEnji Cooper 	if (assert_status(fd, kqueue_fd, READABLE, WRITABLE, NOT_EXCEPTION,
13463cedbec3SEnji Cooper 	    __func__, "write", "fd") < 0) {
13473cedbec3SEnji Cooper 		cleanfifo2("testfifo", fd, kqueue_fd);
13483cedbec3SEnji Cooper 		exit(-1);
13493cedbec3SEnji Cooper 	}
13503cedbec3SEnji Cooper 
13513cedbec3SEnji Cooper 	/*
13523cedbec3SEnji Cooper 	 * Read a byte, which should cause the file descriptor to return to
13533cedbec3SEnji Cooper 	 * simply being writable.
13543cedbec3SEnji Cooper 	 */
13553cedbec3SEnji Cooper 	len = read(fd, &ch, sizeof(ch));
13563cedbec3SEnji Cooper 	if (len < 0) {
13573cedbec3SEnji Cooper 		warn("%s: read", __func__);
13583cedbec3SEnji Cooper 		cleanfifo2("testfifo", fd, kqueue_fd);
13593cedbec3SEnji Cooper 		exit(-1);
13603cedbec3SEnji Cooper 	}
13613cedbec3SEnji Cooper 
13623cedbec3SEnji Cooper 	if (assert_status(fd, kqueue_fd, NOT_READABLE, WRITABLE,
13633cedbec3SEnji Cooper 	    NOT_EXCEPTION, __func__, "write+read", "fd") < 0) {
13643cedbec3SEnji Cooper 		cleanfifo2("testfifo", fd, kqueue_fd);
13653cedbec3SEnji Cooper 		exit(-1);
13663cedbec3SEnji Cooper 	}
13673cedbec3SEnji Cooper 
13683cedbec3SEnji Cooper 	cleanfifo2("testfifo", fd, kqueue_fd);
13693cedbec3SEnji Cooper }
13703cedbec3SEnji Cooper 
13713cedbec3SEnji Cooper int
main(void)13723cedbec3SEnji Cooper main(void)
13733cedbec3SEnji Cooper {
13743cedbec3SEnji Cooper 
13753cedbec3SEnji Cooper 	strcpy(temp_dir, "fifo_io.XXXXXXXXXXX");
13763cedbec3SEnji Cooper 	if (mkdtemp(temp_dir) == NULL)
13773cedbec3SEnji Cooper 		err(-1, "mkdtemp");
13783cedbec3SEnji Cooper 	atexit(atexit_temp_dir);
13793cedbec3SEnji Cooper 
13803cedbec3SEnji Cooper 	if (chdir(temp_dir) < 0)
13813cedbec3SEnji Cooper 		err(-1, "chdir %s", temp_dir);
13823cedbec3SEnji Cooper 
13833cedbec3SEnji Cooper 	test_simpleio();
13843cedbec3SEnji Cooper 	test_blocking_read_empty();
13853cedbec3SEnji Cooper 	test_blocking_one_byte();
13863cedbec3SEnji Cooper 	test_nonblocking_one_byte();
13873cedbec3SEnji Cooper 	test_blocking_partial_write();
13883cedbec3SEnji Cooper 	test_nonblocking_partial_write();
13893cedbec3SEnji Cooper 	test_coalesce_big_read();
13903cedbec3SEnji Cooper 	test_coalesce_big_write();
13913cedbec3SEnji Cooper 	test_events_outofbox();
13923cedbec3SEnji Cooper 	test_events_write_read_byte();
13933cedbec3SEnji Cooper 	test_events_partial_write();
13943cedbec3SEnji Cooper 	test_events_rdwr();
13953cedbec3SEnji Cooper 
13963cedbec3SEnji Cooper 	return (0);
13973cedbec3SEnji Cooper }
1398