Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 22 May 2023 13:46:48 GMT
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 6f49eafb056c - main - libthr rtld locks: do not leak URWLOCK_READ_WAITERS into child
Message-ID:  <202305221346.34MDkmo9076921@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=6f49eafb056cfa0703dfc97a731cabe4ed2596b8

commit 6f49eafb056cfa0703dfc97a731cabe4ed2596b8
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-05-20 08:11:54 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-05-22 13:46:42 +0000

    libthr rtld locks: do not leak URWLOCK_READ_WAITERS into child
    
    Since there is only the current thread in the child, no pending readers
    exist.  Clear the bit, since it confuses future attempts to acquire
    write ownership of the rtld locks, due to URWLOCK_PREFER_READERS flag.
    
    To be future-proof, clear all state about pending writers and readers.
    
    PR:     271490
    Reported and tested by: KJ Tsanaktsidis <kj@kjtsanaktsidis.id.au>
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D40178
---
 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 a64c3f1692ab..e235ff424358 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 a9d1924967a7..cedc13a1440e 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--;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202305221346.34MDkmo9076921>