#include #include #include #include #include #include #include #include #include void die(const char *msg) {fprintf(stderr, "%s: %s\n",msg,strerror(errno)); exit(1);} void timer_expired(int sig) {} int main(void) { int fd1, fd2, i, err; char data[2048]; pid_t pid; /* Create a fifo. Open one reader and two writers. Make one writer non-blocking. */ if (mkfifo("testpipe", 0666)) if (errno!=EEXIST) die("mknod"); if ((fd1=open("testpipe", O_RDWR))==-1) die("open"); if ((fd2=open("testpipe", O_RDWR))==-1) die("open"); if (unlink("testpipe")) die("unlink"); if (fcntl(fd1, F_SETFL, O_NONBLOCK)==-1) die("fcntl"); /* Fill the tty buffer until full */ memset(data, 0, 2048); for (i=0; i<10; i++) { if (write(fd1, data, 2048)==-1) { if (errno==EINTR) continue; if (errno==EAGAIN) break; die("write"); } } /* Fork, and do a blocking write in the child */ if ((pid=fork())==-1) die("fork"); if (!pid) { if (write(fd2, data, 2048)==-1) die("write"); _exit(0); } sleep(1); alarm(0); signal(SIGALRM, timer_expired); alarm(1); errno=0; /* In the parent, do a non-blocking write while the atomic_write semaphore is held. */ if (write(fd1, data, 2048)==-1) { if (errno!=EINTR && errno!=EAGAIN) die("write"); } err=errno; if (kill(pid, SIGTERM)) die("kill"); switch(errno) { case EAGAIN: printf("pipe write failed with EAGAIN. Good.\n"); return 0; case 0: printf("pipe write completed sucessfully. " "Bug test failed - run program again.\n"); return 1; case EINTR: printf("pipe write failed with EINTR.\n" "write blocked despite file descriptor being " "non-blocking!\n"); return 2; } return 1; /* NOTREACHED */ }