summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2003-05-13 20:36:02 +0000
committerjhb <jhb@FreeBSD.org>2003-05-13 20:36:02 +0000
commit89a4eb17deddba4ba8bfb0cf7c6801a608731f8c (patch)
tree0e2ba79e40f08e96bb98756b67576ff96caccfbc /sys/kern
parent3b9288c6f4df2bfdc2a41de3ae161246c310e064 (diff)
downloadFreeBSD-src-89a4eb17deddba4ba8bfb0cf7c6801a608731f8c.zip
FreeBSD-src-89a4eb17deddba4ba8bfb0cf7c6801a608731f8c.tar.gz
- Merge struct procsig with struct sigacts.
- Move struct sigacts out of the u-area and malloc() it using the M_SUBPROC malloc bucket. - Add a small sigacts_*() API for managing sigacts structures: sigacts_alloc(), sigacts_free(), sigacts_copy(), sigacts_share(), and sigacts_shared(). - Remove the p_sigignore, p_sigacts, and p_sigcatch macros. - Add a mutex to struct sigacts that protects all the members of the struct. - Add sigacts locking. - Remove Giant from nosys(), kill(), killpg(), and kern_sigaction() now that sigacts is locked. - Several in-kernel functions such as psignal(), tdsignal(), trapsignal(), and thread_stopped() are now MP safe. Reviewed by: arch@ Approved by: re (rwatson)
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/init_main.c11
-rw-r--r--sys/kern/kern_condvar.c6
-rw-r--r--sys/kern/kern_exec.c25
-rw-r--r--sys/kern/kern_exit.c24
-rw-r--r--sys/kern/kern_fork.c38
-rw-r--r--sys/kern/kern_kthread.c4
-rw-r--r--sys/kern/kern_proc.c10
-rw-r--r--sys/kern/kern_sig.c242
-rw-r--r--sys/kern/kern_synch.c4
-rw-r--r--sys/kern/subr_trap.c2
-rw-r--r--sys/kern/tty.c4
-rw-r--r--sys/kern/tty_pty.c2
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);
OpenPOWER on IntegriCloud