To prevent an infinite loop, threads looking for events inside kqueue_scan(), insert a `marker' in the list. Such markers are not accounted and they are removed from the list as soon as the thread is finished or goes to sleep.
Diff below is a small cleanup to keep the accounting of events in sync with the number of events on the list. This is a noop for the moment, but it's small & easy part to review of my upcoming diff. ok? Index: kern/kern_event.c =================================================================== RCS file: /cvs/src/sys/kern/kern_event.c,v retrieving revision 1.79 diff -u -p -r1.79 kern_event.c --- kern/kern_event.c 31 May 2017 14:52:05 -0000 1.79 +++ kern/kern_event.c 9 Oct 2017 09:57:54 -0000 @@ -760,22 +760,24 @@ start: TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe); while (count) { kn = TAILQ_FIRST(&kq->kq_head); - TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe); if (kn == &marker) { + TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe); splx(s); if (count == maxevents) goto retry; goto done; } + + TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe); + kq->kq_count--; + if (kn->kn_status & KN_DISABLED) { kn->kn_status &= ~KN_QUEUED; - kq->kq_count--; continue; } if ((kn->kn_flags & EV_ONESHOT) == 0 && kn->kn_fop->f_event(kn, 0) == 0) { kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE); - kq->kq_count--; continue; } *kevp = kn->kn_kevent; @@ -783,7 +785,6 @@ start: nkev++; if (kn->kn_flags & EV_ONESHOT) { kn->kn_status &= ~KN_QUEUED; - kq->kq_count--; splx(s); kn->kn_fop->f_detach(kn); knote_drop(kn, p, p->p_fd); @@ -796,9 +797,9 @@ start: if (kn->kn_flags & EV_DISPATCH) kn->kn_status |= KN_DISABLED; kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE); - kq->kq_count--; } else { TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe); + kq->kq_count++; } count--; if (nkev == KQ_NEVENTS) {