Moved signal handling and rescheduling from userret() to ast() so that

they aren't in the usual path of execution for syscalls and traps.
The main complication for this is that we have to set flags to control
ast() everywhere that changes the signal mask.

Avoid locking in userret() in most of the remaining cases.

Submitted by:	luoqi (first part only, long ago, reorganized by me)
Reminded by:	dillon
This commit is contained in:
Bruce Evans 2002-04-04 17:49:48 +00:00
parent fead6f3f5b
commit 79065dba2a
19 changed files with 101 additions and 34 deletions

View File

@ -1471,6 +1471,7 @@ osigreturn(struct thread *td,
*/
SIGSETOLD(p->p_sigmask, ksc.sc_mask);
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
set_regs(td, (struct reg *)ksc.sc_regs);
@ -1553,6 +1554,7 @@ sigreturn(struct thread *td,
p->p_sigmask = uc.uc_sigmask;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
/* XXX ksc.sc_ownedfp ? */

View File

@ -491,11 +491,13 @@ osf1_sigprocmask(td, uap)
case OSF1_SIG_UNBLOCK:
SIGSETNAND(p->p_sigmask, bss);
signotify(p);
break;
case OSF1_SIG_SETMASK:
p->p_sigmask = bss;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
break;
default:
@ -729,6 +731,7 @@ osf1_sigreturn(struct thread *td,
*/
osf1_to_bsd_sigset(&ksc.sc_mask, &p->p_sigmask);
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
set_regs(td, (struct reg *)ksc.sc_regs);

View File

@ -649,6 +649,7 @@ osigreturn(td, uap)
SIGSETOLD(p->p_sigmask, scp->sc_mask);
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
regs->tf_ebp = scp->sc_fp;
regs->tf_esp = scp->sc_sp;
@ -758,6 +759,7 @@ sigreturn(td, uap)
p->p_sigmask = ucp->uc_sigmask;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
return (EJUSTRETURN);
}

View File

@ -602,6 +602,7 @@ coda_call(mntinfo, inSize, outSize, buffer)
}
} while (error && i++ < 128 && VC_OPEN(vcp));
p->p_sigmask = psig_omask;
signotify(p);
PROC_UNLOCK(p);
#else
(void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);

View File

@ -256,10 +256,12 @@ linux_do_sigprocmask(struct thread *td, int how, l_sigset_t *new,
break;
case LINUX_SIG_UNBLOCK:
SIGSETNAND(p->p_sigmask, mask);
signotify(p);
break;
case LINUX_SIG_SETMASK:
p->p_sigmask = mask;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
break;
default:
error = EINVAL;
@ -377,6 +379,7 @@ linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args)
linux_to_bsd_sigset(&lset, &bset);
p->p_sigmask = bset;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
return (0);
}

View File

@ -531,11 +531,13 @@ svr4_sys_sigprocmask(td, uap)
case SVR4_SIG_UNBLOCK:
SIGSETNAND(td->td_proc->p_sigmask, bss);
signotify(td->td_proc);
break;
case SVR4_SIG_SETMASK:
td->td_proc->p_sigmask = bss;
SIG_CANTMASK(td->td_proc->p_sigmask);
signotify(td->td_proc);
break;
default:

View File

@ -602,6 +602,7 @@ coda_call(mntinfo, inSize, outSize, buffer)
}
} while (error && i++ < 128 && VC_OPEN(vcp));
p->p_sigmask = psig_omask;
signotify(p);
PROC_UNLOCK(p);
#else
(void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);

View File

@ -649,6 +649,7 @@ osigreturn(td, uap)
SIGSETOLD(p->p_sigmask, scp->sc_mask);
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
regs->tf_ebp = scp->sc_fp;
regs->tf_esp = scp->sc_sp;
@ -758,6 +759,7 @@ sigreturn(td, uap)
p->p_sigmask = ucp->uc_sigmask;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
return (EJUSTRETURN);
}

View File

