Module Name:    src
Committed By:   jdolecek
Date:           Mon Jan 25 19:57:05 UTC 2021

Modified Files:
        src/sys/kern: kern_event.c

Log Message:
put back clearing of KN_QUEUED and check for re-queue - as rev. 1.53 notes,
it's necessary for correct function

fixes PR kern/55946, thanks to Paul Goyette for testing

part of PR kern/50094 fix


To generate a diff of this commit:
cvs rdiff -u -r1.114 -r1.115 src/sys/kern/kern_event.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_event.c
diff -u src/sys/kern/kern_event.c:1.114 src/sys/kern/kern_event.c:1.115
--- src/sys/kern/kern_event.c:1.114	Sun Jan 24 11:31:47 2021
+++ src/sys/kern/kern_event.c	Mon Jan 25 19:57:05 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_event.c,v 1.114 2021/01/24 11:31:47 jdolecek Exp $	*/
+/*	$NetBSD: kern_event.c,v 1.115 2021/01/25 19:57:05 jdolecek Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.114 2021/01/24 11:31:47 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.115 2021/01/25 19:57:05 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -1487,11 +1487,12 @@ relock:
 		KASSERT((kn->kn_status & KN_BUSY) == 0);
 
 		kq_check(kq);
+		kn->kn_status &= ~KN_QUEUED;
 		kn->kn_status |= KN_BUSY;
 		kq_check(kq);
 		if (kn->kn_status & KN_DISABLED) {
+			kn->kn_status &= ~KN_BUSY;
 			kq->kq_count--;
-			kn->kn_status &= ~(KN_QUEUED|KN_BUSY);
 			/* don't want disabled events */
 			continue;
 		}
@@ -1504,12 +1505,20 @@ relock:
 			rv = (*kn->kn_fop->f_event)(kn, 0);
 			KERNEL_UNLOCK_ONE(NULL);	/* XXXSMP */
 			mutex_spin_enter(&kq->kq_lock);
+			/* Re-poll if note was re-enqueued. */
+			if ((kn->kn_status & KN_QUEUED) != 0) {
+				kn->kn_status &= ~KN_BUSY;
+				/* Re-enqueue raised kq_count, lower it again */
+				kq->kq_count--;
+				influx = 1;
+				continue;
+			}
 			if (rv == 0) {
 				/*
 				 * non-ONESHOT event that hasn't
 				 * triggered again, so de-queue.
 				 */
-				kn->kn_status &= ~(KN_QUEUED|KN_ACTIVE|KN_BUSY);
+				kn->kn_status &= ~(KN_ACTIVE|KN_BUSY);
 				kq->kq_count--;
 				influx = 1;
 				continue;
@@ -1533,7 +1542,7 @@ relock:
 		influx = 1;
 		if (kn->kn_flags & EV_ONESHOT) {
 			/* delete ONESHOT events after retrieval */
-			kn->kn_status &= ~(KN_QUEUED|KN_BUSY);
+			kn->kn_status &= ~KN_BUSY;
 			kq->kq_count--;
 			mutex_spin_exit(&kq->kq_lock);
 			knote_detach(kn, fdp, true);
@@ -1551,15 +1560,16 @@ relock:
 				kn->kn_data = 0;
 				kn->kn_fflags = 0;
 			}
-			kn->kn_status &= ~(KN_QUEUED|KN_ACTIVE|KN_BUSY);
+			kn->kn_status &= ~(KN_ACTIVE|KN_BUSY);
 			kq->kq_count--;
 		} else if (kn->kn_flags & EV_DISPATCH) {
 			kn->kn_status |= KN_DISABLED;
-			kn->kn_status &= ~(KN_QUEUED|KN_ACTIVE|KN_BUSY);
+			kn->kn_status &= ~(KN_ACTIVE|KN_BUSY);
 			kq->kq_count--;
 		} else {
 			/* add event back on list */
 			kq_check(kq);
+			kn->kn_status |= KN_QUEUED;
 			kn->kn_status &= ~KN_BUSY;
 			TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
 			kq_check(kq);

Reply via email to