X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/3a59f0f785bdfca121c5c9afa3d8c56ed4f390bc..ca466baeb91097acf0817cd63a0c33886ca69d31:/sys/kern/kern_sig.c diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 7e36567892..1ea00291ca 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -37,7 +37,7 @@ * * @(#)kern_sig.c 8.7 (Berkeley) 4/18/94 * $FreeBSD: src/sys/kern/kern_sig.c,v 1.72.2.17 2003/05/16 16:34:34 obrien Exp $ - * $DragonFly: src/sys/kern/kern_sig.c,v 1.34 2005/02/20 01:17:44 davidxu Exp $ + * $DragonFly: src/sys/kern/kern_sig.c,v 1.45 2006/05/05 21:15:08 dillon Exp $ */ #include "opt_ktrace.h" @@ -65,6 +65,7 @@ #include #include #include +#include #include @@ -76,7 +77,6 @@ static char *expand_name(const char *, uid_t, pid_t); static int killpg(int sig, int pgid, int all); static int sig_ffs(sigset_t *set); static int sigprop(int sig); -static void stop(struct proc *); #ifdef SMP static void signotify_remote(void *arg); #endif @@ -260,7 +260,7 @@ kern_sigaction(int sig, struct sigaction *act, struct sigaction *oact) /* * Change setting atomically. */ - splhigh(); + crit_enter(); ps->ps_catchmask[_SIG_IDX(sig)] = act->sa_mask; SIG_CANTMASK(ps->ps_catchmask[_SIG_IDX(sig)]); @@ -331,7 +331,7 @@ kern_sigaction(int sig, struct sigaction *act, struct sigaction *oact) SIGADDSET(p->p_sigcatch, sig); } - spl0(); + crit_exit(); } return (0); } @@ -413,8 +413,7 @@ execsigs(struct proc *p) * kern_sigprocmask() - MP SAFE ONLY IF p == curproc * * Manipulate signal mask. This routine is MP SAFE *ONLY* if - * p == curproc. Also remember that in order to remain MP SAFE - * no spl*() calls may be made. + * p == curproc. */ int kern_sigprocmask(int how, sigset_t *set, sigset_t *oset) @@ -629,10 +628,11 @@ killpg(int sig, int pgid, int all) return (ESRCH); } LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { - if (p->p_pid <= 1 || p->p_flag & P_SYSTEM || - p->p_stat == SZOMB || - !CANSIGNAL(p, sig)) + if (p->p_pid <= 1 || + (p->p_flag & (P_SYSTEM | P_ZOMBIE)) || + !CANSIGNAL(p, sig)) { continue; + } nfound++; if (sig) psignal(p, sig); @@ -760,16 +760,11 @@ trapsignal(struct proc *p, int sig, u_long code) * * Other ignored signals are discarded immediately. */ - -/* - * temporary hack to allow checkpoint code to continue to - * be in a module for the moment - */ - void psignal(struct proc *p, int sig) { - int s, prop; + struct lwp *lp = &p->p_lwp; + int prop; sig_t action; if (sig > _SIG_MAXSIG || sig <= 0) { @@ -777,9 +772,9 @@ psignal(struct proc *p, int sig) panic("psignal signal number"); } - s = splhigh(); + crit_enter(); KNOTE(&p->p_klist, NOTE_SIGNAL | sig); - splx(s); + crit_exit(); prop = sigprop(sig); @@ -813,10 +808,12 @@ psignal(struct proc *p, int sig) p->p_nice = NZERO; } + /* + * If continuing, clear any pending STOP signals. + */ if (prop & SA_CONT) SIG_STOPSIGMASK(p->p_siglist); - if (prop & SA_STOP) { /* * If sending a tty stop signal to a member of an orphaned @@ -836,74 +833,111 @@ psignal(struct proc *p, int sig) * Defer further processing for signals which are held, * except that stopped processes must be continued by SIGCONT. */ - if (action == SIG_HOLD && (!(prop & SA_CONT) || p->p_stat != SSTOP)) - return; - s = splhigh(); - switch (p->p_stat) { - case SSLEEP: + if (action == SIG_HOLD) { + if ((prop & SA_CONT) == 0 || (p->p_flag & P_STOPPED) == 0) + return; + } + + crit_enter(); + + /* + * Process is in tsleep and not stopped + */ + if (p->p_stat == SSLEEP && (p->p_flag & P_STOPPED) == 0) { /* - * If process is sleeping uninterruptibly + * If the process is sleeping uninterruptibly * we can't interrupt the sleep... the signal will * be noticed when the process returns through * trap() or syscall(). */ if ((p->p_flag & P_SINTR) == 0) goto out; + /* - * Process is sleeping and traced... make it runnable + * If the process is sleeping and traced, make it runnable * so it can discover the signal in issignal() and stop * for the parent. + * + * If the process is stopped and traced, no further action + * is necessary. */ if (p->p_flag & P_TRACED) goto run; + /* - * If SIGCONT is default (or ignored) and process is - * asleep, we are finished; the process should not - * be awakened. + * If the process is sleeping and SA_CONT, and the signal + * mode is SIG_DFL, then make the process runnable. + * + * However, do *NOT* set P_BREAKTSLEEP. We do not want + * a SIGCONT to terminate an interruptable tsleep early + * and generate a spurious EINTR. */ if ((prop & SA_CONT) && action == SIG_DFL) { SIGDELSET(p->p_siglist, sig); - goto out; + goto run_no_break; } + /* - * When a sleeping process receives a stop - * signal, process immediately if possible. - * All other (caught or default) signals - * cause the process to run. + * If the process is sleeping and receives a STOP signal, + * process immediately if possible. All other (caught or + * default) signals cause the process to run. */ if (prop & SA_STOP) { if (action != SIG_DFL) goto run; + /* - * If a child holding parent blocked, - * stopping could cause deadlock. + * If a child holding parent blocked, stopping + * could cause deadlock. Take no action at this + * time. */ if (p->p_flag & P_PPWAIT) goto out; + + /* + * Do not actually try to manipulate the process + * while it is sleeping, simply set P_STOPPED to + * indicate that it should stop as soon as it safely + * can. + */ SIGDELSET(p->p_siglist, sig); + p->p_flag |= P_STOPPED; + p->p_flag &= ~P_WAITED; p->p_xstat = sig; + wakeup(p->p_pptr); if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) psignal(p->p_pptr, SIGCHLD); - stop(p); goto out; - } else { - goto run; } - /*NOTREACHED*/ - case SSTOP: + + /* + * Otherwise the signal can interrupt the sleep. + */ + goto run; + } + + /* + * Process is in tsleep and is stopped + */ + if (p->p_stat == SSLEEP && (p->p_flag & P_STOPPED)) { /* - * If traced process is already stopped, - * then no further action is necessary. + * If the process is stopped and is being traced, then no + * further action is necessary. */ if (p->p_flag & P_TRACED) goto out; /* - * Kill signal always sets processes running. + * If the process is stopped and receives a KILL signal, + * make the process runnable. */ if (sig == SIGKILL) goto run; + /* + * If the process is stopped and receives a CONT signal, + * then try to make the process runnable again. + */ if (prop & SA_CONT) { /* * If SIGCONT is default (or ignored), we continue the @@ -911,91 +945,86 @@ psignal(struct proc *p, int sig) * it has no further action. If SIGCONT is held, we * continue the process and leave the signal in * p_siglist. If the process catches SIGCONT, let it - * handle the signal itself. If it isn't waiting on - * an event, then it goes back to run state. - * Otherwise, process goes back to sleep state. + * handle the signal itself. */ if (action == SIG_DFL) SIGDELSET(p->p_siglist, sig); if (action == SIG_CATCH) goto run; - if (p->p_wchan == 0) - goto run; - clrrunnable(p, SSLEEP); - goto out; - } - if (prop & SA_STOP) { /* - * Already stopped, don't need to stop again. - * (If we did the shell could get confused.) + * Make runnable but do not break a tsleep unless + * some other signal was pending. */ + goto run_no_break; + } + + /* + * If the process is stopped and receives another STOP + * signal, we do not need to stop it again. If we did + * the shell could get confused. + */ + if (prop & SA_STOP) { SIGDELSET(p->p_siglist, sig); goto out; } /* - * If process is sleeping interruptibly, then simulate a - * wakeup so that when it is continued, it will be made - * runnable and can look at the signal. But don't make - * the process runnable, leave it stopped. + * Otherwise the process is sleeping interruptably but + * is stopped, just set the P_BREAKTSLEEP flag and take + * no further action. The next runnable action will wake + * the process up. */ - if (p->p_wchan && (p->p_flag & P_SINTR)) - unsleep(p->p_thread); + p->p_flag |= P_BREAKTSLEEP; goto out; - default: - /* - * SRUN, SIDL, SZOMB do nothing with the signal, - * other than kicking ourselves if we are running. - * It will either never be noticed, or noticed very soon. - * - * Note that p_thread may be NULL or may not be completely - * initialized if the process is in the SIDL or SZOMB state. - * - * For SMP we may have to forward the request to another cpu. - * YYY the MP lock prevents the target process from moving - * to another cpu, see kern/kern_switch.c - * - * If the target thread is waiting on its message port, - * wakeup the target thread so it can check (or ignore) - * the new signal. YYY needs cleanup. - */ + } + + /* + * Otherwise the process is running + * + * SRUN, SIDL, SZOMB do nothing with the signal, + * other than kicking ourselves if we are running. + * It will either never be noticed, or noticed very soon. + * + * Note that p_thread may be NULL or may not be completely + * initialized if the process is in the SIDL or SZOMB state. + * + * For SMP we may have to forward the request to another cpu. + * YYY the MP lock prevents the target process from moving + * to another cpu, see kern/kern_switch.c + * + * If the target thread is waiting on its message port, + * wakeup the target thread so it can check (or ignore) + * the new signal. YYY needs cleanup. + */ + if (lp == lwkt_preempted_proc()) { + signotify(); + } else if (p->p_stat == SRUN) { + struct thread *td = p->p_thread; + + KASSERT(td != NULL, + ("pid %d NULL p_thread stat %d flags %08x", + p->p_pid, p->p_stat, p->p_flag)); + #ifdef SMP - if (p == lwkt_preempted_proc()) { - signotify(); - } else if (p->p_stat == SRUN) { - struct thread *td = p->p_thread; - - KASSERT(td != NULL, - ("pid %d NULL p_thread stat %d flags %08x", - p->p_pid, p->p_stat, p->p_flag)); - - if (td->td_gd != mycpu) - lwkt_send_ipiq(td->td_gd, signotify_remote, p); - else if (td->td_msgport.mp_flags & MSGPORTF_WAITING) - lwkt_schedule(td); - } -#else - if (p == lwkt_preempted_proc()) { - signotify(); - } else if (p->p_stat == SRUN) { - struct thread *td = p->p_thread; - - KASSERT(td != NULL, - ("pid %d NULL p_thread stat %d flags %08x", - p->p_pid, p->p_stat, p->p_flag)); - - if (td->td_msgport.mp_flags & MSGPORTF_WAITING) - lwkt_schedule(td); - } + if (td->td_gd != mycpu) + lwkt_send_ipiq(td->td_gd, signotify_remote, lp); + else #endif - goto out; + if (td->td_msgport.mp_flags & MSGPORTF_WAITING) + lwkt_schedule(td); } + goto out; /*NOTREACHED*/ run: + /* + * Make runnable and break out of any tsleep as well. + */ + p->p_flag |= P_BREAKTSLEEP; +run_no_break: setrunnable(p); out: - splx(s); + crit_exit(); } #ifdef SMP @@ -1008,12 +1037,12 @@ out: static void signotify_remote(void *arg) { - struct proc *p = arg; + struct lwp *lp = arg; - if (p == lwkt_preempted_proc()) { + if (lp == lwkt_preempted_proc()) { signotify(); } else { - struct thread *td = p->p_thread; + struct thread *td = lp->lwp_thread; if (td->td_msgport.mp_flags & MSGPORTF_WAITING) lwkt_schedule(td); } @@ -1036,8 +1065,8 @@ kern_sigtimedwait(sigset_t waitset, siginfo_t *info, struct timespec *timeout) savedmask = p->p_sigmask; if (timeout) { - if (timeout->tv_sec < 0 || - (timeout->tv_nsec >= 0 && timeout->tv_nsec < 1000000000)) { + if (timeout->tv_sec >= 0 && timeout->tv_nsec >= 0 && + timeout->tv_nsec < 1000000000) { timevalid = 1; getnanouptime(&rts); ets = rts; @@ -1051,6 +1080,7 @@ kern_sigtimedwait(sigset_t waitset, siginfo_t *info, struct timespec *timeout) if ((sig = sig_ffs(&set)) != 0) { SIGFILLSET(p->p_sigmask); SIGDELSET(p->p_sigmask, sig); + SIG_CANTMASK(p->p_sigmask); sig = issignal(p); /* * It may be a STOP signal, in the case, issignal @@ -1113,6 +1143,9 @@ kern_sigtimedwait(sigset_t waitset, siginfo_t *info, struct timespec *timeout) bzero(info, sizeof(*info)); info->si_signo = sig; SIGDELSET(p->p_siglist, sig); /* take the signal! */ + + if (sig == SIGKILL) + sigexit(p, sig); } return (error); } @@ -1201,6 +1234,9 @@ iscaught(struct proc *p) * by checking the pending signal masks in the CURSIG macro.) The normal call * sequence is * + * This routine is called via CURSIG/__cursig and the MP lock might not be + * held. Obtain the MP lock for the duration of the operation. + * * while (sig = CURSIG(curproc)) * postsig(sig); */ @@ -1210,6 +1246,7 @@ issignal(struct proc *p) sigset_t mask; int sig, prop; + get_mplock(); for (;;) { int traced = (p->p_flag & P_TRACED) || (p->p_stops & S_SIG); @@ -1217,8 +1254,10 @@ issignal(struct proc *p) SIGSETNAND(mask, p->p_sigmask); if (p->p_flag & P_PPWAIT) SIG_STOPSIGMASK(mask); - if (!SIGNOTEMPTY(mask)) /* no signal to send */ + if (!SIGNOTEMPTY(mask)) { /* no signal to send */ + rel_mplock(); return (0); + } sig = sig_ffs(&mask); STOPEVENT(p, S_SIG, sig); @@ -1231,17 +1270,24 @@ issignal(struct proc *p) SIGDELSET(p->p_siglist, sig); continue; } - if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) { + if ((p->p_flag & P_TRACED) && (p->p_flag & P_PPWAIT) == 0) { /* - * If traced, always stop, and stay - * stopped until released by the parent. + * If traced, always stop, and stay stopped until + * released by the parent. + * + * NOTE: P_STOPPED may get cleared during the loop, + * but we do not re-notify the parent if we have + * to loop several times waiting for the parent + * to let us continue. */ p->p_xstat = sig; + p->p_flag |= P_STOPPED; + p->p_flag &= ~P_WAITED; psignal(p->p_pptr, SIGCHLD); do { - stop(p); - mi_switch(p); - } while (!trace_req(p) && p->p_flag & P_TRACED); + tstop(p); + } while (!trace_req(p) && (p->p_flag & P_TRACED)); + p->p_flag &= ~P_STOPPED; /* * If parent wants us to take the signal, @@ -1278,7 +1324,6 @@ issignal(struct proc *p) * to clear it from the pending mask. */ switch ((int)(intptr_t)p->p_sigacts->ps_sigact[_SIG_IDX(sig)]) { - case (int)SIG_DFL: /* * Don't take default actions on system processes. @@ -1316,10 +1361,14 @@ issignal(struct proc *p) prop & SA_TTYSTOP)) break; /* == ignore */ p->p_xstat = sig; - stop(p); + p->p_flag |= P_STOPPED; + p->p_flag &= ~P_WAITED; + if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) psignal(p->p_pptr, SIGCHLD); - mi_switch(p); + while (p->p_flag & P_STOPPED) { + tstop(p); + } break; } else if (prop & SA_IGNORE) { /* @@ -1328,6 +1377,7 @@ issignal(struct proc *p) */ break; /* == ignore */ } else { + rel_mplock(); return (sig); } @@ -1349,6 +1399,7 @@ issignal(struct proc *p) * This signal has an action, let * postsig() process it. */ + rel_mplock(); return (sig); } SIGDELSET(p->p_siglist, sig); /* take the signal! */ @@ -1356,19 +1407,6 @@ issignal(struct proc *p) /* NOTREACHED */ } -/* - * Put the argument process into the stopped state and notify the parent - * via wakeup. Signals are handled elsewhere. The process must not be - * on the run queue. - */ -void -stop(struct proc *p) -{ - p->p_stat = SSTOP; - p->p_flag &= ~P_WAITED; - wakeup((caddr_t)p->p_pptr); -} - /* * Take the action for the specified signal * from the current set of pending signals. @@ -1415,7 +1453,7 @@ postsig(int sig) * mask from before the sigsuspend is what we want * restored after the signal processing is completed. */ - splhigh(); + crit_enter(); if (p->p_flag & P_OLDMASK) { returnmask = p->p_oldsigmask; p->p_flag &= ~P_OLDMASK; @@ -1437,7 +1475,7 @@ postsig(int sig) SIGADDSET(p->p_sigignore, sig); ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; } - spl0(); + crit_exit(); p->p_stats->p_ru.ru_nsignals++; if (p->p_sig != sig) { code = 0; @@ -1630,7 +1668,7 @@ coredump(struct proc *p) nd.nl_open_vp = NULL; nlookup_done(&nd); - VOP_UNLOCK(vp, 0, td); + VOP_UNLOCK(vp, 0); lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; @@ -1647,12 +1685,11 @@ coredump(struct proc *p) } VATTR_NULL(&vattr); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vattr.va_size = 0; - VOP_LEASE(vp, td, cred, LEASE_WRITE); VOP_SETATTR(vp, &vattr, cred, td); p->p_acflag |= ACORE; - VOP_UNLOCK(vp, 0, td); + VOP_UNLOCK(vp, 0); error = p->p_sysent->sv_coredump ? p->p_sysent->sv_coredump(p, vp, limit) : ENOSYS;