diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2021-12-07 14:06:17 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2021-12-07 14:06:17 +0000 |
commit | 8effea2c45ccd7a7f261af64b2ea15a9cea65736 (patch) | |
tree | 8bfff04bd815a98a47c986518292e3c3aee0a819 /sys | |
parent | d482c624e6ccfa8a176514bb0dc60544c1b64d8e (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.c | 79 |
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) { |