From owner-freebsd-current Wed Jan 31 18:59:53 1996 Return-Path: owner-current Received: (from root@localhost) by freefall.freebsd.org (8.7.3/8.7.3) id SAA13231 for current-outgoing; Wed, 31 Jan 1996 18:59:53 -0800 (PST) Received: from godzilla.zeta.org.au (godzilla.zeta.org.au [203.2.228.19]) by freefall.freebsd.org (8.7.3/8.7.3) with SMTP id SAA12944 Wed, 31 Jan 1996 18:57:39 -0800 (PST) Received: (from bde@localhost) by godzilla.zeta.org.au (8.6.9/8.6.9) id NAA06197; Thu, 1 Feb 1996 13:56:26 +1100 Date: Thu, 1 Feb 1996 13:56:26 +1100 From: Bruce Evans Message-Id: <199602010256.NAA06197@godzilla.zeta.org.au> To: current@freebsd.org, dyson@freebsd.org Subject: new pipes fail several tests #4 Sender: owner-current@freebsd.org Precedence: bulk The fix for #3 seems to work. Thanks. New pipes don't honor the O_NONBLOCK flag or _POSIX_PIPE_MAX or PIPE_MAX. sys_pipe.c doesn't even reference these values. This test demonstrates that non-blocking writes block and that atomic writes may be non-atomic. PIPESIZE can be determined in a machine-independent way by nonblock-writing a byte at a time until the pipe fills up, but this can't be used here because the writes would block. PIPE_MAX can be checked automatically iff nonblocking writes work. Old pipes have several bugs involving PIPE_MAX: 1. PIPE_MAX is defined in , so if you fix it or change it, all binaries that depend on it must be recompiled. 2. PIPE_MAX is identical with _POSIX_PIPE_MAX (512). It is actually kinda sorta identical with MCLBYTES (2048). 3. MCLBYTES > _POSIX_PIPE_MAX is not enforced. 3. The corresponding socket semantics are a little different. Nonblocking that don't fit work correctly when <= MCLBYTES is written (-1/EAGAIN is returned) buy sometimes fail when > MCLBYTES is written (-1/EAGAIN is sometimes returned instead of writing what fits). PIPE_MAX should be a significant fraction of PIPESIZE in the new implementation. I think Linux uses 4095 for PIPE_MAX and 4096 for PIPESIZE. The non-power of 2 is probably not so good - processes wanting to do atomic writes to pipes should write PIPE_MAX bytes at a time and this will cause extra blocking overhead. Bruce #include #include #include #include #include #include #include #include #include #define check(what, expected) assert((what, expected)) #define NONBLOCKING 0 /* option */ #define USE_NAMED_PIPE_P 0 /* option */ #if USE_NAMED_PIPE_P #define PIPESIZE 8192 #else #define PIPESIZE 16384 #endif sig_atomic_t caught; static void catch(int s) { caught = 1; } int main(void) { char buf[_POSIX_PIPE_BUF]; int fd[2]; size_t nw; int r; long tot; #if USE_NAMED_PIPE_P fd[0] = open("p", O_RDONLY | O_NONBLOCK); check("open", fd[0] != -1); r = fcntl(fd[0], F_SETFL, O_RDONLY); check("fcntl", r == 0); fd[1] = open("p", O_WRONLY | O_NONBLOCK); check("open", fd[1] != -1); r = fcntl(fd[1], F_SETFL, O_WRONLY); check("fcntl", r == 0); #else r = pipe(fd); check("pipe", r == 0); #endif #if NONBLOCKING r = fcntl(fd[1], F_SETFL, O_NONBLOCK); check("fcntl", r == 0); #endif /* * Fill up the pipe except for a little less than _POSIX_PIPE_BUF * bytes so that the next write of _POSIX_PIPE_BUF bytes (only) * partly fits. */ for (tot = 0; tot + sizeof buf <= PIPESIZE;) { nw = (tot + sizeof buf == PIPESIZE) ? 1 : sizeof buf; r = write(fd[1], buf, nw); if (r != -1) tot += r; fprintf(stderr, "write returned %d, tot = %ld\n", r, tot); check("write", r == nw); } check("almost filled", tot < PIPESIZE && tot + sizeof buf > PIPESIZE); /* Trap failures. */ check("siginterrupt", siginterrupt(SIGALRM, 1) == 0); check("signal", signal(SIGALRM, catch) != SIG_ERR); alarm(2); /* * Now we should be able to write at least _POSIX_PIPE_BUF bytes * atomically (or PIPE_BUF bytes, or fpathconf(fd[1], _PC_PIPE_BUF) * bytes, but those are bogusly the same as _POSIX_PIPE_BUF under * FreeBSD). */ r = write(fd[1], buf, sizeof buf); alarm(0); fprintf(stderr, "wrote %d bytes, errno = %d, caught = %d\n", r, errno , caught); #if NONBLOCKING /* Should have returned immediately without writing anything. */ check("write", r == -1); check("write", errno == EAGAIN); check("write", caught == 0); #else /* Should have returned after the alarm without writing anything. */ check("write", r == -1); check("write", errno == EINTR); check("write", caught == 1); #endif return 0; }