selwakeup(sip) calls KNOTE(&sip->si_note, 0), which implies that kqueue_wakeup() should not call selwakeup() directly. Otherwise, a contrived program can trigger deep recursion.
The diff below moves selwakeup() from kqueue_wakeup() to kqueue_task(). In addition to preventing the recursion, this change is necessary with the current select/poll implementation to make kqueue_wakeup() free of the kernel lock. OK? Index: kern/kern_event.c =================================================================== RCS file: src/sys/kern/kern_event.c,v retrieving revision 1.129 diff -u -p -r1.129 kern_event.c --- kern/kern_event.c 2 Apr 2020 07:00:25 -0000 1.129 +++ kern/kern_event.c 3 Apr 2020 03:44:00 -0000 @@ -1102,7 +1102,12 @@ kqueue_task(void *arg) { struct kqueue *kq = arg; - KNOTE(&kq->kq_sel.si_note, 0); + if (kq->kq_state & KQ_SEL) { + kq->kq_state &= ~KQ_SEL; + selwakeup(&kq->kq_sel); + } else { + KNOTE(&kq->kq_sel.si_note, 0); + } KQRELE(kq); } @@ -1114,10 +1119,7 @@ kqueue_wakeup(struct kqueue *kq) kq->kq_state &= ~KQ_SLEEP; wakeup(kq); } - if (kq->kq_state & KQ_SEL) { - kq->kq_state &= ~KQ_SEL; - selwakeup(&kq->kq_sel); - } else if (!SLIST_EMPTY(&kq->kq_sel.si_note)) { + if ((kq->kq_state & KQ_SEL) || !SLIST_EMPTY(&kq->kq_sel.si_note)) { /* Defer activation to avoid recursion. */ KQREF(kq); if (!task_add(systq, &kq->kq_task))