/* * buffer: try to stream data * * usage: * <generator> | buffer -i<blksize> -o<blksize> > output * buffer -i<blksize> -o<blksize> < input | <user * * * How it works: Buffer preforks 4-6 children which spend their * existance waiting on a flock(); when they get the lock, they * fill their buffer, release their lock. write out the data * they read, then wait on the lock again. */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <sys/file.h> #include <sys/signal.h> #include <errno.h> int ibs = 512, obs = 512; void consumer(int childno) { static char buffer[20480]; /* tape blocksize of 40 */ int status, size, chunk; char *ptr; while (1) { if (flock(0, LOCK_EX) == -1) /* grab control of our input */ if (errno = EINTR) continue; else { kill(getppid(), SIGHUP); exit(0); } chunk = sizeof buffer; ptr = buffer; while (chunk > 0) { if ((size = read(0, ptr, chunk)) > 0) { chunk -= size; ptr += size; } else break; } while (flock(1, LOCK_EX) == -1) if (errno != EINTR) { kill(getppid(), SIGHUP); exit(0); } flock(0, LOCK_UN); /* release input to the next thread */ if (ptr > buffer) write(1, buffer, ptr-buffer); flock(1, LOCK_UN); if (ptr == buffer) { exit(0); } } } main() { int x; #define NRCHILD 16 pid_t children[NRCHILD]; pid_t child; int nrchild; for (x=0; x < NRCHILD; x++) { child = fork(); if (child == 0) { consumer(x); exit(0); } else if (child > 0) { children[x] = child; nrchild++; } else { children[x] = 0; } } if (nrchild == 0) { perror("forking consumers"); exit(1); } while (nrchild > 0) if ((child = wait(&x)) > 0) { for (x = 0; x < NRCHILD; x++) if (children[x] == child) { children[x] = 0; nrchild--; } } exit(0); }