From 6f49eafb056cfa0703dfc97a731cabe4ed2596b8 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sat, 20 May 2023 11:11:54 +0300 Subject: [PATCH] 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 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 9861e93c427..341afc2b06e 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 a64c3f1692a..e235ff42435 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 a9d1924967a..cedc13a1440 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--;