@ -328,6 +328,7 @@ ibcs2_sigsys(td, uap)
/* return SIG_HOLD and unblock signal*/
td->td_retval[0] = (int)IBCS2_SIG_HOLD;
SIGDELSET(p->p_sigmask, signum);
signotify(p);
}
PROC_UNLOCK(p);
}
@ -426,11 +427,13 @@ ibcs2_sigprocmask(td, uap)
case IBCS2_SIG_UNBLOCK:
SIGSETNAND(p->p_sigmask, bss);
signotify(p);
break;
case IBCS2_SIG_SETMASK:
p->p_sigmask = bss;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
break;
default:

View File

@ -555,6 +555,7 @@ linux_sigreturn(td, args)
PROC_LOCK(p);
linux_to_bsd_sigset(&lmask, &p->p_sigmask);
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
/*
@ -654,6 +655,7 @@ linux_rt_sigreturn(td, args)
PROC_LOCK(p);
linux_to_bsd_sigset(&uc.uc_sigmask, &p->p_sigmask);
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
/*

View File

@ -294,6 +294,7 @@ svr4_setcontext(td, uc)
svr4_to_bsd_sigset(&uc->uc_sigmask, &mask);
SIG_CANTMASK(mask);
p->p_sigmask = mask;
signotify(p);
}
PROC_UNLOCK(p);

View File

@ -1041,6 +1041,7 @@ sigreturn(struct thread *td,
p->p_sigmask = uc.uc_sigmask;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
/* XXX ksc.sc_ownedfp ? */

View File

@ -180,6 +180,25 @@ CURSIG(struct proc *p)
return (SIGPENDING(p) ? issignal(p) : 0);
}
/*
* Arrange for ast() to handle unmasked pending signals on return to user
* mode. This must be called whenever a signal is added to p_siglist or
* unmasked in p_sigmask.
*/
void
signotify(struct proc *p)
{
PROC_LOCK_ASSERT(p, MA_OWNED);
mtx_assert(&sched_lock, MA_NOTOWNED);
mtx_lock_spin(&sched_lock);
if (SIGPENDING(p)) {
p->p_sflag |= PS_NEEDSIGCHK;
p->p_kse.ke_flags |= KEF_ASTPENDING; /* XXXKSE */
}
mtx_unlock_spin(&sched_lock);
}
static __inline int
sigprop(int sig)
{
@ -514,6 +533,7 @@ do_sigprocmask(p, how, set, oset, old)
break;
case SIG_UNBLOCK:
SIGSETNAND(p->p_sigmask, *set);
signotify(p);
break;
case SIG_SETMASK:
SIG_CANTMASK(*set);
@ -521,6 +541,7 @@ do_sigprocmask(p, how, set, oset, old)
SIGSETLO(p->p_sigmask, *set);
else
p->p_sigmask = *set;
signotify(p);
break;
default:
error = EINVAL;
@ -753,6 +774,7 @@ osigsetmask(td, uap)
PROC_LOCK(p);
SIG2OSIG(p->p_sigmask, td->td_retval[0]);
SIGSETLO(p->p_sigmask, set);
signotify(p);
PROC_UNLOCK(p);
mtx_unlock(&Giant);
return (0);
@ -805,6 +827,7 @@ sigsuspend(td, uap)
SIG_CANTMASK(mask);
p->p_sigmask = mask;
signotify(p);
while (msleep((caddr_t) ps, &p->p_mtx, PPAUSE|PCATCH, "pause", 0) == 0)
/* void */;
PROC_UNLOCK(p);
@ -840,6 +863,7 @@ osigsuspend(td, uap)
OSIG2SIG(uap->mask, mask);
SIG_CANTMASK(mask);
SIGSETLO(p->p_sigmask, mask);
signotify(p);
while (msleep((caddr_t) ps, &p->p_mtx, PPAUSE|PCATCH, "opause", 0) == 0)
/* void */;
PROC_UNLOCK(p);
@ -1303,6 +1327,7 @@ psignal(p, sig)
SIG_CONTSIGMASK(p->p_siglist);
}
SIGADDSET(p->p_siglist, sig);
signotify(p);
/*
* Defer further processing for signals which are held,
@ -1475,7 +1500,6 @@ psignal(p, sig)
#ifdef SMP
struct kse *ke;
struct thread *td = curthread;
signotify(&p->p_kse); /* XXXKSE */
/* we should only deliver to one thread.. but which one? */
FOREACH_KSEGRP_IN_PROC(p, kg) {
FOREACH_KSE_IN_GROUP(kg, ke) {
@ -1485,8 +1509,6 @@ psignal(p, sig)
forward_signal(ke->ke_thread);
}
}
#else
signotify(&p->p_kse); /* XXXKSE */
#endif
}
mtx_unlock_spin(&sched_lock);

