summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_event.c')
-rw-r--r--sys/kern/kern_event.c39
1 files changed, 35 insertions, 4 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 828b2ffa06c..b84a674e38b 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_event.c,v 1.120 2020/01/13 13:57:19 visa Exp $ */
+/* $OpenBSD: kern_event.c,v 1.121 2020/01/18 08:59:48 visa Exp $ */
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -465,6 +465,27 @@ seltrue_kqfilter(dev_t dev, struct knote *kn)
return (0);
}
+static int
+filt_dead(struct knote *kn, long hint)
+{
+ kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+ kn->kn_data = 0;
+ return (1);
+}
+
+static void
+filt_deaddetach(struct knote *kn)
+{
+ /* Nothing to do */
+}
+
+static const struct filterops dead_filtops = {
+ .f_isfd = 1,
+ .f_attach = NULL,
+ .f_detach = filt_deaddetach,
+ .f_event = filt_dead,
+};
+
int
sys_kqueue(struct proc *p, void *v, register_t *retval)
{
@@ -1315,8 +1336,18 @@ klist_invalidate(struct klist *list)
{
struct knote *kn;
- SLIST_FOREACH(kn, list, kn_selnext) {
- kn->kn_status |= KN_DETACHED;
- kn->kn_flags |= EV_EOF | EV_ONESHOT;
+ /*
+ * NET_LOCK() must not be held because it can block another thread
+ * in f_event with a knote acquired.
+ */
+ NET_ASSERT_UNLOCKED();
+
+ while ((kn = SLIST_FIRST(list)) != NULL) {
+ if (knote_acquire(kn) == 0)
+ continue;
+ kn->kn_fop->f_detach(kn);
+ kn->kn_fop = &dead_filtops;
+ knote_activate(kn);
+ knote_release(kn);
}
}