When a thread is blocked in direct write state, it only sets PIPE_DIRECTW

flag but not PIPE_WANTW, but FIFO pipe code does not understand this internal
state, when a FIFO peer reader closes the pipe, it wants to notify the writer,
it checks PIPE_WANTW, if not set, it skips calling wakeup(), so blocked writer
never noticed the case, but in general, the writer should return from the
syscall with EPIPE error code and may get SIGPIPE signal. Setting the
PIPE_WANTW fixed problem, or you can turn off direct write, it should fix the
problem too. This bug is found by PR/170203.

Another bug in FIFO pipe code is when peer closes the pipe, another end which
is being blocked in select() or poll() is not notified, it missed to call
pipeselwakeup().

Third problem is found in poll regression test, the existing code can not
pass 6b,6c,6d tests, but FreeBSD-4 works. This commit does not fix the
problem, I still need to study more to find the cause.

PR: 170203
Tested by: Garrett Copper < yanegomi at gmail dot com >
This commit is contained in:
David Xu 2012-07-31 02:00:37 +00:00
parent e9832bb1da
commit 12a480fa41
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=238928
3 changed files with 12 additions and 6 deletions

View File

@ -283,8 +283,11 @@ fifo_close(ap)
if (fip->fi_readers == 0) {
PIPE_LOCK(cpipe);
cpipe->pipe_state |= PIPE_EOF;
if (cpipe->pipe_state & PIPE_WANTW)
if ((cpipe->pipe_state & PIPE_WANTW)) {
cpipe->pipe_state &= ~PIPE_WANTW;
wakeup(cpipe);
}
pipeselwakeup(cpipe);
PIPE_UNLOCK(cpipe);
}
}
@ -293,10 +296,13 @@ fifo_close(ap)
if (fip->fi_writers == 0) {
PIPE_LOCK(cpipe);
cpipe->pipe_state |= PIPE_EOF;
if (cpipe->pipe_state & PIPE_WANTR)
if ((cpipe->pipe_state & PIPE_WANTR)) {
cpipe->pipe_state &= ~PIPE_WANTR;
wakeup(cpipe);
}
fip->fi_wgen++;
FIFO_UPDWGEN(fip, cpipe);
pipeselwakeup(cpipe);
PIPE_UNLOCK(cpipe);
}
}

View File

@ -227,7 +227,6 @@ static int pipe_create(struct pipe *pipe, int backing);
static int pipe_paircreate(struct thread *td, struct pipepair **p_pp);
static __inline int pipelock(struct pipe *cpipe, int catch);
static __inline void pipeunlock(struct pipe *cpipe);
static __inline void pipeselwakeup(struct pipe *cpipe);
#ifndef PIPE_NODIRECT
static int pipe_build_write_buffer(struct pipe *wpipe, struct uio *uio);
static void pipe_destroy_write_buffer(struct pipe *wpipe);
@ -607,7 +606,7 @@ pipeunlock(cpipe)
}
}
static __inline void
void
pipeselwakeup(cpipe)
struct pipe *cpipe;
{
@ -738,7 +737,7 @@ pipe_read(fp, uio, active_cred, flags, td)
rpipe->pipe_map.pos += size;
rpipe->pipe_map.cnt -= size;
if (rpipe->pipe_map.cnt == 0) {
rpipe->pipe_state &= ~PIPE_DIRECTW;
rpipe->pipe_state &= ~(PIPE_DIRECTW|PIPE_WANTW);
wakeup(rpipe);
}
#endif
@ -1001,6 +1000,7 @@ pipe_direct_write(wpipe, uio)
wakeup(wpipe);
}
pipeselwakeup(wpipe);
wpipe->pipe_state |= PIPE_WANTW;
pipeunlock(wpipe);
error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH,
"pipdwt", 0);

View File

@ -143,5 +143,5 @@ struct pipepair {
void pipe_dtor(struct pipe *dpipe);
int pipe_named_ctor(struct pipe **ppipe, struct thread *td);
void pipeselwakeup(struct pipe *cpipe);
#endif /* !_SYS_PIPE_H_ */