xref: /freebsd/tests/sys/kern/pipe/big_pipe_test.c (revision 734e82fe33aa764367791a7d603b383996c6b40b)
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 
17 static void
18 write_frame(int fd, char *buf, unsigned long buflen)
19 {
20 	fd_set wfd;
21 	int i;
22 
23 	while (buflen) {
24 		FD_ZERO(&wfd);
25 		FD_SET(fd, &wfd);
26 		i = select(fd+1, NULL, &wfd, NULL, NULL);
27 		if (i < 0)
28 			err(1, "select failed");
29 		if (i != 1) {
30 			errx(1, "select returned unexpected value %d\n", i);
31 			exit(1);
32 		}
33 		i = write(fd, buf, buflen);
34 		if (i < 0) {
35 			if (errno != EAGAIN)
36 				warn("write failed");
37 			exit(1);
38 		}
39 		buf += i;
40 		buflen -= i;
41 	}
42 }
43 
44 int
45 main(void)
46 {
47 	/* any value over PIPE_SIZE should do */
48 	char buf[BIG_PIPE_SIZE];
49 	int i, flags, fd[2];
50 
51 	if (pipe(fd) < 0)
52 		errx(1, "pipe failed");
53 
54 	flags = fcntl(fd[1], F_GETFL);
55 	if (flags == -1 || fcntl(fd[1], F_SETFL, flags|O_NONBLOCK) == -1) {
56 		printf("fcntl failed: %s\n", strerror(errno));
57 		exit(1);
58 	}
59 
60 	switch (fork()) {
61 	case -1:
62 		err(1, "fork failed: %s\n", strerror(errno));
63 		break;
64 	case 0:
65 		close(fd[1]);
66 		for (;;) {
67 			/* Any small size should do */
68 			i = read(fd[0], buf, 256);
69 			if (i == 0)
70 				break;
71 			if (i < 0)
72 				err(1, "read");
73 		}
74 		exit(0);
75 	default:
76 		break;
77 	}
78 
79 	close(fd[0]);
80 	memset(buf, 0, sizeof buf);
81 	for (i = 0; i < 1000; i++)
82 		write_frame(fd[1], buf, sizeof buf);
83 
84 	printf("ok\n");
85 	exit(0);
86 }
87