Date: Thu, 1 Feb 1996 13:56:26 +1100 From: Bruce Evans <bde@zeta.org.au> To: current@freebsd.org, dyson@freebsd.org Subject: new pipes fail several tests #4 Message-ID: <199602010256.NAA06197@godzilla.zeta.org.au>
next in thread | raw e-mail | index | archive | help
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 <limits.h>, 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 <sys/types.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#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;
}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199602010256.NAA06197>
