Obtaining compat rtld lock in write mode sets process signal mask to
block all signals. Previous mask is stored in the global variable
oldsigmask. If a lock is write-locked while another lock is already
write-locked, oldsigmask is overwritten by the total mask and on the
last unlock, all signals except traps appear to be blocked.
Fix this by counting the write-lock nested level, and only storing to
oldsigmask/restoring from it at the outermost level.
Masking signals disables involuntary preemption for libc_r, and there
could be no voluntary context switches in the locked code
(dl_iterate_phdr(3) keeps a lock around user callback, but it was
added long after libc_r was renounced). Due to this, remembering the
level in the global variable after the lock is obtained should be
safe, because no two libc_r threads can acquire different write locks
in parallel.
PR: 215826
Reported by: kami
Tested by: yamagi@yamagi.org (previous version)
To be reviewed by: kan
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks