git: 4472a048cf95 - main - libthr: GC pshared locks not more than each 25msecs by default

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 27 Sep 2026 23:51:12 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=4472a048cf95c9c1593a8b04655a59096b44b0c9

commit 4472a048cf95c9c1593a8b04655a59096b44b0c9
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-09-27 22:16:33 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-09-27 22:30:00 +0000

    libthr: GC pshared locks not more than each 25msecs by default
    
    Provide a tunable env variable to request immediate GC on destroy
    to allow to return to the previous behavior.
    
    Based on the report and patch by Atle Solbakken <atle.solbakken@gmail.com>.
    PR:     268532
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
---
 lib/libthr/thread/thr_init.c    |  3 +++
 lib/libthr/thread/thr_private.h |  1 +
 lib/libthr/thread/thr_pshared.c | 25 ++++++++++++++++++++++---
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
index 0f9e3749d75f..162ef7dfe7a9 100644
--- a/lib/libthr/thread/thr_init.c
+++ b/lib/libthr/thread/thr_init.c
@@ -539,6 +539,9 @@ init_private(void)
 				    mint, NULL, NULL);
 			}
 		}
+		env = getenv("LIBPTHREAD_PSHARED_LOCK_DESTROY_IMMEDIATE_GC");
+		if (env)
+			__thr_pshared_destroy_imm_gc = true;
 	}
 	init_once = 1;
 }
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index d7b889930365..2edf09d761ae 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -780,6 +780,7 @@ extern struct pthread	*_single_thread __hidden;
 extern bool		_thr_after_fork __hidden;
 
 extern int	__thr_new_flags;
+extern bool	__thr_pshared_destroy_imm_gc __hidden;
 
 /*
  * Function prototype definitions.
diff --git a/lib/libthr/thread/thr_pshared.c b/lib/libthr/thread/thr_pshared.c
index d20d66e21ea3..698cc5e6adc7 100644
--- a/lib/libthr/thread/thr_pshared.c
+++ b/lib/libthr/thread/thr_pshared.c
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 #include "namespace.h"
 #include <stdlib.h>
 #include "un-namespace.h"
@@ -49,6 +50,10 @@ static struct pshared_hash_head pshared_hash[HASH_SIZE];
 static struct urwlock pshared_lock = DEFAULT_URWLOCK;
 static int page_size;
 
+#define GC_INTERVAL_USEC 25000
+static struct timeval pshared_gc_time = {0, 0};
+bool __thr_pshared_destroy_imm_gc = false;
+
 void
 __thr_pshared_init(void)
 {
@@ -94,9 +99,8 @@ pshared_unlock(struct pthread *curthread)
  * mapped off-page.
  *
  * Mitigate the problem by checking the liveness of all hashed keys
- * periodically.  Right now this is executed on each
- * pthread_lock_destroy(), but may be done less often if found to be
- * too time-consuming.
+ * periodically.  Right now this is executed on pthread_lock_destroy()
+ * if previous gc happen later than 25msecs.
  */
 static void
 pshared_gc(struct pthread *curthread)
@@ -104,8 +108,18 @@ pshared_gc(struct pthread *curthread)
 	struct pshared_hash_head *hd;
 	struct psh *h, *h1;
 	int error, i;
+	struct timeval now, diff;
 
 	pshared_wlock(curthread);
+
+	if (!__thr_pshared_destroy_imm_gc && gettimeofday(&now, NULL) == 0) {
+		timersub(&now, &pshared_gc_time, &diff);
+		if (diff.tv_sec == 0 && diff.tv_usec < GC_INTERVAL_USEC) {
+			pshared_unlock(curthread);
+			return;
+		}
+	}
+
 	for (i = 0; i < HASH_SIZE; i++) {
 		hd = &pshared_hash[i];
 		LIST_FOREACH_SAFE(h, hd, link, h1) {
@@ -118,6 +132,11 @@ pshared_gc(struct pthread *curthread)
 			free(h);
 		}
 	}
+
+	if (!__thr_pshared_destroy_imm_gc && gettimeofday(&now, NULL) == 0) {
+		pshared_gc_time = now;
+	}
+
 	pshared_unlock(curthread);
 }