Provide helper macros to detect 'non-silent SBDRY' state and to

calculate appropriate return value for stops.  Simplify the code by
using them.

Fix typo in sig_suspend_threads().  The thread which sleep must be
aborted is td2. (*)

In issignal(), when handling stopping signal for thread in
TD_SBDRY_INTR state, do not stop, this is wrong and fires assert.
This is yet another place where execution should be forced out of
SBDRY-protected region.  For such case, return -1 from issignal() and
translate it to corresponding error code in sleepq_catch_signals().
Assert that other consumers of cursig() are not affected by the new
return value. (*)

Micro-optimize, mostly VFS and VOP methods, by avoiding calling the
functions when SIGDEFERSTOP_NOP non-change is requested. (**)

Reported and tested by:	pho (*)
Requested by:	bde (**)
Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
Approved by:	re (gjb)
This commit is contained in:
kib 2016-07-03 18:19:48 +00:00
parent c861dc4640
commit 2ff8e9c636
5 changed files with 62 additions and 32 deletions

View File

@ -1251,6 +1251,7 @@ kern_sigtimedwait(struct thread *td, sigset_t waitset, ksiginfo_t *ksi,
mtx_lock(&ps->ps_mtx);
sig = cursig(td);
mtx_unlock(&ps->ps_mtx);
KASSERT(sig >= 0, ("sig %d", sig));
if (sig != 0 && SIGISMEMBER(waitset, sig)) {
if (sigqueue_get(&td->td_sigqueue, sig, ksi) != 0 ||
sigqueue_get(&p->p_sigqueue, sig, ksi) != 0) {
@ -1512,8 +1513,10 @@ kern_sigsuspend(struct thread *td, sigset_t mask)
/* void */;
thread_suspend_check(0);
mtx_lock(&p->p_sigacts->ps_mtx);
while ((sig = cursig(td)) != 0)
while ((sig = cursig(td)) != 0) {
KASSERT(sig >= 0, ("sig %d", sig));
has_sig += postsig(sig);
}
mtx_unlock(&p->p_sigacts->ps_mtx);
}
PROC_UNLOCK(p);
@ -2476,11 +2479,9 @@ sig_suspend_threads(struct thread *td, struct proc *p, int sending)
*/
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);
if (TD_SBDRY_INTR(td2) && sending) {
wakeup_swapper |= sleepq_abort(td2,
TD_SBDRY_ERRNO(td2));
}
} else if (!TD_IS_SUSPENDED(td2)) {
thread_suspend_one(td2);
@ -2628,7 +2629,7 @@ sigdeferstop_curr_flags(int cflags)
* accesses below.
*/
int
sigdeferstop(int mode)
sigdeferstop_impl(int mode)
{
struct thread *td;
int cflags, nflags;
@ -2655,11 +2656,11 @@ sigdeferstop(int mode)
panic("sigdeferstop: invalid mode %x", mode);
break;
}
if (cflags != nflags) {
thread_lock(td);
td->td_flags = (td->td_flags & ~cflags) | nflags;
thread_unlock(td);
}
if (cflags == nflags)
return (SIGDEFERSTOP_VAL_NCHG);
thread_lock(td);
td->td_flags = (td->td_flags & ~cflags) | nflags;
thread_unlock(td);
return (cflags);
}
@ -2670,11 +2671,12 @@ sigdeferstop(int mode)
* either via ast() or a subsequent interruptible sleep.
*/
void
sigallowstop(int prev)
sigallowstop_impl(int prev)
{
struct thread *td;
int cflags;
KASSERT(prev != SIGDEFERSTOP_VAL_NCHG, ("failed sigallowstop"));
KASSERT((prev & ~(TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)) == 0,
("sigallowstop: incorrect previous mode %x", prev));
td = curthread;
@ -2835,6 +2837,11 @@ issignal(struct thread *td)
(p->p_pgrp->pg_jobc == 0 &&
prop & SA_TTYSTOP))
break; /* == ignore */
if (TD_SBDRY_INTR(td)) {
KASSERT((td->td_flags & TDF_SBDRY) != 0,
("lost TDF_SBDRY"));
return (-1);
}
mtx_unlock(&ps->ps_mtx);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK,
&p->p_mtx.lock_object, "Catching SIGSTOP");

