xref: /freebsd/tests/sys/kern/pipe/big_pipe_test.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
1 #include <sys/select.h>
2 #include <err.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 
10 #define BIG_PIPE_SIZE  64*1024 /* From sys/pipe.h */
11 
12 /*
13  * Test for the non-blocking big pipe bug (write(2) returning
14  * EAGAIN while select(2) returns the descriptor as ready for write).
15  *
16  * $FreeBSD$
17  */
18 
19 static void
20 write_frame(int fd, char *buf, unsigned long buflen)
21 {
22 	fd_set wfd;
23 	int i;
24 
25 	while (buflen) {
26 		FD_ZERO(&wfd);
27 		FD_SET(fd, &wfd);
28 		i = select(fd+1, NULL, &wfd, NULL, NULL);
29 		if (i < 0)
30 			err(1, "select failed");
31 		if (i != 1) {
32 			errx(1, "select returned unexpected value %d\n", i);
33 			exit(1);
34 		}
35 		i = write(fd, buf, buflen);
36 		if (i < 0) {
37 			if (errno != EAGAIN)
38 				warn("write failed");
39 			exit(1);
40 		}
41 		buf += i;
42 		buflen -= i;
43 	}
44 }
45 
46 int
47 main(void)
48 {
49 	/* any value over PIPE_SIZE should do */
50 	char buf[BIG_PIPE_SIZE];
51 	int i, flags, fd[2];
52 
53 	if (pipe(fd) < 0)
54 		errx(1, "pipe failed");
55 
56 	flags = fcntl(fd[1], F_GETFL);
57 	if (flags == -1 || fcntl(fd[1], F_SETFL, flags|O_NONBLOCK) == -1) {
58 		printf("fcntl failed: %s\n", strerror(errno));
59 		exit(1);
60 	}
61 
62 	switch (fork()) {
63 	case -1:
64 		err(1, "fork failed: %s\n", strerror(errno));
65 		break;
66 	case 0:
67 		close(fd[1]);
68 		for (;;) {
69 			/* Any small size should do */
70 			i = read(fd[0], buf, 256);
71 			if (i == 0)
72 				break;
73 			if (i < 0)
74 				err(1, "read");
75 		}
76 		exit(0);
77 	default:
78 		break;
79 	}
80 
81 	close(fd[0]);
82 	memset(buf, 0, sizeof buf);
83 	for (i = 0; i < 1000; i++)
84 		write_frame(fd[1], buf, sizeof buf);
85 
86 	printf("ok\n");
87 	exit(0);
88 }
89