From a26b930e92d7c8b0f65a8bb58d831bb5db99b57f Mon Sep 17 00:00:00 2001 From: visa Date: Sun, 12 Jun 2022 10:34:36 +0000 Subject: [PATCH] kqueue: Fix missing wakeup While one thread is running kqueue_scan(), another thread can begin scanning the same kqueue, observe that the event queue is empty, and go to sleep. If the first thread re-inserts a knote for re-processing, the second thread can miss the newly pending event. Wake up the kqueue after a re-insert to correct this. This fixes a Go test hang that jsing@ tracked down to kqueue. Tested in snaps for a week. OK jsing@ mpi@ --- sys/kern/kern_event.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 1d1b4772b58..378e029c204 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_event.c,v 1.188 2022/05/12 13:33:00 visa Exp $ */ +/* $OpenBSD: kern_event.c,v 1.189 2022/06/12 10:34:36 visa Exp $ */ /*- * Copyright (c) 1999,2000,2001 Jonathan Lemon @@ -1286,6 +1286,7 @@ kqueue_scan(struct kqueue_scan_state *scan, int maxevents, struct kqueue *kq = scan->kqs_kq; struct knote *kn; int error = 0, nkev = 0; + int reinserted; if (maxevents == 0) goto done; @@ -1293,6 +1294,7 @@ retry: KASSERT(nkev == 0); error = 0; + reinserted = 0; /* msleep() with PCATCH requires kernel lock. */ KERNEL_LOCK(); @@ -1453,6 +1455,8 @@ retry: kq->kq_count++; kn->kn_status |= KN_QUEUED; TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe); + /* Wakeup is done after loop. */ + reinserted = 1; } knote_release(kn); } @@ -1463,6 +1467,8 @@ retry: scan->kqs_nevent++; } TAILQ_REMOVE(&kq->kq_head, &scan->kqs_start, kn_tqe); + if (reinserted && kq->kq_count != 0) + kqueue_wakeup(kq); mtx_leave(&kq->kq_lock); if (scan->kqs_nevent == 0) goto retry; -- 2.20.1