git: 99edcc3bd526 - main - libthr: Reorder pthread mutex to prevent false sharing

From: ShengYi Hung <aokblast_at_FreeBSD.org>
Date: Wed, 07 Oct 2026 17:06:35 UTC
The branch main has been updated by aokblast:

URL: https://cgit.FreeBSD.org/src/commit/?id=99edcc3bd52614c6cf972ea8424a7807ed3fe1e3

commit 99edcc3bd52614c6cf972ea8424a7807ed3fe1e3
Author:     ShengYi Hung <aokblast@FreeBSD.org>
AuthorDate: 2026-10-07 07:22:13 +0000
Commit:     ShengYi Hung <aokblast@FreeBSD.org>
CommitDate: 2026-10-07 17:05:58 +0000

    libthr: Reorder pthread mutex to prevent false sharing
    
    On a 64 byte cache line CPU (amd64), m_owner is contended by all of
    the shared processes. However, after finding one winner, mtx is
    enqueued, which trigger a cache refresh from other processors. Reorder
    mtx so that m_lock and m_qu will not be in the same cache line.
    
    Notice that this doesn't affet arch that expose 128 bytes cache line
    line aarch64 or powerpc.
    
    Reviewed by:    kib, markj
    MFC after:      2 weeks
    Differential Revision: https://reviews.freebsd.org/D60434
---
 lib/libthr/thread/thr_mutex.c   | 9 +++++++++
 lib/libthr/thread/thr_private.h | 6 +++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/lib/libthr/thread/thr_mutex.c b/lib/libthr/thread/thr_mutex.c
index ccb3094db16d..139dc768b7ba 100644
--- a/lib/libthr/thread/thr_mutex.c
+++ b/lib/libthr/thread/thr_mutex.c
@@ -53,6 +53,15 @@
 _Static_assert(sizeof(struct pthread_mutex) <= THR_PAGE_SIZE_MIN,
     "pthread_mutex is too large for off-page");
 
+/*
+ * Keep the thread-private linkage off the cache line holding the lock word;
+ * Only meaningful where cache line is 64 bytes.
+ */
+#if defined(__LP64__) && CACHE_LINE_SIZE == 64
+_Static_assert(offsetof(struct pthread_mutex, m_qe) >= CACHE_LINE_SIZE,
+    "m_qe must not share a cache line with m_lock.m_owner");
+#endif
+
 /*
  * For adaptive mutexes, how many times to spin doing trylock2
  * before entering the kernel to block
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index 2edf09d761ae..cf90ac5bd4ef 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -171,6 +171,11 @@ struct pthread_mutex {
 	int				m_spinloops;
 	int				m_yieldloops;
 	int				m_ps;	/* pshared init stage */
+	/*
+	 * Deliberately put m_qe and m_lock into different cache line to prevent
+	 * false sharing.
+	 */
+	struct pthread_mutex		*m_rb_prev;
 	/*
 	 * Link for all mutexes a thread currently owns, of the same
 	 * prio type.
@@ -178,7 +183,6 @@ struct pthread_mutex {
 	TAILQ_ENTRY(pthread_mutex)	m_qe;
 	/* Link for all private mutexes a thread currently owns. */
 	TAILQ_ENTRY(pthread_mutex)	m_pqe;
-	struct pthread_mutex		*m_rb_prev;
 };
 
 struct pthread_mutex_attr {