summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/sys_pipe.c33
-rw-r--r--sys/sys/pipe.h7
2 files changed, 29 insertions, 11 deletions
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index b58d3c64fa2d..22468e22622b 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -263,8 +263,8 @@ pipe_zone_ctor(void *mem, int size, void *arg, int flags)
* one at a time. When both are free'd, then the whole pair
* is released.
*/
- rpipe->pipe_present = 1;
- wpipe->pipe_present = 1;
+ rpipe->pipe_present = PIPE_ACTIVE;
+ wpipe->pipe_present = PIPE_ACTIVE;
/*
* Eventually, the MAC Framework may initialize the label
@@ -982,7 +982,8 @@ pipe_write(fp, uio, active_cred, flags, td)
/*
* detect loss of pipe read side, issue SIGPIPE if lost.
*/
- if ((!wpipe->pipe_present) || (wpipe->pipe_state & PIPE_EOF)) {
+ if (wpipe->pipe_present != PIPE_ACTIVE ||
+ (wpipe->pipe_state & PIPE_EOF)) {
pipeunlock(wpipe);
PIPE_UNLOCK(rpipe);
return (EPIPE);
@@ -1341,13 +1342,14 @@ pipe_poll(fp, events, active_cred, td)
revents |= events & (POLLIN | POLLRDNORM);
if (events & (POLLOUT | POLLWRNORM))
- if (!wpipe->pipe_present || (wpipe->pipe_state & PIPE_EOF) ||
+ if (wpipe->pipe_present != PIPE_ACTIVE ||
+ (wpipe->pipe_state & PIPE_EOF) ||
(((wpipe->pipe_state & PIPE_DIRECTW) == 0) &&
(wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF))
revents |= events & (POLLOUT | POLLWRNORM);
if ((rpipe->pipe_state & PIPE_EOF) ||
- (!wpipe->pipe_present) ||
+ wpipe->pipe_present != PIPE_ACTIVE ||
(wpipe->pipe_state & PIPE_EOF))
revents |= POLLHUP;
@@ -1486,7 +1488,7 @@ pipeclose(cpipe)
* Disconnect from peer, if any.
*/
ppipe = cpipe->pipe_peer;
- if (ppipe->pipe_present != 0) {
+ if (ppipe->pipe_present == PIPE_ACTIVE) {
pipeselwakeup(ppipe);
ppipe->pipe_state |= PIPE_EOF;
@@ -1503,16 +1505,23 @@ pipeclose(cpipe)
PIPE_UNLOCK(cpipe);
pipe_free_kmem(cpipe);
PIPE_LOCK(cpipe);
- cpipe->pipe_present = 0;
+ cpipe->pipe_present = PIPE_CLOSING;
pipeunlock(cpipe);
+
+ /*
+ * knlist_clear() may sleep dropping the PIPE_MTX. Set the
+ * PIPE_FINALIZED, that allows other end to free the
+ * pipe_pair, only after the knotes are completely dismantled.
+ */
knlist_clear(&cpipe->pipe_sel.si_note, 1);
+ cpipe->pipe_present = PIPE_FINALIZED;
knlist_destroy(&cpipe->pipe_sel.si_note);
/*
* If both endpoints are now closed, release the memory for the
* pipe pair. If not, unlock.
*/
- if (ppipe->pipe_present == 0) {
+ if (ppipe->pipe_present == PIPE_FINALIZED) {
PIPE_UNLOCK(cpipe);
#ifdef MAC
mac_destroy_pipe(pp);
@@ -1536,7 +1545,7 @@ pipe_kqfilter(struct file *fp, struct knote *kn)
break;
case EVFILT_WRITE:
kn->kn_fop = &pipe_wfiltops;
- if (!cpipe->pipe_peer->pipe_present) {
+ if (cpipe->pipe_peer->pipe_present != PIPE_ACTIVE) {
/* other end of pipe has been closed */
PIPE_UNLOCK(cpipe);
return (EPIPE);
@@ -1579,7 +1588,8 @@ filt_piperead(struct knote *kn, long hint)
kn->kn_data = rpipe->pipe_map.cnt;
if ((rpipe->pipe_state & PIPE_EOF) ||
- (!wpipe->pipe_present) || (wpipe->pipe_state & PIPE_EOF)) {
+ wpipe->pipe_present != PIPE_ACTIVE ||
+ (wpipe->pipe_state & PIPE_EOF)) {
kn->kn_flags |= EV_EOF;
PIPE_UNLOCK(rpipe);
return (1);
@@ -1597,7 +1607,8 @@ filt_pipewrite(struct knote *kn, long hint)
struct pipe *wpipe = rpipe->pipe_peer;
PIPE_LOCK(rpipe);
- if ((!wpipe->pipe_present) || (wpipe->pipe_state & PIPE_EOF)) {
+ if (wpipe->pipe_present != PIPE_ACTIVE ||
+ (wpipe->pipe_state & PIPE_EOF)) {
kn->kn_data = 0;
kn->kn_flags |= EV_EOF;
PIPE_UNLOCK(rpipe);
diff --git a/sys/sys/pipe.h b/sys/sys/pipe.h
index 1d3729fc38c9..2371b2a4e96f 100644
--- a/sys/sys/pipe.h
+++ b/sys/sys/pipe.h
@@ -115,6 +115,13 @@ struct pipe {
};
/*
+ * Values for the pipe_present.
+ */
+#define PIPE_ACTIVE 1
+#define PIPE_CLOSING 2
+#define PIPE_FINALIZED 3
+
+/*
* Container structure to hold the two pipe endpoints, mutex, and label
* pointer.
*/