Subject: Another NEW_PIPE bug
To: None <tech-kern@netbsd.org>
From: Charles M. Hannum <abuse@spamalicious.com>
List: tech-kern
Date: 10/08/2001 05:14:47
I'm seeing a condition where NEW_PIPE causes a select/write loop.
Specifically, when I do:

cd /usr/pkgsrc/mk
cvs log bsd.pkg.mk|less
/275

I see the `ssh' process start using 100% of the CPU, spinning between
select(2) and write(2).

The problem is that the write and poll conditions are incompatible.
Using a slightly tweaked fstat(1), I see:

mycroft  ssh          782    7* pipe 0x124f3b8 -> 0x124f220 wn 800 0 0/0
mycroft  cvs          780    5* pipe 0x124f220 <- 0x124f3b8 r 800 0 18829/65536

This means the write side is non-blocking, and the pipe currently has
18829 out of 65536 bytes in use.  Note: this means the pipe was grown
to BIG_PIPE_SIZE.

The poll condition:

        if (events & (POLLOUT | POLLWRNORM))
                if (wpipe == NULL || (wpipe->pipe_state & PIPE_EOF)
                    || (
#ifndef PIPE_NODIRECT 
                     ((wpipe->pipe_state & PIPE_DIRECTW) == 0) &&
#endif  
                     (wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_
BUF))
                        revents |= events & (POLLOUT | POLLWRNORM);

returns true in this case, because there are in fact more than
PIPE_BUF bytes available.  However, in pipe_write() we have:

                if (space > 0 && (wpipe->pipe_buffer.cnt < PIPE_SIZE)) {

which returns false, because there are more than PIPE_SIZE bytes
already in the buffer.

This seems Just Plain Wrong to me.  Unless we're going to add logic to
shorten the buffer again, this condition should be:

                if (space > 0 && (wpipe->pipe_buffer.cnt < wpipe->pipe_buffer.size)) {

or the logically equivalent:

		if (space > 0) {

instead.

So, what's the deal here?