git: c6dd40f2d35d - main - kqueue: slightly clarify the flow in knlist_cleardel()

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Thu, 09 Apr 2026 02:37:34 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=c6dd40f2d35d596ca60a5d87616c3e4a0fd4f676

commit c6dd40f2d35d596ca60a5d87616c3e4a0fd4f676
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2026-04-09 02:37:00 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-04-09 02:37:11 +0000

    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
---
 sys/kern/kern_event.c | 50 +++++++++++++++++++++++++++++---------------------
 1 file 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)