git: 4ab9e73994e6 - main - libthr/thr_mutex.c: make mutex asserts more useful

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 28 Oct 2026 01:09:39 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=4ab9e73994e673e518d1b0631f8ce7d1faec6d80

commit 4ab9e73994e673e518d1b0631f8ce7d1faec6d80
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-10-27 13:05:59 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-10-28 00:56:06 +0000

    libthr/thr_mutex.c: make mutex asserts more useful
    
    Print the file and line number of the caller where the assert fired.
    Use _thread_exitf() directly for this.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
---
 lib/libthr/thread/thr_mutex.c | 50 +++++++++++++++++++++++++------------------
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/lib/libthr/thread/thr_mutex.c b/lib/libthr/thread/thr_mutex.c
index 9c0939aa6080..58c79c973a9b 100644
--- a/lib/libthr/thread/thr_mutex.c
+++ b/lib/libthr/thread/thr_mutex.c
@@ -131,41 +131,50 @@ mutex_init_link(struct pthread_mutex *m __unused)
 #endif
 }
 
+#if defined(_PTHREADS_INVARIANTS)
 static void
-mutex_assert_is_owned(struct pthread_mutex *m __unused)
+mutex_assert_is_owned(struct pthread_mutex *m, int line)
 {
-
-#if defined(_PTHREADS_INVARIANTS)
-	if (__predict_false(m->m_qe.tqe_prev == NULL))
-		PANIC("mutex %p own %#x is not on list %p %p",
+	if (__predict_false(m->m_qe.tqe_prev == NULL)) {
+		_thread_exitf(__FILE__, line,
+		    "mutex %p own %#x is not on list %p %p",
 		    m, m->m_lock.m_owner, m->m_qe.tqe_prev, m->m_qe.tqe_next);
-#endif
+	}
 }
 
 static void
-mutex_assert_not_owned(struct pthread *curthread __unused,
-    struct pthread_mutex *m __unused)
+mutex_assert_not_owned(struct pthread_mutex *m, int line)
 {
+	struct pthread *curthread;
 
-#if defined(_PTHREADS_INVARIANTS)
+	curthread = _get_curthread();
 	if (__predict_false(m->m_qe.tqe_prev != NULL ||
-	    m->m_qe.tqe_next != NULL))
-		PANIC("mutex %p own %#x is on list %p %p",
+	    m->m_qe.tqe_next != NULL)) {
+		_thread_exitf(__FILE__, line,
+		    "mutex %p own %#x is on list %p %p",
 		    m, m->m_lock.m_owner, m->m_qe.tqe_prev, m->m_qe.tqe_next);
+	}
 	if (__predict_false(is_robust_mutex(m) &&
 	    (m->m_lock.m_rb_lnk != 0 || m->m_rb_prev != NULL ||
 	    (is_pshared_mutex(m) && curthread->robust_list ==
 	    (uintptr_t)&m->m_lock) ||
 	    (!is_pshared_mutex(m) && curthread->priv_robust_list ==
-	    (uintptr_t)&m->m_lock))))
-		PANIC(
-    "mutex %p own %#x is on robust linkage %p %p head %p phead %p",
+	    (uintptr_t)&m->m_lock)))) {
+		_thread_exitf(__FILE__, line,
+	    "mutex %p own %#x is on robust linkage %p %p head %p phead %p",
 		    m, m->m_lock.m_owner, (void *)m->m_lock.m_rb_lnk,
 		    m->m_rb_prev, (void *)curthread->robust_list,
 		    (void *)curthread->priv_robust_list);
-#endif
+	}
 }
 
+#define	MUTEX_ASSERT_IS_OWNED(m)	mutex_assert_is_owned(m, __LINE__)
+#define	MUTEX_ASSERT_NOT_OWNED(m)	mutex_assert_not_owned(m, __LINE__)
+#else
+#define	MUTEX_ASSERT_IS_OWNED(m)	do {} while (0)
+#define	MUTEX_ASSERT_NOT_OWNED(m)	do {} while (0)
+#endif
+
 static bool
 is_pshared_mutex(struct pthread_mutex *m)
 {
@@ -477,8 +486,7 @@ _thr_mutex_destroy(pthread_mutex_t *mutex)
 			if (m1 != NULL) {
 				if ((uint32_t)m1->m_lock.m_owner !=
 				    UMUTEX_RB_OWNERDEAD) {
-					mutex_assert_not_owned(
-					    _get_curthread(), m1);
+					MUTEX_ASSERT_NOT_OWNED(m1);
 				}
 				__thr_pshared_destroy(mutex);
 			}
@@ -490,7 +498,7 @@ _thr_mutex_destroy(pthread_mutex_t *mutex)
 			ret = EBUSY;
 		} else {
 			*mutex = THR_MUTEX_DESTROYED;
-			mutex_assert_not_owned(_get_curthread(), m);
+			MUTEX_ASSERT_NOT_OWNED(m);
 			__thr_free(m);
 			ret = 0;
 		}
@@ -530,7 +538,7 @@ enqueue_mutex(struct pthread *curthread, struct pthread_mutex *m,
 
 	/* Add to the list of owned mutexes: */
 	if (error != EOWNERDEAD)
-		mutex_assert_not_owned(curthread, m);
+		MUTEX_ASSERT_NOT_OWNED(m);
 	qidx = mutex_qidx(m);
 	TAILQ_INSERT_TAIL(&curthread->mq[qidx], m, m_qe);
 	if (!is_pshared_mutex(m))
@@ -558,7 +566,7 @@ dequeue_mutex(struct pthread *curthread, struct pthread_mutex *m)
 	struct pthread_mutex *mp, *mn;
 	int qidx;
 
-	mutex_assert_is_owned(m);
+	MUTEX_ASSERT_IS_OWNED(m);
 	qidx = mutex_qidx(m);
 	if (is_robust_mutex(m)) {
 		mp = m->m_rb_prev;
@@ -1054,7 +1062,7 @@ _pthread_mutex_setprioceiling(pthread_mutex_t * __restrict mutex,
 
 	curthread = _get_curthread();
 	if (PMUTEX_OWNER_ID(m) == TID(curthread)) {
-		mutex_assert_is_owned(m);
+		MUTEX_ASSERT_IS_OWNED(m);
 		m1 = TAILQ_PREV(m, mutex_queue, m_qe);
 		m2 = TAILQ_NEXT(m, m_qe);
 		if ((m1 != NULL && m1->m_lock.m_ceilings[0] > (u_int)ceiling) ||