Fix a deadlock w/kqueue that was introduced with the last set of changes.

Spotted by yamt@.
This commit is contained in:
ad 2007-03-23 18:33:43 +00:00
parent cc085574cb
commit bb25376cda
1 changed files with 30 additions and 23 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: sys_pipe.c,v 1.82 2007/03/12 21:31:12 ad Exp $ */
/* $NetBSD: sys_pipe.c,v 1.83 2007/03/23 18:33:43 ad Exp $ */
/*-
* Copyright (c) 2003, 2007 The NetBSD Foundation, Inc.
@ -83,7 +83,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.82 2007/03/12 21:31:12 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.83 2007/03/23 18:33:43 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -1098,7 +1098,7 @@ pipe_ioctl(struct file *fp, u_long cmd, void *data, struct lwp *l)
case FIONWRITE:
/* Look at other side */
rw_enter(&pipe_peer_lock, RW_WRITER);
rw_enter(&pipe_peer_lock, RW_READER);
pipe = pipe->pipe_peer;
mutex_enter(&pipe->pipe_lock);
#ifndef PIPE_NODIRECT
@ -1113,7 +1113,7 @@ pipe_ioctl(struct file *fp, u_long cmd, void *data, struct lwp *l)
case FIONSPACE:
/* Look at other side */
rw_enter(&pipe_peer_lock, RW_WRITER);
rw_enter(&pipe_peer_lock, RW_READER);
pipe = pipe->pipe_peer;
mutex_enter(&pipe->pipe_lock);
#ifndef PIPE_NODIRECT
@ -1206,7 +1206,7 @@ pipe_stat(struct file *fp, struct stat *ub, struct lwp *l)
{
struct pipe *pipe = (struct pipe *)fp->f_data;
rw_enter(&pipe_peer_lock, RW_WRITER);
rw_enter(&pipe_peer_lock, RW_READER);
memset((void *)ub, 0, sizeof(*ub));
ub->st_mode = S_IFIFO | S_IRUSR | S_IWUSR;
@ -1277,7 +1277,7 @@ pipeclose(struct file *fp, struct pipe *pipe)
return;
retry:
rw_enter(&pipe_peer_lock, RW_READER);
rw_enter(&pipe_peer_lock, RW_WRITER);
mutex_enter(&pipe->pipe_lock);
pipeselwakeup(pipe, pipe, POLL_HUP);
@ -1338,7 +1338,7 @@ filt_pipedetach(struct knote *kn)
{
struct pipe *pipe = (struct pipe *)kn->kn_fp->f_data;
rw_enter(&pipe_peer_lock, RW_WRITER);
rw_enter(&pipe_peer_lock, RW_READER);
switch(kn->kn_filter) {
case EVFILT_WRITE:
@ -1375,26 +1375,30 @@ filt_piperead(struct knote *kn, long hint)
struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
struct pipe *wpipe;
rw_enter(&pipe_peer_lock, RW_WRITER);
wpipe = rpipe->pipe_peer;
if ((hint & NOTE_SUBMIT) == 0)
if ((hint & NOTE_SUBMIT) == 0) {
rw_enter(&pipe_peer_lock, RW_READER);
mutex_enter(&rpipe->pipe_lock);
}
wpipe = rpipe->pipe_peer;
kn->kn_data = rpipe->pipe_buffer.cnt;
if ((kn->kn_data == 0) && (rpipe->pipe_state & PIPE_DIRECTW))
kn->kn_data = rpipe->pipe_map.cnt;
if ((rpipe->pipe_state & PIPE_EOF) ||
(wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
kn->kn_flags |= EV_EOF;
if ((hint & NOTE_SUBMIT) == 0)
if ((hint & NOTE_SUBMIT) == 0) {
mutex_exit(&rpipe->pipe_lock);
rw_exit(&pipe_peer_lock);
rw_exit(&pipe_peer_lock);
}
return (1);
}
if ((hint & NOTE_SUBMIT) == 0)
if ((hint & NOTE_SUBMIT) == 0) {
mutex_exit(&rpipe->pipe_lock);
rw_exit(&pipe_peer_lock);
rw_exit(&pipe_peer_lock);
}
return (kn->kn_data > 0);
}
@ -1405,26 +1409,29 @@ filt_pipewrite(struct knote *kn, long hint)
struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
struct pipe *wpipe;
rw_enter(&pipe_peer_lock, RW_WRITER);
if ((hint & NOTE_SUBMIT) == 0) {
rw_enter(&pipe_peer_lock, RW_READER);
mutex_enter(&rpipe->pipe_lock);
}
wpipe = rpipe->pipe_peer;
if ((hint & NOTE_SUBMIT) == 0)
mutex_enter(&rpipe->pipe_lock);
if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
kn->kn_data = 0;
kn->kn_flags |= EV_EOF;
if ((hint & NOTE_SUBMIT) == 0)
if ((hint & NOTE_SUBMIT) == 0) {
mutex_exit(&rpipe->pipe_lock);
rw_exit(&pipe_peer_lock);
rw_exit(&pipe_peer_lock);
}
return (1);
}
kn->kn_data = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt;
if (wpipe->pipe_state & PIPE_DIRECTW)
kn->kn_data = 0;
if ((hint & NOTE_SUBMIT) == 0)
if ((hint & NOTE_SUBMIT) == 0) {
mutex_exit(&rpipe->pipe_lock);
rw_exit(&pipe_peer_lock);
rw_exit(&pipe_peer_lock);
}
return (kn->kn_data >= PIPE_BUF);
}
@ -1439,7 +1446,7 @@ pipe_kqfilter(struct file *fp, struct knote *kn)
{
struct pipe *pipe;
rw_enter(&pipe_peer_lock, RW_WRITER);
rw_enter(&pipe_peer_lock, RW_READER);
pipe = (struct pipe *)kn->kn_fp->f_data;
switch (kn->kn_filter) {