View File

@ -894,7 +894,7 @@ thread_suspend_check(int return_instead)
{
struct thread *td;
struct proc *p;
int wakeup_swapper, r;
int wakeup_swapper;
td = curthread;
p = td->td_proc;
@ -927,21 +927,10 @@ thread_suspend_check(int return_instead)
if ((td->td_flags & TDF_SBDRY) != 0) {
KASSERT(return_instead,
("TDF_SBDRY set for unsafe thread_suspend_check"));
switch (td->td_flags & (TDF_SEINTR | TDF_SERESTART)) {
case 0:
r = 0;
break;
case TDF_SEINTR:
r = EINTR;
break;
case TDF_SERESTART:
r = ERESTART;
break;
default:
panic("both TDF_SEINTR and TDF_SERESTART");
break;
}
return (r);
KASSERT((td->td_flags & (TDF_SEINTR | TDF_SERESTART)) !=
(TDF_SEINTR | TDF_SERESTART),
("both TDF_SEINTR and TDF_SERESTART"));
return (TD_SBDRY_INTR(td) ? TD_SBDRY_ERRNO(td) : 0);
}
/*

View File

@ -453,7 +453,16 @@ sleepq_catch_signals(void *wchan, int pri)
ps = p->p_sigacts;
mtx_lock(&ps->ps_mtx);
sig = cursig(td);
if (sig == 0) {
if (sig == -1) {
mtx_unlock(&ps->ps_mtx);
KASSERT((td->td_flags & TDF_SBDRY) != 0, ("lost TDF_SBDRY"));
KASSERT(TD_SBDRY_INTR(td),
("lost TDF_SERESTART of TDF_SEINTR"));
KASSERT((td->td_flags & (TDF_SEINTR | TDF_SERESTART)) !=
(TDF_SEINTR | TDF_SERESTART),
("both TDF_SEINTR and TDF_SERESTART"));
ret = TD_SBDRY_ERRNO(td);
} else if (sig == 0) {
mtx_unlock(&ps->ps_mtx);
ret = thread_suspend_check(1);
MPASS(ret == 0 || ret == EINTR || ret == ERESTART);

View File

@ -511,6 +511,11 @@ do { \
#define TD_SET_RUNQ(td) (td)->td_state = TDS_RUNQ
#define TD_SET_CAN_RUN(td) (td)->td_state = TDS_CAN_RUN
#define TD_SBDRY_INTR(td) \
(((td)->td_flags & (TDF_SEINTR | TDF_SERESTART)) != 0)
#define TD_SBDRY_ERRNO(td) \
(((td)->td_flags & TDF_SEINTR) != 0 ? EINTR : ERESTART)
/*
* Process structure.
*/

View File

@ -337,9 +337,29 @@ extern struct mtx sigio_lock;
#define SIGDEFERSTOP_EINTR 3 /* ignore STOPs, return EINTR */
#define SIGDEFERSTOP_ERESTART 4 /* ignore STOPs, return ERESTART */
#define SIGDEFERSTOP_VAL_NCHG (-1) /* placeholder indicating no state change */
int sigdeferstop_impl(int mode);
void sigallowstop_impl(int prev);
static inline int
sigdeferstop(int mode)
{
if (mode == SIGDEFERSTOP_NOP)
return (SIGDEFERSTOP_VAL_NCHG);
return (sigdeferstop_impl(mode));
}
static inline void
sigallowstop(int prev)
{
if (prev == SIGDEFERSTOP_VAL_NCHG)
return;
sigallowstop_impl(prev);
}
int cursig(struct thread *td);
int sigdeferstop(int mode);
void sigallowstop(int prev);
void execsigs(struct proc *p);
void gsignal(int pgid, int sig, ksiginfo_t *ksi);
void killproc(struct proc *p, char *why);