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?