Do not wake up sleeping thread in reschedule_signals() if the signal

is blocked.  The spurious wakeup might result in spurious EINTR.

The reschedule_signals() function is called when the calling thread
has the signal mask changed.  For each newly blocked signal, we try to
find a thread which might have the signal not blocked.  If no such
thread exists, sigtd() returns random thread, which must not be waken
up.  I decided that re-checking, as suggested by PR submitter, is more
reasonable change than to change sigtd() interface, due to other uses
of sigtd().  signotify() already performs this check.

Submitted by:	Duane <parakleta@darkreality.org>
PR:	219228
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2017-05-12 15:34:59 +00:00
parent 342b8b88ba
commit 396a0d4455

View File

@ -2646,7 +2646,9 @@ reschedule_signals(struct proc *p, sigset_t block, int flags)
signotify(td);
if (!(flags & SIGPROCMASK_PS_LOCKED))
mtx_lock(&ps->ps_mtx);
if (p->p_flag & P_TRACED || SIGISMEMBER(ps->ps_sigcatch, sig))
if (p->p_flag & P_TRACED ||
(SIGISMEMBER(ps->ps_sigcatch, sig) &&
!SIGISMEMBER(td->td_sigmask, sig)))
tdsigwakeup(td, sig, SIG_CATCH,
(SIGISMEMBER(ps->ps_sigintr, sig) ? EINTR :
ERESTART));