git: 7865d159c5e1 - stable/14 - thr_rtld: accept read lock requests while owning the lock for write

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 10 May 2025 19:33:10 UTC
The branch stable/14 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=7865d159c5e1b825286777ec236b502ec1261dc0

commit 7865d159c5e1b825286777ec236b502ec1261dc0
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-05-02 15:09:46 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-05-10 18:57:45 +0000

    thr_rtld: accept read lock requests while owning the lock for write
    
    PR:     286505
    
    (cherry picked from commit 812c4bf3f17024f192980bbb8a781676cb9cf6b6)
---
 lib/libthr/thread/thr_rtld.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c
index 55197a9c5461..5195b208f287 100644
--- a/lib/libthr/thread/thr_rtld.c
+++ b/lib/libthr/thread/thr_rtld.c
@@ -51,8 +51,11 @@ static int	_thr_rtld_set_flag(int);
 static void	_thr_rtld_wlock_acquire(void *);
 
 struct rtld_lock {
-	struct	urwlock	lock;
-	char		_pad[CACHE_LINE_SIZE - sizeof(struct urwlock)];
+	struct urwlock lock;
+	struct pthread *wowner;
+	u_int rlocks;
+	char _pad[CACHE_LINE_SIZE - sizeof(struct urwlock) -
+	    sizeof(struct pthread *) - sizeof(u_int)];
 };
 
 static struct rtld_lock lock_place[MAX_RTLD_LOCKS] __aligned(CACHE_LINE_SIZE);
@@ -117,9 +120,13 @@ _thr_rtld_rlock_acquire(void *lock)
 	SAVE_ERRNO();
 	l = (struct rtld_lock *)lock;
 
-	THR_CRITICAL_ENTER(curthread);
-	while (_thr_rwlock_rdlock(&l->lock, 0, NULL) != 0)
-		;
+	if (l->wowner == curthread) {
+		l->rlocks++;
+	} else {
+		THR_CRITICAL_ENTER(curthread);
+		while (_thr_rwlock_rdlock(&l->lock, 0, NULL) != 0)
+			;
+	}
 	curthread->rdlock_count++;
 	RESTORE_ERRNO();
 }
@@ -138,6 +145,7 @@ _thr_rtld_wlock_acquire(void *lock)
 	THR_CRITICAL_ENTER(curthread);
 	while (_thr_rwlock_wrlock(&l->lock, NULL) != 0)
 		;
+	l->wowner = curthread;
 	RESTORE_ERRNO();
 }
 
@@ -165,6 +173,14 @@ _thr_rtld_lock_release(void *lock)
 		l->lock.rw_blocked_readers = 0;
 		l->lock.rw_blocked_writers = 0;
 	}
+	if ((state & URWLOCK_WRITE_OWNER) != 0) {
+		if (l->rlocks > 0) {
+			l->rlocks--;
+			return;
+		} else {
+			l->wowner = NULL;
+		}
+	}
 	if (_thr_rwlock_unlock(&l->lock) == 0) {
 		if ((state & URWLOCK_WRITE_OWNER) == 0)
 			curthread->rdlock_count--;