Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 6 Sep 2021 23:43:58 GMT
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 98168a6e6c12 - main - kqueue: drain kqueue taskqueue if syscall tickled it
Message-ID:  <202109062343.186NhwMK094831@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kib:

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

commit 98168a6e6c12dab8f608f6b5f5b0b175d2b87ef0
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-09-06 11:43:06 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-09-06 23:43:34 +0000

    kqueue: drain kqueue taskqueue if syscall tickled it
    
    Otherwise return from the syscall and next syscall, which could be
    kevent(2) on the kqueue that should be notified, races with the kqueue
    taskqueue thread, and potentially misses the wakeup.  This is reliably
    visible when kevent(2) only peeks into events using zeroed timeout.
    
    PR:     258310
    Reported by:    arichardson, Jan Kokemüller <jan.kokemueller@gmail.com>
    Reviewed by:    arichardson, markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D31858
---
 sys/kern/kern_event.c | 11 +++++++++++
 sys/kern/subr_trap.c  |  7 ++++++-
 sys/sys/event.h       |  1 +
 sys/sys/proc.h        |  2 +-
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 859248569f76..db505b234268 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1768,9 +1768,16 @@ kqueue_release(struct kqueue *kq, int locked)
 		KQ_UNLOCK(kq);
 }
 
+void
+kqueue_drain_schedtask(void)
+{
+	taskqueue_quiesce(taskqueue_kqueue_ctx);
+}
+
 static void
 kqueue_schedtask(struct kqueue *kq)
 {
+	struct thread *td;
 
 	KQ_OWNED(kq);
 	KASSERT(((kq->kq_state & KQ_TASKDRAIN) != KQ_TASKDRAIN),
@@ -1779,6 +1786,10 @@ kqueue_schedtask(struct kqueue *kq)
 	if ((kq->kq_state & KQ_TASKSCHED) != KQ_TASKSCHED) {
 		taskqueue_enqueue(taskqueue_kqueue_ctx, &kq->kq_task);
 		kq->kq_state |= KQ_TASKSCHED;
+		td = curthread;
+		thread_lock(td);
+		td->td_flags |= TDF_ASTPENDING | TDF_KQTICKLED;
+		thread_unlock(td);
 	}
 }
 
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
index edeeded09911..2b86fe75776f 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/capsicum.h>
+#include <sys/event.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/msan.h>
@@ -241,7 +242,8 @@ ast(struct trapframe *framep)
 	thread_lock(td);
 	flags = td->td_flags;
 	td->td_flags &= ~(TDF_ASTPENDING | TDF_NEEDSIGCHK | TDF_NEEDSUSPCHK |
-	    TDF_NEEDRESCHED | TDF_ALRMPEND | TDF_PROFPEND | TDF_MACPEND);
+	    TDF_NEEDRESCHED | TDF_ALRMPEND | TDF_PROFPEND | TDF_MACPEND |
+	    TDF_KQTICKLED);
 	thread_unlock(td);
 	VM_CNT_INC(v_trap);
 
@@ -343,6 +345,9 @@ ast(struct trapframe *framep)
 		resched_sigs = false;
 	}
 
+	if ((flags & TDF_KQTICKLED) != 0)
+		kqueue_drain_schedtask();
+
 	/*
 	 * Handle deferred update of the fast sigblock value, after
 	 * the postsig() loop was performed.
diff --git a/sys/sys/event.h b/sys/sys/event.h
index cf7db43475fd..80ed1268c8a1 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -349,6 +349,7 @@ int 	kqfd_register(int fd, struct kevent *kev, struct thread *p,
 	    int mflag);
 int	kqueue_add_filteropts(int filt, struct filterops *filtops);
 int	kqueue_del_filteropts(int filt);
+void	kqueue_drain_schedtask(void);
 
 #else 	/* !_KERNEL */
 
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 39ff1d95f80b..ddc8392481aa 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -451,7 +451,7 @@ do {									\
 #define	TDF_ALLPROCSUSP	0x00000200 /* suspended by SINGLE_ALLPROC */
 #define	TDF_BOUNDARY	0x00000400 /* Thread suspended at user boundary */
 #define	TDF_ASTPENDING	0x00000800 /* Thread has some asynchronous events. */
-#define	TDF_UNUSED12	0x00001000 /* --available-- */
+#define	TDF_KQTICKLED	0x00001000 /* AST drain kqueue taskqueue */
 #define	TDF_SBDRY	0x00002000 /* Stop only on usermode boundary. */
 #define	TDF_UPIBLOCKED	0x00004000 /* Thread blocked on user PI mutex. */
 #define	TDF_NEEDSUSPCHK	0x00008000 /* Thread may need to suspend. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202109062343.186NhwMK094831>