git: 5b45cd83c44e - stable/13 - libthr rtld locks: do not leak URWLOCK_READ_WAITERS into child

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 29 May 2023 03:21:05 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=5b45cd83c44edb9386eed1155acd3c52f36bf12c

commit 5b45cd83c44edb9386eed1155acd3c52f36bf12c
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-05-20 08:11:54 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-05-29 03:20:42 +0000

    libthr rtld locks: do not leak URWLOCK_READ_WAITERS into child
    
    PR:     271490
    
    (cherry picked from commit 6f49eafb056cfa0703dfc97a731cabe4ed2596b8)
---
 lib/libthr/thread/thr_fork.c    |  4 ++++
 lib/libthr/thread/thr_private.h |  2 ++
 lib/libthr/thread/thr_rtld.c    | 11 +++++++++++
 3 files changed, 17 insertions(+)

diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c
index 9861e93c427d..341afc2b06ec 100644
--- a/lib/libthr/thread/thr_fork.c
+++ b/lib/libthr/thread/thr_fork.c
@@ -78,6 +78,8 @@ __FBSDID("$FreeBSD$");
 __weak_reference(_thr_atfork, _pthread_atfork);
 __weak_reference(_thr_atfork, pthread_atfork);
 
+bool _thr_after_fork = false;
+
 int
 _thr_atfork(void (*prepare)(void), void (*parent)(void),
     void (*child)(void))
@@ -243,7 +245,9 @@ thr_fork_impl(const struct thr_fork_args *a)
 		_thr_signal_postfork_child();
 
 		if (was_threaded) {
+			_thr_after_fork = true;
 			_rtld_atfork_post(rtld_locks);
+			_thr_after_fork = false;
 			__thr_pshared_atfork_post();
 		}
 		_thr_setthreaded(0);
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index 0e88c6711817..910de374accf 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -779,6 +779,8 @@ extern int		_suspend_all_waiters __hidden;
 extern int		_suspend_all_cycle __hidden;
 extern struct pthread	*_single_thread __hidden;
 
+extern bool		_thr_after_fork __hidden;
+
 /*
  * Function prototype definitions.
  */
diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c
index 1967ea14859d..fe4fb7ae0602 100644
--- a/lib/libthr/thread/thr_rtld.c
+++ b/lib/libthr/thread/thr_rtld.c
@@ -158,6 +158,17 @@ _thr_rtld_lock_release(void *lock)
 	l = (struct rtld_lock *)lock;
 	
 	state = l->lock.rw_state;
+	if (__predict_false(_thr_after_fork)) {
+		/*
+		 * After fork, only this thread is running, there is no
+		 * waiters.  Keeping waiters recorded in rwlock breaks
+		 * wake logic.
+		 */
+		atomic_clear_int(&l->lock.rw_state,
+		    URWLOCK_WRITE_WAITERS | URWLOCK_READ_WAITERS);
+		l->lock.rw_blocked_readers = 0;
+		l->lock.rw_blocked_writers = 0;
+	}
 	if (_thr_rwlock_unlock(&l->lock) == 0) {
 		if ((state & URWLOCK_WRITE_OWNER) == 0)
 			curthread->rdlock_count--;