diff options
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/init_main.c | 11 | ||||
-rw-r--r-- | sys/kern/kern_condvar.c | 6 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 25 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 24 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 38 | ||||
-rw-r--r-- | sys/kern/kern_kthread.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 10 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 242 | ||||
-rw-r--r-- | sys/kern/kern_synch.c | 4 | ||||
-rw-r--r-- | sys/kern/subr_trap.c | 2 | ||||
-rw-r--r-- | sys/kern/tty.c | 4 | ||||
-rw-r--r-- | sys/kern/tty_pty.c | 2 |
12 files changed, 216 insertions, 156 deletions
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 83fca78..6caec77 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -90,7 +90,6 @@ struct proc proc0; struct thread thread0; struct kse kse0; struct ksegrp ksegrp0; -static struct procsig procsig0; static struct filedesc0 filedesc0; static struct plimit limit0; struct vmspace vmspace0; @@ -399,9 +398,8 @@ proc0_init(void *dummy __unused) #endif td->td_ucred = crhold(p->p_ucred); - /* Create procsig. */ - p->p_procsig = &procsig0; - p->p_procsig->ps_refcnt = 1; + /* Create sigacts. */ + p->p_sigacts = sigacts_alloc(); /* Initialize signal state for process 0. */ siginit(&proc0); @@ -441,11 +439,10 @@ proc0_init(void *dummy __unused) vmspace0.vm_map.pmap = vmspace_pmap(&vmspace0); /* - * We continue to place resource usage info and signal - * actions in the user struct so they're pageable. + * We continue to place resource usage info + * in the user struct so that it's pageable. */ p->p_stats = &p->p_uarea->u_stats; - p->p_sigacts = &p->p_uarea->u_sigacts; /* * Charge root for one process. diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c index 160434b..7852234 100644 --- a/sys/kern/kern_condvar.c +++ b/sys/kern/kern_condvar.c @@ -146,7 +146,9 @@ cv_switch_catch(struct thread *td) mtx_unlock_spin(&sched_lock); p = td->td_proc; PROC_LOCK(p); + mtx_lock(&p->p_sigacts->ps_mtx); sig = cursig(td); + mtx_unlock(&p->p_sigacts->ps_mtx); if (thread_suspend_check(1)) sig = SIGSTOP; mtx_lock_spin(&sched_lock); @@ -283,6 +285,7 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp) mtx_unlock_spin(&sched_lock); PROC_LOCK(p); + mtx_lock(&p->p_sigacts->ps_mtx); if (sig == 0) sig = cursig(td); /* XXXKSE */ if (sig != 0) { @@ -291,6 +294,7 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp) else rval = ERESTART; } + mtx_unlock(&p->p_sigacts->ps_mtx); if (p->p_flag & P_WEXIT) rval = EINTR; PROC_UNLOCK(p); @@ -446,6 +450,7 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) mtx_unlock_spin(&sched_lock); PROC_LOCK(p); + mtx_lock(&p->p_sigacts->ps_mtx); if (sig == 0) sig = cursig(td); if (sig != 0) { @@ -454,6 +459,7 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) else rval = ERESTART; } + mtx_unlock(&p->p_sigacts->ps_mtx); if (p->p_flag & P_WEXIT) rval = EINTR; PROC_UNLOCK(p); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 7f5c819..a453152 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -163,7 +163,7 @@ kern_execve(td, fname, argv, envv, mac_p) struct vattr attr; int (*img_first)(struct image_params *); struct pargs *oldargs = NULL, *newargs = NULL; - struct procsig *oldprocsig, *newprocsig; + struct sigacts *oldsigacts, *newsigacts; #ifdef KTRACE struct vnode *tracevp = NULL; struct ucred *tracecred = NULL; @@ -409,23 +409,16 @@ interpret: * reset. */ PROC_LOCK(p); - mp_fixme("procsig needs a lock"); - if (p->p_procsig->ps_refcnt > 1) { - oldprocsig = p->p_procsig; + if (sigacts_shared(p->p_sigacts)) { + oldsigacts = p->p_sigacts; PROC_UNLOCK(p); - MALLOC(newprocsig, struct procsig *, sizeof(struct procsig), - M_SUBPROC, M_WAITOK); - bcopy(oldprocsig, newprocsig, sizeof(*newprocsig)); - newprocsig->ps_refcnt = 1; - oldprocsig->ps_refcnt--; + newsigacts = sigacts_alloc(); + sigacts_copy(newsigacts, oldsigacts); PROC_LOCK(p); - p->p_procsig = newprocsig; - if (p->p_sigacts == &p->p_uarea->u_sigacts) - panic("shared procsig but private sigacts?"); + p->p_sigacts = newsigacts; + } else + oldsigacts = NULL; - p->p_uarea->u_sigacts = *p->p_sigacts; - p->p_sigacts = &p->p_uarea->u_sigacts; - } /* Stop profiling */ stopprofclock(p); @@ -624,6 +617,8 @@ done1: pargs_drop(oldargs); if (newargs != NULL) pargs_drop(newargs); + if (oldsigacts != NULL) + sigacts_free(oldsigacts); exec_fail_dealloc: diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index b77c1d9..2adfa9c 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -431,9 +431,11 @@ exit1(struct thread *td, int rv) * 1 instead (and hope it will handle this situation). */ PROC_LOCK(p->p_pptr); - if (p->p_pptr->p_procsig->ps_flag & (PS_NOCLDWAIT | PS_CLDSIGIGN)) { + mtx_lock(&p->p_pptr->p_sigacts->ps_mtx); + if (p->p_pptr->p_sigacts->ps_flag & (PS_NOCLDWAIT | PS_CLDSIGIGN)) { struct proc *pp; + mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); pp = p->p_pptr; PROC_UNLOCK(pp); proc_reparent(p, initproc); @@ -445,7 +447,8 @@ exit1(struct thread *td, int rv) */ if (LIST_EMPTY(&pp->p_children)) wakeup(pp); - } + } else + mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); if (p->p_sigparent && p->p_pptr != initproc) psignal(p->p_pptr, p->p_sigparent); @@ -656,23 +659,14 @@ loop: (void)chgproccnt(p->p_ucred->cr_ruidinfo, -1, 0); /* - * Free up credentials. + * Free credentials, arguments, and sigacts */ crfree(p->p_ucred); - p->p_ucred = NULL; /* XXX: why? */ - - /* - * Remove unused arguments - */ + p->p_ucred = NULL; pargs_drop(p->p_args); p->p_args = NULL; - - if (--p->p_procsig->ps_refcnt == 0) { - if (p->p_sigacts != &p->p_uarea->u_sigacts) - FREE(p->p_sigacts, M_SUBPROC); - FREE(p->p_procsig, M_SUBPROC); - p->p_procsig = NULL; - } + sigacts_free(p->p_sigacts); + p->p_sigacts = NULL; /* * do any thread-system specific cleanups diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 17387f8..0ba17ce 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -214,7 +214,6 @@ fork1(td, flags, pages, procp) struct kse *ke2; struct ksegrp *kg2; struct sigacts *newsigacts; - struct procsig *newprocsig; int error; /* Can't copy and clear */ @@ -412,15 +411,10 @@ again: /* * Malloc things while we don't hold any locks. */ - if (flags & RFSIGSHARE) { - MALLOC(newsigacts, struct sigacts *, - sizeof(struct sigacts), M_SUBPROC, M_WAITOK); - newprocsig = NULL; - } else { + if (flags & RFSIGSHARE) newsigacts = NULL; - MALLOC(newprocsig, struct procsig *, sizeof(struct procsig), - M_SUBPROC, M_WAITOK); - } + else + newsigacts = sigacts_alloc(); /* * Copy filedesc. @@ -477,7 +471,7 @@ again: /* * Duplicate sub-structures as needed. * Increase reference counts on shared objects. - * The p_stats and p_sigacts substructs are set in vm_forkproc. + * The p_stats substruct is set in vm_forkproc. */ p2->p_flag = 0; if (p1->p_flag & P_PROFIL) @@ -497,25 +491,10 @@ again: pargs_hold(p2->p_args); if (flags & RFSIGSHARE) { - p2->p_procsig = p1->p_procsig; - p2->p_procsig->ps_refcnt++; - if (p1->p_sigacts == &p1->p_uarea->u_sigacts) { - /* - * Set p_sigacts to the new shared structure. - * Note that this is updating p1->p_sigacts at the - * same time, since p_sigacts is just a pointer to - * the shared p_procsig->ps_sigacts. - */ - p2->p_sigacts = newsigacts; - newsigacts = NULL; - *p2->p_sigacts = p1->p_uarea->u_sigacts; - } + p2->p_sigacts = sigacts_hold(p1->p_sigacts); } else { - p2->p_procsig = newprocsig; - newprocsig = NULL; - bcopy(p1->p_procsig, p2->p_procsig, sizeof(*p2->p_procsig)); - p2->p_procsig->ps_refcnt = 1; - p2->p_sigacts = NULL; /* finished in vm_forkproc() */ + sigacts_copy(newsigacts, p1->p_sigacts); + p2->p_sigacts = newsigacts; } if (flags & RFLINUXTHPN) p2->p_sigparent = SIGUSR1; @@ -647,9 +626,6 @@ again: p2->p_acflag = AFORK; PROC_UNLOCK(p2); - KASSERT(newprocsig == NULL, ("unused newprocsig")); - if (newsigacts != NULL) - FREE(newsigacts, M_SUBPROC); /* * Finish creating the child process. It will return via a different * execution path later. (ie: directly into user mode) diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c index d4846dd..7d38520 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -94,7 +94,9 @@ kthread_create(void (*func)(void *), void *arg, /* this is a non-swapped system process */ PROC_LOCK(p2); p2->p_flag |= P_SYSTEM | P_KTHREAD; - p2->p_procsig->ps_flag |= PS_NOCLDWAIT; + mtx_lock(&p2->p_sigacts->ps_mtx); + p2->p_sigacts->ps_flag |= PS_NOCLDWAIT; + mtx_unlock(&p2->p_sigacts->ps_mtx); _PHOLD(p2); PROC_UNLOCK(p2); diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 6810537..7665674 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -623,6 +623,7 @@ fill_kinfo_proc(p, kp) struct tty *tp; struct session *sp; struct timeval tv; + struct sigacts *ps; td = FIRST_THREAD_IN_PROC(p); @@ -653,9 +654,12 @@ fill_kinfo_proc(p, kp) kp->ki_rgid = p->p_ucred->cr_rgid; kp->ki_svgid = p->p_ucred->cr_svgid; } - if (p->p_procsig) { - kp->ki_sigignore = p->p_procsig->ps_sigignore; - kp->ki_sigcatch = p->p_procsig->ps_sigcatch; + if (p->p_sigacts) { + ps = p->p_sigacts; + mtx_lock(&ps->ps_mtx); + kp->ki_sigignore = ps->ps_sigignore; + kp->ki_sigcatch = ps->ps_sigcatch; + mtx_unlock(&ps->ps_mtx); } mtx_lock_spin(&sched_lock); if (p->p_state != PRS_NEW && diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index dd2fb3e..abe10df 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -181,6 +181,7 @@ int cursig(struct thread *td) { PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); + mtx_assert(&td->td_proc->p_sigacts->ps_mtx, MA_OWNED); mtx_assert(&sched_lock, MA_NOTOWNED); return (SIGPENDING(td) ? issignal(td) : 0); } @@ -267,16 +268,16 @@ kern_sigaction(td, sig, act, oact, flags) struct sigaction *act, *oact; int flags; { - register struct sigacts *ps; + struct sigacts *ps; struct thread *td0; struct proc *p = td->td_proc; if (!_SIG_VALID(sig)) return (EINVAL); - mtx_lock(&Giant); PROC_LOCK(p); ps = p->p_sigacts; + mtx_lock(&ps->ps_mtx); if (oact) { oact->sa_handler = ps->ps_sigact[_SIG_IDX(sig)]; oact->sa_mask = ps->ps_catchmask[_SIG_IDX(sig)]; @@ -291,16 +292,16 @@ kern_sigaction(td, sig, act, oact, flags) oact->sa_flags |= SA_NODEFER; if (SIGISMEMBER(ps->ps_siginfo, sig)) oact->sa_flags |= SA_SIGINFO; - if (sig == SIGCHLD && p->p_procsig->ps_flag & PS_NOCLDSTOP) + if (sig == SIGCHLD && ps->ps_flag & PS_NOCLDSTOP) oact->sa_flags |= SA_NOCLDSTOP; - if (sig == SIGCHLD && p->p_procsig->ps_flag & PS_NOCLDWAIT) + if (sig == SIGCHLD && ps->ps_flag & PS_NOCLDWAIT) oact->sa_flags |= SA_NOCLDWAIT; } if (act) { if ((sig == SIGKILL || sig == SIGSTOP) && act->sa_handler != SIG_DFL) { + mtx_unlock(&ps->ps_mtx); PROC_UNLOCK(p); - mtx_unlock(&Giant); return (EINVAL); } @@ -342,9 +343,9 @@ kern_sigaction(td, sig, act, oact, flags) #endif if (sig == SIGCHLD) { if (act->sa_flags & SA_NOCLDSTOP) - p->p_procsig->ps_flag |= PS_NOCLDSTOP; + ps->ps_flag |= PS_NOCLDSTOP; else - p->p_procsig->ps_flag &= ~PS_NOCLDSTOP; + ps->ps_flag &= ~PS_NOCLDSTOP; if (act->sa_flags & SA_NOCLDWAIT) { /* * Paranoia: since SA_NOCLDWAIT is implemented @@ -353,20 +354,20 @@ kern_sigaction(td, sig, act, oact, flags) * is forbidden to set SA_NOCLDWAIT. */ if (p->p_pid == 1) - p->p_procsig->ps_flag &= ~PS_NOCLDWAIT; + ps->ps_flag &= ~PS_NOCLDWAIT; else - p->p_procsig->ps_flag |= PS_NOCLDWAIT; + ps->ps_flag |= PS_NOCLDWAIT; } else - p->p_procsig->ps_flag &= ~PS_NOCLDWAIT; + ps->ps_flag &= ~PS_NOCLDWAIT; if (ps->ps_sigact[_SIG_IDX(SIGCHLD)] == SIG_IGN) - p->p_procsig->ps_flag |= PS_CLDSIGIGN; + ps->ps_flag |= PS_CLDSIGIGN; else - p->p_procsig->ps_flag &= ~PS_CLDSIGIGN; + ps->ps_flag &= ~PS_CLDSIGIGN; } /* - * Set bit in p_sigignore for signals that are set to SIG_IGN, + * Set bit in ps_sigignore for signals that are set to SIG_IGN, * and for signals set to SIG_DFL where the default is to - * ignore. However, don't put SIGCONT in p_sigignore, as we + * ignore. However, don't put SIGCONT in ps_sigignore, as we * have to restart the process. */ if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || @@ -378,14 +379,14 @@ kern_sigaction(td, sig, act, oact, flags) SIGDELSET(td0->td_siglist, sig); if (sig != SIGCONT) /* easier in psignal */ - SIGADDSET(p->p_sigignore, sig); - SIGDELSET(p->p_sigcatch, sig); + SIGADDSET(ps->ps_sigignore, sig); + SIGDELSET(ps->ps_sigcatch, sig); } else { - SIGDELSET(p->p_sigignore, sig); + SIGDELSET(ps->ps_sigignore, sig); if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL) - SIGDELSET(p->p_sigcatch, sig); + SIGDELSET(ps->ps_sigcatch, sig); else - SIGADDSET(p->p_sigcatch, sig); + SIGADDSET(ps->ps_sigcatch, sig); } #ifdef COMPAT_FREEBSD4 if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || @@ -404,8 +405,8 @@ kern_sigaction(td, sig, act, oact, flags) SIGADDSET(ps->ps_osigset, sig); #endif } + mtx_unlock(&ps->ps_mtx); PROC_UNLOCK(p); - mtx_unlock(&Giant); return (0); } @@ -543,11 +544,15 @@ siginit(p) struct proc *p; { register int i; + struct sigacts *ps; PROC_LOCK(p); + ps = p->p_sigacts; + mtx_lock(&ps->ps_mtx); for (i = 1; i <= NSIG; i++) if (sigprop(i) & SA_IGNORE && i != SIGCONT) - SIGADDSET(p->p_sigignore, i); + SIGADDSET(ps->ps_sigignore, i); + mtx_unlock(&ps->ps_mtx); PROC_UNLOCK(p); } @@ -568,12 +573,13 @@ execsigs(p) */ PROC_LOCK_ASSERT(p, MA_OWNED); ps = p->p_sigacts; - while (SIGNOTEMPTY(p->p_sigcatch)) { - sig = sig_ffs(&p->p_sigcatch); - SIGDELSET(p->p_sigcatch, sig); + mtx_lock(&ps->ps_mtx); + while (SIGNOTEMPTY(ps->ps_sigcatch)) { + sig = sig_ffs(&ps->ps_sigcatch); + SIGDELSET(ps->ps_sigcatch, sig); if (sigprop(sig) & SA_IGNORE) { if (sig != SIGCONT) - SIGADDSET(p->p_sigignore, sig); + SIGADDSET(ps->ps_sigignore, sig); SIGDELSET(p->p_siglist, sig); /* * There is only one thread at this point. @@ -597,9 +603,10 @@ execsigs(p) /* * Reset no zombies if child dies flag as Solaris does. */ - p->p_procsig->ps_flag &= ~(PS_NOCLDWAIT | PS_CLDSIGIGN); + ps->ps_flag &= ~(PS_NOCLDWAIT | PS_CLDSIGIGN); if (ps->ps_sigact[_SIG_IDX(SIGCHLD)] == SIG_IGN) ps->ps_sigact[_SIG_IDX(SIGCHLD)] = SIG_DFL; + mtx_unlock(&ps->ps_mtx); } /* @@ -822,14 +829,13 @@ kern_sigtimedwait(struct thread *td, sigset_t set, siginfo_t *info, sig = 0; SIG_CANTMASK(set); - mtx_lock(&Giant); PROC_LOCK(p); - ps = p->p_sigacts; oldmask = td->td_sigmask; td->td_sigmask = set; signotify(td); + mtx_lock(&ps->ps_mtx); sig = cursig(td); if (sig) goto out; @@ -850,7 +856,9 @@ kern_sigtimedwait(struct thread *td, sigset_t set, siginfo_t *info, } else hz = 0; + mtx_unlock(&ps->ps_mtx); error = msleep(ps, &p->p_mtx, PPAUSE|PCATCH, "pause", hz); + mtx_lock(&ps->ps_mtx); if (error == EINTR) error = 0; else if (error) @@ -863,6 +871,7 @@ out: sig_t action; action = ps->ps_sigact[_SIG_IDX(sig)]; + mtx_unlock(&ps->ps_mtx); #ifdef KTRACE if (KTRPOINT(td, KTR_PSIG)) ktrpsig(sig, action, td->td_flags & TDF_OLDMASK ? @@ -877,11 +886,9 @@ out: SIGDELSET(td->td_siglist, sig); info->si_signo = sig; info->si_code = 0; - } - + } else + mtx_unlock(&ps->ps_mtx); PROC_UNLOCK(p); - mtx_unlock(&Giant); - return (error); } @@ -1330,39 +1337,30 @@ kill(td, uap) register struct kill_args *uap; { register struct proc *p; - int error = 0; + int error; if ((u_int)uap->signum > _SIG_MAXSIG) return (EINVAL); - mtx_lock(&Giant); if (uap->pid > 0) { /* kill single process */ - if ((p = pfind(uap->pid)) == NULL) { - error = ESRCH; - } else if ((error = p_cansignal(td, p, uap->signum)) != 0) { - PROC_UNLOCK(p); - } else { - if (uap->signum) - psignal(p, uap->signum); - PROC_UNLOCK(p); - error = 0; - } - } else { - switch (uap->pid) { - case -1: /* broadcast signal */ - error = killpg1(td, uap->signum, 0, 1); - break; - case 0: /* signal own process group */ - error = killpg1(td, uap->signum, 0, 0); - break; - default: /* negative explicit process group */ - error = killpg1(td, uap->signum, -uap->pid, 0); - break; - } + if ((p = pfind(uap->pid)) == NULL) + return (ESRCH); + error = p_cansignal(td, p, uap->signum); + if (error == 0 && uap->signum) + psignal(p, uap->signum); + PROC_UNLOCK(p); + return (error); + } + switch (uap->pid) { + case -1: /* broadcast signal */ + return (killpg1(td, uap->signum, 0, 1)); + case 0: /* signal own process group */ + return (killpg1(td, uap->signum, 0, 0)); + default: /* negative explicit process group */ + return (killpg1(td, uap->signum, -uap->pid, 0)); } - mtx_unlock(&Giant); - return(error); + /* NOTREACHED */ } #if defined(COMPAT_43) || defined(COMPAT_SUNOS) @@ -1381,14 +1379,10 @@ okillpg(td, uap) struct thread *td; register struct okillpg_args *uap; { - int error; if ((u_int)uap->signum > _SIG_MAXSIG) return (EINVAL); - mtx_lock(&Giant); - error = killpg1(td, uap->signum, uap->pgid, 0); - mtx_unlock(&Giant); - return (error); + return (killpg1(td, uap->signum, uap->pgid, 0)); } #endif /* COMPAT_43 || COMPAT_SUNOS */ @@ -1451,7 +1445,8 @@ trapsignal(struct thread *td, int sig, u_long code) PROC_LOCK(p); ps = p->p_sigacts; - if ((p->p_flag & P_TRACED) == 0 && SIGISMEMBER(p->p_sigcatch, sig) && + mtx_lock(&ps->ps_mtx); + if ((p->p_flag & P_TRACED) == 0 && SIGISMEMBER(ps->ps_sigcatch, sig) && !SIGISMEMBER(td->td_sigmask, sig)) { p->p_stats->p_ru.ru_nsignals++; #ifdef KTRACE @@ -1468,13 +1463,15 @@ trapsignal(struct thread *td, int sig, u_long code) /* * See kern_sigaction() for origin of this code. */ - SIGDELSET(p->p_sigcatch, sig); + SIGDELSET(ps->ps_sigcatch, sig); if (sig != SIGCONT && sigprop(sig) & SA_IGNORE) - SIGADDSET(p->p_sigignore, sig); + SIGADDSET(ps->ps_sigignore, sig); ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; } + mtx_unlock(&ps->ps_mtx); } else { + mtx_unlock(&ps->ps_mtx); p->p_code = code; /* XXX for core dump/debugger */ p->p_sig = sig; /* XXX to verify code */ tdsignal(td, sig); @@ -1528,6 +1525,8 @@ sigtd(struct proc *p, int sig, int prop) * regardless of the signal action (eg, blocked or ignored). * * Other ignored signals are discarded immediately. + * + * MPSAFE */ void psignal(struct proc *p, int sig) @@ -1546,6 +1545,9 @@ psignal(struct proc *p, int sig) tdsignal(td, sig); } +/* + * MPSAFE + */ void tdsignal(struct thread *td, int sig) { @@ -1554,12 +1556,13 @@ tdsignal(struct thread *td, int sig) sigset_t *siglist; struct thread *td0; register int prop; - + struct sigacts *ps; KASSERT(_SIG_VALID(sig), ("tdsignal(): invalid signal %d\n", sig)); p = td->td_proc; + ps = p->p_sigacts; PROC_LOCK_ASSERT(p, MA_OWNED); KNOTE(&p->p_klist, NOTE_SIGNAL | sig); @@ -1586,18 +1589,23 @@ tdsignal(struct thread *td, int sig) /* * If the signal is being ignored, * then we forget about it immediately. - * (Note: we don't set SIGCONT in p_sigignore, + * (Note: we don't set SIGCONT in ps_sigignore, * and if it is set to SIG_IGN, * action will be SIG_DFL here.) */ - if (SIGISMEMBER(p->p_sigignore, sig) || (p->p_flag & P_WEXIT)) + mtx_lock(&ps->ps_mtx); + if (SIGISMEMBER(ps->ps_sigignore, sig) || + (p->p_flag & P_WEXIT)) { + mtx_unlock(&ps->ps_mtx); return; + } if (SIGISMEMBER(td->td_sigmask, sig)) action = SIG_HOLD; - else if (SIGISMEMBER(p->p_sigcatch, sig)) + else if (SIGISMEMBER(ps->ps_sigcatch, sig)) action = SIG_CATCH; else action = SIG_DFL; + mtx_unlock(&ps->ps_mtx); } if (prop & SA_CONT) { @@ -1890,13 +1898,14 @@ issignal(td) struct thread *td; { struct proc *p; + struct sigacts *ps; sigset_t sigpending; register int sig, prop; p = td->td_proc; + ps = p->p_sigacts; + mtx_assert(&ps->ps_mtx, MA_OWNED); PROC_LOCK_ASSERT(p, MA_OWNED); - WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &p->p_mtx.mtx_object, - "Checking for signals"); for (;;) { int traced = (p->p_flag & P_TRACED) || (p->p_stops & S_SIG); @@ -1916,7 +1925,7 @@ issignal(td) * We should see pending but ignored signals * only if P_TRACED was on when they were posted. */ - if (SIGISMEMBER(p->p_sigignore, sig) && (traced == 0)) { + if (SIGISMEMBER(ps->ps_sigignore, sig) && (traced == 0)) { SIGDELSET(td->td_siglist, sig); continue; } @@ -1924,6 +1933,9 @@ issignal(td) /* * If traced, always stop. */ + mtx_unlock(&ps->ps_mtx); + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, + &p->p_mtx.mtx_object, "Stopping for traced signal"); p->p_xstat = sig; PROC_LOCK(p->p_pptr); psignal(p->p_pptr, SIGCHLD); @@ -1938,11 +1950,12 @@ issignal(td) mtx_unlock_spin(&sched_lock); PICKUP_GIANT(); PROC_LOCK(p); + mtx_lock(&ps->ps_mtx); /* * If the traced bit got turned off, go back up * to the top to rescan signals. This ensures - * that p_sig* and ps_sigact are consistent. + * that p_sig* and p_sigacts are consistent. */ if ((p->p_flag & P_TRACED) == 0) continue; @@ -2001,6 +2014,9 @@ issignal(td) (p->p_pgrp->pg_jobc == 0 && prop & SA_TTYSTOP)) break; /* == ignore */ + mtx_unlock(&ps->ps_mtx); + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, + &p->p_mtx.mtx_object, "Catching SIGSTOP"); p->p_flag |= P_STOPPED_SIG; p->p_xstat = sig; mtx_lock_spin(&sched_lock); @@ -2013,6 +2029,7 @@ issignal(td) mtx_unlock_spin(&sched_lock); PICKUP_GIANT(); PROC_LOCK(p); + mtx_lock(&ps->ps_mtx); break; } else if (prop & SA_IGNORE) { /* @@ -2063,10 +2080,14 @@ stop(struct proc *p) wakeup(p->p_pptr); } +/* + * MPSAFE + */ void thread_stopped(struct proc *p) { struct proc *p1 = curthread->td_proc; + struct sigacts *ps; int n; PROC_LOCK_ASSERT(p, MA_OWNED); @@ -2078,10 +2099,13 @@ thread_stopped(struct proc *p) mtx_unlock_spin(&sched_lock); stop(p); PROC_LOCK(p->p_pptr); - if ((p->p_pptr->p_procsig->ps_flag & - PS_NOCLDSTOP) == 0) { + ps = p->p_pptr->p_sigacts; + mtx_lock(&ps->ps_mtx); + if ((ps->ps_flag & PS_NOCLDSTOP) == 0) { + mtx_unlock(&ps->ps_mtx); psignal(p->p_pptr, SIGCHLD); - } + } else + mtx_unlock(&ps->ps_mtx); PROC_UNLOCK(p->p_pptr); mtx_lock_spin(&sched_lock); } @@ -2106,6 +2130,7 @@ postsig(sig) PROC_LOCK_ASSERT(p, MA_OWNED); ps = p->p_sigacts; + mtx_assert(&ps->ps_mtx, MA_OWNED); SIGDELSET(td->td_siglist, sig); action = ps->ps_sigact[_SIG_IDX(sig)]; #ifdef KTRACE @@ -2120,6 +2145,7 @@ postsig(sig) * Default action, where the default is to kill * the process. (Other cases were ignored above.) */ + mtx_unlock(&ps->ps_mtx); sigexit(td, sig); /* NOTREACHED */ } else { @@ -2153,10 +2179,10 @@ postsig(sig) /* * See kern_sigaction() for origin of this code. */ - SIGDELSET(p->p_sigcatch, sig); + SIGDELSET(ps->ps_sigcatch, sig); if (sig != SIGCONT && sigprop(sig) & SA_IGNORE) - SIGADDSET(p->p_sigignore, sig); + SIGADDSET(ps->ps_sigignore, sig); ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; } p->p_stats->p_ru.ru_nsignals++; @@ -2199,6 +2225,8 @@ killproc(p, why) * signal state. Mark the accounting record with the signal termination. * If dumping core, save the signal number for the debugger. Calls exit and * does not return. + * + * MPSAFE */ void sigexit(td, sig) @@ -2443,11 +2471,9 @@ nosys(td, args) { struct proc *p = td->td_proc; - mtx_lock(&Giant); PROC_LOCK(p); psignal(p, SIGSYS); PROC_UNLOCK(p); - mtx_unlock(&Giant); return (ENOSYS); } @@ -2532,3 +2558,57 @@ filt_signal(struct knote *kn, long hint) } return (kn->kn_data != 0); } + +struct sigacts * +sigacts_alloc(void) +{ + struct sigacts *ps; + + ps = malloc(sizeof(struct sigacts), M_SUBPROC, M_WAITOK | M_ZERO); + ps->ps_refcnt = 1; + mtx_init(&ps->ps_mtx, "sigacts", NULL, MTX_DEF); + return (ps); +} + +void +sigacts_free(struct sigacts *ps) +{ + + mtx_lock(&ps->ps_mtx); + ps->ps_refcnt--; + if (ps->ps_refcnt == 0) { + mtx_destroy(&ps->ps_mtx); + free(ps, M_SUBPROC); + } else + mtx_unlock(&ps->ps_mtx); +} + +struct sigacts * +sigacts_hold(struct sigacts *ps) +{ + mtx_lock(&ps->ps_mtx); + ps->ps_refcnt++; + mtx_unlock(&ps->ps_mtx); + return (ps); +} + +void +sigacts_copy(struct sigacts *dest, struct sigacts *src) +{ + + KASSERT(dest->ps_refcnt == 1, ("sigacts_copy to shared dest")); + mtx_lock(&src->ps_mtx); + bcopy(src, dest, offsetof(struct sigacts, ps_refcnt)); + mtx_unlock(&src->ps_mtx); +} + +int +sigacts_shared(struct sigacts *ps) +{ + int shared; + + mtx_lock(&ps->ps_mtx); + shared = ps->ps_refcnt > 1; + mtx_unlock(&ps->ps_mtx); + return (shared); +} diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index d648e9e..fbf6ed3 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -230,7 +230,9 @@ msleep(ident, mtx, priority, wmesg, timo) td->td_flags |= TDF_SINTR; mtx_unlock_spin(&sched_lock); PROC_LOCK(p); + mtx_lock(&p->p_sigacts->ps_mtx); sig = cursig(td); + mtx_unlock(&p->p_sigacts->ps_mtx); if (sig == 0 && thread_suspend_check(1)) sig = SIGSTOP; mtx_lock_spin(&sched_lock); @@ -291,12 +293,14 @@ msleep(ident, mtx, priority, wmesg, timo) if (rval == 0 && catch) { PROC_LOCK(p); /* XXX: shouldn't we always be calling cursig() */ + mtx_lock(&p->p_sigacts->ps_mtx); if (sig != 0 || (sig = cursig(td))) { if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) rval = EINTR; else rval = ERESTART; } + mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); } #ifdef KTRACE diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index b2fc0fc..9eaa5b8 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -245,10 +245,12 @@ ast(struct trapframe *framep) sigs = 0; PROC_LOCK(p); + mtx_lock(&p->p_sigacts->ps_mtx); while ((sig = cursig(td)) != 0) { postsig(sig); sigs++; } + mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); if (p->p_flag & P_THREADED && sigs) { struct kse_upcall *ku = td->td_upcall; diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 33ecd6e..0b543f1 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -776,7 +776,7 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag) sx_slock(&proctree_lock); PROC_LOCK(p); while (isbackground(p, tp) && !(p->p_flag & P_PPWAIT) && - !SIGISMEMBER(p->p_sigignore, SIGTTOU) && + !SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTOU) && !SIGISMEMBER(td->td_sigmask, SIGTTOU)) { pgrp = p->p_pgrp; PROC_UNLOCK(p); @@ -1934,7 +1934,7 @@ loop: PROC_LOCK(p); if (isbackground(p, tp) && ISSET(tp->t_lflag, TOSTOP) && !(p->p_flag & P_PPWAIT) && - !SIGISMEMBER(p->p_sigignore, SIGTTOU) && + !SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTOU) && !SIGISMEMBER(td->td_sigmask, SIGTTOU)) { if (p->p_pgrp->pg_jobc == 0) { PROC_UNLOCK(p); diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index b104e6b..eadcf08 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -235,7 +235,7 @@ again: while (isbackground(p, tp)) { sx_slock(&proctree_lock); PROC_LOCK(p); - if (SIGISMEMBER(p->p_sigignore, SIGTTIN) || + if (SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTIN) || SIGISMEMBER(td->td_sigmask, SIGTTIN) || p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT) { PROC_UNLOCK(p); |