From 029b91ee4a71acb8fc1e54fe1ef0711437738fe6 Mon Sep 17 00:00:00 2001 From: visa Date: Tue, 7 Dec 2021 14:06:16 +0000 Subject: [PATCH] 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@ --- sys/kern/sys_pipe.c | 79 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) 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) { -- 2.20.1