summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2021-12-07 14:06:17 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2021-12-07 14:06:17 +0000
commit8effea2c45ccd7a7f261af64b2ea15a9cea65736 (patch)
tree8bfff04bd815a98a47c986518292e3c3aee0a819 /sys
parentd482c624e6ccfa8a176514bb0dc60544c1b64d8e (diff)
Add EVFILT_EXCEPT filter for pipes
The kqueue-based select(2) needs the filter to replicate the old exceptfds behaviour. The upcoming new poll(2) code will use the filter for POLLHUP condition checking when the events bitmap is clear of read/write events. OK anton@
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/sys_pipe.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 280b475e373..3ece79221b3 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_pipe.c,v 1.129 2021/10/24 06:59:54 visa Exp $ */
+/* $OpenBSD: sys_pipe.c,v 1.130 2021/12/07 14:06:16 visa Exp $ */
/*
* Copyright (c) 1996 John S. Dyson
@@ -85,6 +85,10 @@ int filt_pipewrite(struct knote *kn, long hint);
int filt_pipewritemodify(struct kevent *kev, struct knote *kn);
int filt_pipewriteprocess(struct knote *kn, struct kevent *kev);
int filt_pipewrite_common(struct knote *kn, struct pipe *rpipe);
+int filt_pipeexcept(struct knote *kn, long hint);
+int filt_pipeexceptmodify(struct kevent *kev, struct knote *kn);
+int filt_pipeexceptprocess(struct knote *kn, struct kevent *kev);
+int filt_pipeexcept_common(struct knote *kn, struct pipe *rpipe);
const struct filterops pipe_rfiltops = {
.f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
@@ -104,6 +108,15 @@ const struct filterops pipe_wfiltops = {
.f_process = filt_pipewriteprocess,
};
+const struct filterops pipe_efiltops = {
+ .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
+ .f_attach = NULL,
+ .f_detach = filt_pipedetach,
+ .f_event = filt_pipeexcept,
+ .f_modify = filt_pipeexceptmodify,
+ .f_process = filt_pipeexceptprocess,
+};
+
/*
* Default pipe buffer size(s), this can be kind-of large now because pipe
* space is pageable. The pipe code will try to maintain locality of
@@ -908,6 +921,11 @@ pipe_kqfilter(struct file *fp, struct knote *kn)
kn->kn_hook = wpipe;
klist_insert_locked(&wpipe->pipe_sel.si_note, kn);
break;
+ case EVFILT_EXCEPT:
+ kn->kn_fop = &pipe_efiltops;
+ kn->kn_hook = rpipe;
+ klist_insert_locked(&rpipe->pipe_sel.si_note, kn);
+ break;
default:
error = EINVAL;
}
@@ -1047,6 +1065,65 @@ filt_pipewriteprocess(struct knote *kn, struct kevent *kev)
return (active);
}
+int
+filt_pipeexcept_common(struct knote *kn, struct pipe *rpipe)
+{
+ struct pipe *wpipe;
+
+ rw_assert_wrlock(rpipe->pipe_lock);
+
+ wpipe = pipe_peer(rpipe);
+
+ if ((rpipe->pipe_state & PIPE_EOF) || wpipe == NULL) {
+ kn->kn_flags |= EV_EOF;
+ if (kn->kn_flags & __EV_POLL)
+ kn->kn_flags |= __EV_HUP;
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+filt_pipeexcept(struct knote *kn, long hint)
+{
+ struct pipe *rpipe = kn->kn_fp->f_data;
+
+ return (filt_pipeexcept_common(kn, rpipe));
+}
+
+int
+filt_pipeexceptmodify(struct kevent *kev, struct knote *kn)
+{
+ struct pipe *rpipe = kn->kn_fp->f_data;
+ int active;
+
+ rw_enter_write(rpipe->pipe_lock);
+ knote_modify(kev, kn);
+ active = filt_pipeexcept_common(kn, rpipe);
+ rw_exit_write(rpipe->pipe_lock);
+
+ return (active);
+}
+
+int
+filt_pipeexceptprocess(struct knote *kn, struct kevent *kev)
+{
+ struct pipe *rpipe = kn->kn_fp->f_data;
+ int active;
+
+ rw_enter_write(rpipe->pipe_lock);
+ if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
+ active = 1;
+ else
+ active = filt_pipeexcept_common(kn, rpipe);
+ if (active)
+ knote_submit(kn, kev);
+ rw_exit_write(rpipe->pipe_lock);
+
+ return (active);
+}
+
void
pipe_init(void)
{