big_pipe_test.c revision 291183
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: stable/10/tests/sys/kern/pipe/big_pipe_test.c 290914 2015-11-16 05:38:40Z ngie $ 17 */ 18 19static void 20write_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 46int 47main(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