aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2026-04-09 02:37:00 +0000
committerKyle Evans <kevans@FreeBSD.org>2026-04-09 02:37:11 +0000
commitc6dd40f2d35d596ca60a5d87616c3e4a0fd4f676 (patch)
tree9f649072a31e385150a464a0348075b2ff33c382
parent0c9cec8b66e7033f50059329704515d5222b9ff4 (diff)
kqueue: slightly clarify the flow in knlist_cleardel()
This is purely a cosmetic change to make it a little easier on the eyes, rather than jumping back to the else branch up top. Re-flow it to use another loop on the outside and just inline the re-lock before we repeat after awaking from fluxwait. The !killkn path should maybe issue a wakeup if there's a thread in KQ_SLEEP so that userland can observe the EOF, but this isn't a practical problem today: pretty much every case of knlist_clear is tied to a file descriptor and called in the close(2) path. As a consequence, potentially affected knotes are almost always destroyed before we even get to knlist_clear(). Reviewed by: kib, markj Differential Revision: https://reviews.freebsd.org/D56226
-rw-r--r--sys/kern/kern_event.c50
1 files changed, 29 insertions, 21 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 1deb7a705c56..01731ca46b6b 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -2792,31 +2792,39 @@ knlist_cleardel(struct knlist *knl, struct thread *td, int islocked, int killkn)
KNL_ASSERT_LOCKED(knl);
else {
KNL_ASSERT_UNLOCKED(knl);
-again: /* need to reacquire lock since we have dropped it */
knl->kl_lock(knl->kl_lockarg);
}
- SLIST_FOREACH_SAFE(kn, &knl->kl_list, kn_selnext, kn2) {
- kq = kn->kn_kq;
- KQ_LOCK(kq);
- if (kn_in_flux(kn)) {
- KQ_UNLOCK(kq);
- continue;
- }
- knlist_remove_kq(knl, kn, 1, 1);
- if (killkn) {
- kn_enter_flux(kn);
- KQ_UNLOCK(kq);
- knote_drop_detached(kn, td);
- } else {
- /* Make sure cleared knotes disappear soon */
- kn->kn_flags |= EV_EOF | EV_ONESHOT;
- KQ_UNLOCK(kq);
+ for (;;) {
+ /*
+ * Each pass removes as many knotes as we can before dropping
+ * into FLUXWAIT. Active knotes are simply detached and either
+ * freed or converted to one-shot, as the attached subject is
+ * essentially disappearing.
+ */
+ SLIST_FOREACH_SAFE(kn, &knl->kl_list, kn_selnext, kn2) {
+ kq = kn->kn_kq;
+ KQ_LOCK(kq);
+ if (kn_in_flux(kn)) {
+ KQ_UNLOCK(kq);
+ continue;
+ }
+ knlist_remove_kq(knl, kn, 1, 1);
+ if (killkn) {
+ kn_enter_flux(kn);
+ KQ_UNLOCK(kq);
+ knote_drop_detached(kn, td);
+ } else {
+ /* Make sure cleared knotes disappear soon */
+ kn->kn_flags |= EV_EOF | EV_ONESHOT;
+ KQ_UNLOCK(kq);
+ }
+ kq = NULL;
}
- kq = NULL;
- }
- if (!SLIST_EMPTY(&knl->kl_list)) {
+ if (SLIST_EMPTY(&knl->kl_list))
+ break;
+
/* there are still in flux knotes remaining */
kn = SLIST_FIRST(&knl->kl_list);
kq = kn->kn_kq;
@@ -2826,7 +2834,7 @@ again: /* need to reacquire lock since we have dropped it */
kq->kq_state |= KQ_FLUXWAIT;
msleep(kq, &kq->kq_lock, PSOCK | PDROP, "kqkclr", 0);
kq = NULL;
- goto again;
+ knl->kl_lock(knl->kl_lockarg);
}
if (islocked)