/* measure size of a pipe buffer */ #include #include #include #include #include #include void die(char* msg) { perror(msg); exit(1); } #define MAXSIZE 20 /* we probe buflens up to 2^(MAXSIZE-1) */ #define MAXPROCESSES 32 /* should be power of two and > MAXSIZE and <= 256 */ /* empty the pipeline by reading up to expected bytes, return the actual number of bytes read */ static unsigned int suck_pipe(int fd, unsigned int expected) { char* buf = malloc(expected); if (!buf) die("malloc"); ssize_t bytes_read = 0; while (bytes_read < expected) { ssize_t nbytes = read(fd, buf, expected - bytes_read); if (nbytes < 0) die("read from pipe"); if (nbytes == 0) break; bytes_read += nbytes; } close(fd); free(buf); return bytes_read; } /* create a pipeline and fork off a process that writes nbytes into the writing end of this pipeline and exists i in case of success; returns the reading end of the pipeline */ static int pipe_and_fork(int i, size_t nbytes) { int fds[2]; if (pipe(fds) < 0) die("pipe"); pid_t pid = fork(); if (pid < 0) die("fork"); if (pid == 0) { close(fds[0]); char* buf = malloc(nbytes); alarm(5); ssize_t written = write(fds[1], buf, nbytes); if (written < nbytes) exit(255); exit(i); } close(fds[1]); return fds[0]; } /* run and evaluate a series of tests where 'tests' is the number of tests and nbytes[i] contains the number of bytes to be written by the i-th process */ static int run_tests(unsigned int nbytes[], unsigned int tests) { int pipes[tests]; for (int i = 0; i < tests; ++i) { pipes[i] = pipe_and_fork(i, nbytes[i]); } // wait for all the forked processes int success[tests]; for (int i = 0; i < tests; ++i) { success[i] = 0; } int wstat; pid_t pid; while ((pid = wait(&wstat)) > 0) { if (WIFEXITED(wstat)) { int status = WEXITSTATUS(wstat); if (status != 255 && status < MAXPROCESSES) { success[status] = 1; } } } // evaluate and confirm results unsigned int confirmed_len = 0; for (int i = 0; i < tests; ++i) { if (success[i]) { confirmed_len = suck_pipe(pipes[i], nbytes[i]); continue; } break; } return confirmed_len; } // check for buf sizes that are powers of two unsigned int test1() { unsigned int nbytes[MAXSIZE]; for (int i = 0; i < MAXSIZE; ++i) { nbytes[i] = (1 << i); } return run_tests(nbytes, MAXSIZE); } // check for arbitrary buf sizes unsigned int test2(unsigned int buflen, unsigned int increment, unsigned int tests) { unsigned int nbytes[tests]; for (int i = 0; i < tests; ++i) { nbytes[i] = buflen + increment * i; } return run_tests(nbytes, tests); } int main() { // check for buf sizes that are powers of two unsigned int buflen = test1(); if (!buflen) { printf("pipe buffer size is beyond %d\n", 1 << (MAXSIZE-1)); exit(1); } // check for buf sizes that are not powers of two unsigned int increment = buflen / MAXPROCESSES; unsigned int lastlen = 0; unsigned int tests = MAXPROCESSES; while (increment > 0) { unsigned int len = test2(buflen, increment, tests); if (!len) { printf("pipe buffer len is possibly %d " "but that did not get confirmed\n", buflen); exit(1); } lastlen = len; buflen = len; if (increment > MAXPROCESSES) { tests = MAXPROCESSES; increment /= MAXPROCESSES; } else if (increment > 1) { tests = increment; increment = 1; } else { increment = 0; } } if (lastlen) { printf("pipe buffer size = %d\n", lastlen); } else { printf("pipe buffer size = %d\n", buflen); } }