View File

@ -70,44 +70,49 @@ userret(td, frame, oticks)
struct proc *p = td->td_proc;
struct kse *ke = td->td_kse;
struct ksegrp *kg = td->td_ksegrp;
int sig;
#ifdef INVARIANTS
/* Check that we called signotify() enough. */
mtx_lock(&Giant);
PROC_LOCK(p);
while ((sig = CURSIG(p)) != 0)
postsig(sig);
mtx_lock_spin(&sched_lock);
if (SIGPENDING(p) && ((p->p_sflag & PS_NEEDSIGCHK) == 0 ||
(p->p_kse.ke_flags & KEF_ASTPENDING) == 0))
printf("failed to set signal flags proprly for ast()\n");
mtx_unlock_spin(&sched_lock);
PROC_UNLOCK(p);
mtx_unlock(&Giant);
#endif
mtx_lock_spin(&sched_lock);
td->td_priority = kg->kg_user_pri;
if (ke->ke_flags & KEF_NEEDRESCHED) {
DROP_GIANT();
setrunqueue(td);
p->p_stats->p_ru.ru_nivcsw++;
mi_switch();
mtx_unlock_spin(&sched_lock);
PICKUP_GIANT();
mtx_lock(&Giant);
PROC_LOCK(p);
while ((sig = CURSIG(p)) != 0)
postsig(sig);
mtx_unlock(&Giant);
PROC_UNLOCK(p);
/*
* XXX we cheat slightly on the locking here to avoid locking in
* the usual case. Setting td_priority here is essentially an
* incomplete workaround for not setting it properly elsewhere.
* Now that some interrupt handlers are threads, not setting it
* properly elsewhere can clobber it in the window between setting
* it here and returning to user mode, so don't waste time setting
* it perfectly here.
*/
if (td->td_priority != kg->kg_user_pri) {
mtx_lock_spin(&sched_lock);
td->td_priority = kg->kg_user_pri;
mtx_unlock_spin(&sched_lock);
}
/*
* Charge system time if profiling.
*
* XXX should move PS_PROFIL to a place that can obviously be
* accessed safely without sched_lock.
*/
if (p->p_sflag & PS_PROFIL) {
quad_t ticks;
mtx_lock_spin(&sched_lock);
ticks = ke->ke_sticks - oticks;
mtx_unlock_spin(&sched_lock);
addupc_task(ke, TRAPF_PC(frame), (u_int)ticks * psratio);
} else
mtx_unlock_spin(&sched_lock);
}
}
/*
@ -122,9 +127,11 @@ ast(framep)
struct thread *td = curthread;
struct proc *p = td->td_proc;
struct kse *ke = td->td_kse;
struct ksegrp *kg = td->td_ksegrp;
u_int prticks, sticks;
int sflag;
int flags;
int sig;
#if defined(DEV_NPX) && !defined(SMP)
int ucode;
#endif
@ -135,6 +142,7 @@ ast(framep)
panic("Returning to user mode with mutex(s) held");
#endif
mtx_assert(&Giant, MA_NOTOWNED);
mtx_assert(&sched_lock, MA_NOTOWNED);
prticks = 0; /* XXX: Quiet warning. */
td->td_frame = framep;
/*
@ -148,8 +156,8 @@ ast(framep)
sticks = ke->ke_sticks;
sflag = p->p_sflag;
flags = ke->ke_flags;
p->p_sflag &= ~(PS_PROFPEND | PS_ALRMPEND);
ke->ke_flags &= ~(KEF_OWEUPC | KEF_ASTPENDING);
p->p_sflag &= ~(PS_ALRMPEND | PS_NEEDSIGCHK | PS_PROFPEND);
ke->ke_flags &= ~(KEF_ASTPENDING | KEF_NEEDRESCHED | KEF_OWEUPC);
cnt.v_soft++;
if (flags & KEF_OWEUPC && sflag & PS_PROFIL) {
prticks = p->p_stats->p_prof.pr_ticks;
@ -181,6 +189,22 @@ ast(framep)
psignal(p, SIGPROF);
PROC_UNLOCK(p);
}
if (flags & KEF_NEEDRESCHED) {
mtx_lock_spin(&sched_lock);
td->td_priority = kg->kg_user_pri;
setrunqueue(td);
p->p_stats->p_ru.ru_nivcsw++;
mi_switch();
mtx_unlock_spin(&sched_lock);
}
if (sflag & PS_NEEDSIGCHK) {
mtx_lock(&Giant);
PROC_LOCK(p);
while ((sig = CURSIG(p)) != 0)
postsig(sig);
PROC_UNLOCK(p);
mtx_unlock(&Giant);
}
userret(td, framep, sticks);
#ifdef DIAGNOSTIC

View File

@ -662,6 +662,7 @@ osigreturn(td, uap)
SIGSETOLD(p->p_sigmask, scp->sc_mask);
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
regs->tf_ebp = scp->sc_fp;
regs->tf_esp = scp->sc_sp;
@ -771,6 +772,7 @@ sigreturn(td, uap)
p->p_sigmask = ucp->uc_sigmask;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
return (EJUSTRETURN);
}

View File

@ -662,6 +662,7 @@ osigreturn(td, uap)
SIGSETOLD(p->p_sigmask, scp->sc_mask);
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
regs->tf_ebp = scp->sc_fp;
regs->tf_esp = scp->sc_sp;
@ -771,6 +772,7 @@ sigreturn(td, uap)
p->p_sigmask = ucp->uc_sigmask;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
return (EJUSTRETURN);
}

View File

@ -508,6 +508,7 @@ sigreturn(struct thread *td, struct sigreturn_args *uap)
p->p_sigmask = uc.uc_sigmask;
SIG_CANTMASK(p->p_sigmask);
signotify(p);
PROC_UNLOCK(p);
CTR4(KTR_SIG, "sigreturn: return td=%p pc=%#lx sp=%#lx tstate=%#lx",
td, tf->tf_tpc, tf->tf_sp, tf->tf_tstate);

View File

@ -503,6 +503,7 @@ struct proc {
#define PS_PROFPEND 0x00040 /* Pending SIGPROF needs to be posted. */
#define PS_SWAPINREQ 0x00100 /* Swapin request due to wakeup. */
#define PS_SWAPPING 0x00200 /* Process is being swapped. */
#define PS_NEEDSIGCHK 0x02000 /* Process may need signal delivery. */
/* flags kept in td_flags */
#define TDF_ONRUNQ 0x00001 /* This KE is on a run queue */
@ -565,15 +566,6 @@ sigonstack(size_t sp)
: 0);
}
/*
* Notify the current process (p) that it has a signal pending,
* process as soon as possible.
*/
#define signotify(ke) do { \
mtx_assert(&sched_lock, MA_OWNED); \
(ke)->ke_flags |= KEF_ASTPENDING; \
} while (0)
/* Handy macro to determine if p1 can mangle p2. */
#define PRISON_CHECK(p1, p2) \
((p1)->p_prison == NULL || (p1)->p_prison == (p2)->p_prison)

View File

@ -233,6 +233,7 @@ void postsig(int sig);
void psignal(struct proc *p, int sig);
void sigexit(struct thread *td, int signum) __dead2;
void siginit(struct proc *p);
void signotify(struct proc *p);
void trapsignal(struct proc *p, int sig, u_long code);
/*