⬢ DragonFlyBSD Kernel Audit
DF-2986 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/kern_condvar.c	2026-06-29 12:51:19.000000000 +0000
+++ b/sys/kern/kern_condvar.c	2026-10-26 03:49:12.313898647 +0000
@@ -2,6 +2,8 @@
 #include <sys/spinlock2.h>
 #include <sys/systm.h>
 #include <sys/lock.h>
+#include <sys/kernel.h>
+
 
 void
 cv_init(struct cv *c, const char *desc)
@@ -14,6 +16,13 @@
 void
 cv_destroy(struct cv *c)
 {
+#ifdef INVARIANTS
+	if (c->cv_waiters && tsleep_wchan_busy(c)) {
+		kprintf("cv_destroy: cv %p (%s) destroyed with waiters\n",
+			c, c->cv_desc);
+		KKASSERT(0 == 1);
+	}
+#endif
 	spin_uninit(&c->cv_lock);
 }
 
--- a/sys/kern/kern_synch.c	2026-06-29 12:51:19.000000000 +0000
+++ b/sys/kern/kern_synch.c	2026-10-26 03:48:50.586174551 +0000
@@ -447,6 +447,32 @@
 	crit_exit_quick(td);
 }
 
+#ifdef INVARIANTS
+/*
+ * TRUE if any thread is currently enqueued (td_wchan == wchan) in any
+ * CPU's tsleep hash.  Diagnostic helper for cv_destroy() (kern_condvar.c).
+ */
+int
+tsleep_wchan_busy(const void *wchan)
+{
+	globaldata_t gd;
+	struct tslpque *qp;
+	struct thread *td;
+	int cpu;
+
+	for (cpu = 0; cpu < ncpus; cpu++) {
+		gd = globaldata_find(cpu);
+		qp = &gd->gd_tsleep_hash[
+		    TCHASHSHIFT(LOOKUP(wchan))];
+		TAILQ_FOREACH(td, &qp->queue, td_sleepq) {
+			if (td->td_wchan == wchan)
+				return (1);
+		}
+	}
+	return (0);
+}
+#endif
+
 void
 tsleep_interlock(const volatile void *ident, int flags)
 {
--- a/sys/sys/systm.h	2026-06-29 12:51:19.000000000 +0000
+++ b/sys/sys/systm.h	2026-10-26 03:49:12.277899104 +0000
@@ -418,6 +418,9 @@
 int	zsleep(const volatile void *, struct lwkt_serialize *, int, const char *, int)
 	    __nonnull(1);
 void	tsleep_interlock(const volatile void *, int) __nonnull(1);
+#ifdef INVARIANTS
+int	tsleep_wchan_busy(const void *wchan);
+#endif
 void	tsleep_remove (struct thread *);
 int	lwkt_sleep (const char *, int);
 void	tstop (void);