diff options
author | kib <kib@FreeBSD.org> | 2016-06-28 16:41:50 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2016-06-28 16:41:50 +0000 |
commit | fb3ea99e649137928787bf59dba50efdce32c30b (patch) | |
tree | f9ca32630bbbc3bc8f2848f38ba73471d624b7f3 /sys/kern | |
parent | be49875b46f954d583aa76b801a58d766f5e48fe (diff) | |
download | FreeBSD-src-fb3ea99e649137928787bf59dba50efdce32c30b.zip FreeBSD-src-fb3ea99e649137928787bf59dba50efdce32c30b.tar.gz |
Complete r302215. TDF_SBDRY | TDF_SERESTART and TDF_SBDRY |
TDF_SEINTR flags values, unlike TDF_SBDRY, must be treated almost as
if TDF_SBDRY is not set for STOP signal delivery. The only difference
is that sig_suspend_threads() should abort the sleep instead of doing
immediate suspension.
Reported by: ngie
Sponsored by: The FreeBSD Foundation
MFC after: 12 days
Approved by: re (gjb)
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_sig.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 424f316..059103dc 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -107,7 +107,7 @@ static int killpg1(struct thread *td, int sig, int pgid, int all, static int issignal(struct thread *td); static int sigprop(int sig); static void tdsigwakeup(struct thread *, int, sig_t, int); -static void sig_suspend_threads(struct thread *, struct proc *, int); +static int sig_suspend_threads(struct thread *, struct proc *, int); static int filt_sigattach(struct knote *kn); static void filt_sigdetach(struct knote *kn); static int filt_signal(struct knote *kn, long hint); @@ -2327,7 +2327,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) p->p_flag |= P_STOPPED_SIG; p->p_xsig = sig; PROC_SLOCK(p); - sig_suspend_threads(td, p, 1); + wakeup_swapper = sig_suspend_threads(td, p, 1); if (p->p_numthreads == p->p_suspcount) { /* * only thread sending signal to another @@ -2341,6 +2341,8 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) sigqueue_delete_proc(p, p->p_xsig); } else PROC_SUNLOCK(p); + if (wakeup_swapper) + kick_proc0(); goto out; } } else { @@ -2421,7 +2423,8 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval) * Don't awaken a sleeping thread for SIGSTOP if the * STOP signal is deferred. */ - if ((prop & SA_STOP) && (td->td_flags & TDF_SBDRY)) + if ((prop & SA_STOP) != 0 && (td->td_flags & (TDF_SBDRY | + TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY) goto out; /* @@ -2449,14 +2452,16 @@ out: kick_proc0(); } -static void +static int sig_suspend_threads(struct thread *td, struct proc *p, int sending) { struct thread *td2; + int wakeup_swapper; PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); + wakeup_swapper = 0; FOREACH_THREAD_IN_PROC(p, td2) { thread_lock(td2); td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; @@ -2465,11 +2470,18 @@ sig_suspend_threads(struct thread *td, struct proc *p, int sending) if (td2->td_flags & TDF_SBDRY) { /* * Once a thread is asleep with - * TDF_SBDRY set, it should never + * TDF_SBDRY and without TDF_SERESTART + * or TDF_SEINTR set, it should never * become suspended due to this check. */ KASSERT(!TD_IS_SUSPENDED(td2), ("thread with deferred stops suspended")); + if ((td2->td_flags & (TDF_SERESTART | + TDF_SEINTR)) != 0 && sending) { + wakeup_swapper |= sleepq_abort(td, + (td2->td_flags & TDF_SERESTART) + != 0 ? ERESTART : EINTR); + } } else if (!TD_IS_SUSPENDED(td2)) { thread_suspend_one(td2); } @@ -2483,6 +2495,7 @@ sig_suspend_threads(struct thread *td, struct proc *p, int sending) } thread_unlock(td2); } + return (wakeup_swapper); } int @@ -2705,7 +2718,8 @@ issignal(struct thread *td) SIGSETOR(sigpending, p->p_sigqueue.sq_signals); SIGSETNAND(sigpending, td->td_sigmask); - if (p->p_flag & P_PPWAIT || td->td_flags & TDF_SBDRY) + if ((p->p_flag & P_PPWAIT) != 0 || (td->td_flags & + (TDF_SBDRY | TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY) SIG_STOPSIGMASK(sigpending); if (SIGISEMPTY(sigpending)) /* no signal to send */ return (0); |