diff --git a/sys/alpha/alpha/machdep.c b/sys/alpha/alpha/machdep.c
index 1efc6b9eedb9..c9b2caf13d39 100644
--- a/sys/alpha/alpha/machdep.c
+++ b/sys/alpha/alpha/machdep.c
@@ -1133,11 +1133,13 @@ osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	td = curthread;
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
+	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
+
 	frame = td->td_frame;
-	oonstack = sigonstack(alpha_pal_rdusp());
 	fsize = sizeof ksi;
 	rndfsize = ((fsize + 15) / 16) * 16;
-	psp = p->p_sigacts;
+	oonstack = sigonstack(alpha_pal_rdusp());
 
 	/*
 	 * Allocate and validate space for the signal handler
@@ -1155,6 +1157,7 @@ osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 #endif
 	} else
 		sip = (osiginfo_t *)(alpha_pal_rdusp() - rndfsize);
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -1210,7 +1213,8 @@ osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	frame->tf_regs[FRAME_A0] = sig;
 	frame->tf_regs[FRAME_FLAGS] = 0; /* full restore */
 	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig))
+	mtx_lock(&psp->ps_mtx);
+	if (SIGISMEMBER(psp->ps_siginfo, sig))
 		frame->tf_regs[FRAME_A1] = (u_int64_t)sip;
 	else
 		frame->tf_regs[FRAME_A1] = code;
@@ -1235,6 +1239,7 @@ freebsd4_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 
 	frame = td->td_frame;
 	oonstack = sigonstack(alpha_pal_rdusp());
@@ -1276,6 +1281,7 @@ freebsd4_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 #endif
 	} else
 		sfp = (struct sigframe4 *)(alpha_pal_rdusp() - rndfsize);
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/* save the floating-point state, if necessary, then copy it. */
@@ -1311,7 +1317,8 @@ freebsd4_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	frame->tf_regs[FRAME_PC] = PS_STRINGS - szfreebsd4_sigcode;
 	frame->tf_regs[FRAME_A0] = sig;
 	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	mtx_lock(&psp->ps_mtx);
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		frame->tf_regs[FRAME_A1] = (u_int64_t)&(sfp->sf_si);
 
 		/* Fill in POSIX parts */
@@ -1343,6 +1350,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 #ifdef COMPAT_FREEBSD4
 	if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
 		freebsd4_sendsig(catcher, sig, mask, code);
@@ -1397,6 +1405,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 #endif
 	} else
 		sfp = (struct sigframe *)(alpha_pal_rdusp() - rndfsize);
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/* save the floating-point state, if necessary, then copy it. */
@@ -1432,7 +1441,8 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	frame->tf_regs[FRAME_PC] = PS_STRINGS - szsigcode;
 	frame->tf_regs[FRAME_A0] = sig;
 	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	mtx_lock(&psp->ps_mtx);
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		frame->tf_regs[FRAME_A1] = (u_int64_t)&(sfp->sf_si);
 
 		/* Fill in POSIX parts */
diff --git a/sys/alpha/osf1/osf1_signal.c b/sys/alpha/osf1/osf1_signal.c
index bc3e06c9d95d..4ba7e86f849e 100644
--- a/sys/alpha/osf1/osf1_signal.c
+++ b/sys/alpha/osf1/osf1_signal.c
@@ -471,6 +471,7 @@ osf1_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 
 	frame = td->td_frame;
 	oonstack = sigonstack(alpha_pal_rdusp());
@@ -490,6 +491,7 @@ osf1_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 		p->p_sigstk.ss_flags |= SS_ONSTACK;
 	} else
 		sip = (osiginfo_t *)(alpha_pal_rdusp() - rndfsize);
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -551,6 +553,7 @@ osf1_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	frame->tf_regs[FRAME_FLAGS] = 0;   	/* full restore */
 	alpha_pal_wrusp((unsigned long)sip);
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index cafc80bb1fa7..b72725665192 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -235,6 +235,7 @@ sendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_rsp);
 
@@ -262,7 +263,6 @@ sendsig(catcher, sig, mask, code)
 		sp = (char *)regs->tf_rsp - sizeof(struct sigframe) - 128;
 	/* Align to 16 bytes. */
 	sfp = (struct sigframe *)((unsigned long)sp & ~0xF);
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -271,8 +271,7 @@ sendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	regs->tf_rdi = sig;			/* arg 1 in %rdi */
 	regs->tf_rdx = (register_t)&sfp->sf_uc;	/* arg 3 in %rdx */
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		regs->tf_rsi = (register_t)&sfp->sf_si;	/* arg 2 in %rsi */
 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
@@ -287,6 +286,7 @@ sendsig(catcher, sig, mask, code)
 		regs->tf_rcx = regs->tf_addr;	/* arg 4 in %rcx */
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -305,6 +305,7 @@ sendsig(catcher, sig, mask, code)
 	regs->tf_rflags &= ~PSL_T;
 	regs->tf_cs = _ucodesel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 /*
diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index 033346ba694d..14f9aebdd02e 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -547,6 +547,7 @@ linprocfs_doprocstatus(PFS_FILL_ARGS)
 	char *state;
 	segsz_t lsize;
 	struct thread *td2;
+	struct sigacts *ps;
 	int i;
 
 	PROC_LOCK(p);
@@ -653,8 +654,11 @@ linprocfs_doprocstatus(PFS_FILL_ARGS)
 	 * relation to struct proc, so SigBlk is left unimplemented.
 	 */
 	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
-	sbuf_printf(sb, "SigIgn:\t%08x\n",	p->p_sigignore.__bits[0]);
-	sbuf_printf(sb, "SigCgt:\t%08x\n",	p->p_sigcatch.__bits[0]);
+	ps = p->p_sigacts;
+	mtx_lock(&ps->ps_mtx);
+	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
+	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
+	mtx_unlock(&ps->ps_mtx);
 	PROC_UNLOCK(p);
 	
 	/*
diff --git a/sys/compat/svr4/svr4_filio.c b/sys/compat/svr4/svr4_filio.c
index 870da5d0427e..374338f46c7f 100644
--- a/sys/compat/svr4/svr4_filio.c
+++ b/sys/compat/svr4/svr4_filio.c
@@ -132,10 +132,21 @@ svr4_sys_read(td, uap)
      DPRINTF(("svr4_read(%d, 0x%0x, %d) = %d\n", 
 	     uap->fd, uap->buf, uap->nbyte, rv));
      if (rv == EAGAIN) {
+#ifdef DEBUG_SVR4
+       struct sigacts *ps;
+
+       PROC_LOCK(td->td_proc);
+       ps = td->td_proc->p_sigacts;
+       mtx_lock(&ps->ps_mtx);
+#endif
        DPRINTF(("sigmask = 0x%x\n", td->td_sigmask));
-       DPRINTF(("sigignore = 0x%x\n", td->td_proc->p_sigignore));
-       DPRINTF(("sigcaught = 0x%x\n", td->td_proc->p_sigcatch));
+       DPRINTF(("sigignore = 0x%x\n", ps->ps_sigignore));
+       DPRINTF(("sigcaught = 0x%x\n", ps->ps_sigcatch));
        DPRINTF(("siglist = 0x%x\n", td->td_siglist));
+#ifdef DEBUG_SVR4
+       mtx_unlock(&ps->ps_mtx);
+       PROC_UNLOCK(td->td_proc);
+#endif
      }
 
 #if defined(GROTTY_READ_HACK)
diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c
index 81eef6656b1b..22fdc66138cf 100644
--- a/sys/compat/svr4/svr4_misc.c
+++ b/sys/compat/svr4/svr4_misc.c
@@ -1363,12 +1363,8 @@ loop:
 			sx_xunlock(&proctree_lock);
 
 			PROC_LOCK(q);
-			if (--q->p_procsig->ps_refcnt == 0) {
-				if (q->p_sigacts != &q->p_uarea->u_sigacts)
-					FREE(q->p_sigacts, M_SUBPROC);
-				FREE(q->p_procsig, M_SUBPROC);
-				q->p_procsig = NULL;
-			}
+			sigacts_free(q->p_sigacts);
+			q->p_sigacts = NULL;
 			PROC_UNLOCK(q);
 
 			/*
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index e5377d4477e6..912035d9ad54 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -295,6 +295,7 @@ osendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
@@ -308,7 +309,6 @@ osendsig(catcher, sig, mask, code)
 #endif
 	} else
 		fp = (struct osigframe *)regs->tf_esp - 1;
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -317,8 +317,7 @@ osendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_arg2 = (register_t)&fp->sf_siginfo;
 		sf.sf_siginfo.si_signo = sig;
@@ -330,6 +329,7 @@ osendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/* Save most if not all of trap frame. */
@@ -402,6 +402,7 @@ osendsig(catcher, sig, mask, code)
 	load_gs(_udatasel);
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 #endif /* COMPAT_43 */
 
@@ -424,6 +425,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
@@ -447,7 +449,6 @@ freebsd4_sendsig(catcher, sig, mask, code)
 #endif
 	} else
 		sfp = (struct sigframe4 *)regs->tf_esp - 1;
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -456,8 +457,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_ucontext = (register_t)&sfp->sf_uc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_siginfo = (register_t)&sfp->sf_si;
 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
@@ -472,6 +472,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -523,6 +524,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	regs->tf_fs = _udatasel;
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 #endif	/* COMPAT_FREEBSD4 */
 
@@ -545,6 +547,7 @@ sendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 #ifdef COMPAT_FREEBSD4
 	if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
 		freebsd4_sendsig(catcher, sig, mask, code);
@@ -585,7 +588,6 @@ sendsig(catcher, sig, mask, code)
 		sp = (char *)regs->tf_esp - sizeof(struct sigframe);
 	/* Align to 16 bytes. */
 	sfp = (struct sigframe *)((unsigned int)sp & ~0xF);
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -594,8 +596,7 @@ sendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_ucontext = (register_t)&sfp->sf_uc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_siginfo = (register_t)&sfp->sf_si;
 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
@@ -610,6 +611,7 @@ sendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -661,6 +663,7 @@ sendsig(catcher, sig, mask, code)
 	regs->tf_fs = _udatasel;
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 /*
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index 27105bc71b5d..706c944d51c0 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -273,11 +273,14 @@ linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 {
 	struct thread *td = curthread;
 	struct proc *p = td->td_proc;
+	struct sigacts *psp;
 	struct trapframe *regs;
 	struct l_rt_sigframe *fp, frame;
 	int oonstack;
 
 	PROC_LOCK_ASSERT(p, MA_OWNED);
+	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
@@ -290,11 +293,12 @@ linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	 * Allocate space for the signal handler context.
 	 */
 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
-	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
+	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
 		fp = (struct l_rt_sigframe *)(p->p_sigstk.ss_sp +
 		    p->p_sigstk.ss_size - sizeof(struct l_rt_sigframe));
 	} else
 		fp = (struct l_rt_sigframe *)regs->tf_esp - 1;
+	mtx_unlock(&psp->ps_mtx);
 
 	/*
 	 * Build the argument list for the signal handler.
@@ -383,6 +387,7 @@ linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	regs->tf_fs = _udatasel;
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 
@@ -401,13 +406,16 @@ linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 {
 	struct thread *td = curthread;
 	struct proc *p = td->td_proc;
+	struct sigacts *psp;
 	struct trapframe *regs;
 	struct l_sigframe *fp, frame;
 	l_sigset_t lmask;
 	int oonstack, i;
 
 	PROC_LOCK_ASSERT(p, MA_OWNED);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		linux_rt_sendsig(catcher, sig, mask, code);
 		return;
@@ -426,11 +434,12 @@ linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	 * Allocate space for the signal handler context.
 	 */
 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
-	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
+	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
 		fp = (struct l_sigframe *)(p->p_sigstk.ss_sp +
 		    p->p_sigstk.ss_size - sizeof(struct l_sigframe));
 	} else
 		fp = (struct l_sigframe *)regs->tf_esp - 1;
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -494,6 +503,7 @@ linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	regs->tf_fs = _udatasel;
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 /*
diff --git a/sys/i386/svr4/svr4_machdep.c b/sys/i386/svr4/svr4_machdep.c
index d29e37bf45d1..e477629e2c6e 100644
--- a/sys/i386/svr4/svr4_machdep.c
+++ b/sys/i386/svr4/svr4_machdep.c
@@ -428,6 +428,7 @@ svr4_sendsig(catcher, sig, mask, code)
 #endif
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 
 	tf = td->td_frame;
 	oonstack = sigonstack(tf->tf_esp);
@@ -443,6 +444,7 @@ svr4_sendsig(catcher, sig, mask, code)
 	} else {
 		fp = (struct svr4_sigframe *)tf->tf_esp - 1;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/* 
@@ -505,6 +507,7 @@ svr4_sendsig(catcher, sig, mask, code)
 	load_gs(_udatasel);
 	tf->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 #endif
 }
 
diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c
index fafe287097b9..dd3fc590f182 100644
--- a/sys/ia64/ia64/machdep.c
+++ b/sys/ia64/ia64/machdep.c
@@ -756,6 +756,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	frame = td->td_frame;
 	oonstack = sigonstack(frame->tf_r[FRAME_SP]);
 	rndfsize = ((sizeof(sf) + 15) / 16) * 16;
@@ -822,6 +823,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 #endif
 	} else
 		sfp = (struct sigframe *)(frame->tf_r[FRAME_SP] - rndfsize);
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 #ifdef DEBUG
@@ -870,7 +872,8 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	frame->tf_cr_iip = PS_STRINGS - (esigcode - sigcode);
 	frame->tf_r[FRAME_R1] = sig;
 	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	mtx_lock(&psp->ps_mtx);
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		frame->tf_r[FRAME_R15] = (u_int64_t)&(sfp->sf_si);
 
 		/* Fill in POSIX parts */
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 83fca78c4ede..6caec77bec39 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 160434b041fe..7852234f8c26 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 7f5c81938d99..a4531527ec98 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 b77c1d9cc059..2adfa9cf7b9b 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 17387f8bb5c7..0ba17cec3f7a 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 d4846dda9635..7d38520e4382 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 6810537fb121..766567453493 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 dd2fb3ee68ba..abe10df5c302 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);
 	}
-	mtx_unlock(&Giant);
-	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));
+	}
+	/* 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 d648e9e311e9..fbf6ed3275af 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 b2fc0fc5abaa..9eaa5b80307b 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 33ecd6e7de10..0b543f176a59 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 b104e6b76d89..eadcf086f021 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);
diff --git a/sys/netncp/ncp_ncp.c b/sys/netncp/ncp_ncp.c
index 0541793c0ff5..1d29afe2b329 100644
--- a/sys/netncp/ncp_ncp.c
+++ b/sys/netncp/ncp_ncp.c
@@ -88,7 +88,9 @@ ncp_chkintr(struct ncp_conn *conn, struct thread *td)
 	tmpset = p->p_siglist;
 	SIGSETOR(tmpset, td->td_siglist);
 	SIGSETNAND(tmpset, td->td_sigmask);
-	SIGSETNAND(tmpset, p->p_sigignore);
+	mtx_lock(&p->p_sigacts->ps_mtx);
+	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
+	mtx_unlock(&p->p_sigacts->ps_mtx);
 	if (SIGNOTEMPTY(td->td_siglist) && NCP_SIGMASK(tmpset)) {
 		PROC_UNLOCK(p);
                 return EINTR;
diff --git a/sys/netsmb/smb_subr.c b/sys/netsmb/smb_subr.c
index 0e0356054d23..1650ece671df 100644
--- a/sys/netsmb/smb_subr.c
+++ b/sys/netsmb/smb_subr.c
@@ -82,7 +82,9 @@ smb_td_intr(struct thread *td)
 	tmpset = p->p_siglist;
 	SIGSETOR(tmpset, td->td_siglist);
 	SIGSETNAND(tmpset, td->td_sigmask);
-	SIGSETNAND(tmpset, p->p_sigignore);
+	mtx_lock(&p->p_sigacts->ps_mtx);
+	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
+	mtx_unlock(&p->p_sigacts->ps_mtx);
 	if (SIGNOTEMPTY(td->td_siglist) && SMB_SIGMASK(tmpset)) {
 		PROC_UNLOCK(p);
                 return EINTR;
diff --git a/sys/nfsclient/nfs_socket.c b/sys/nfsclient/nfs_socket.c
index 3949b747b56b..aaa2f7ad3120 100644
--- a/sys/nfsclient/nfs_socket.c
+++ b/sys/nfsclient/nfs_socket.c
@@ -1239,7 +1239,9 @@ nfs_sigintr(struct nfsmount *nmp, struct nfsreq *rep, struct thread *td)
 	PROC_LOCK(p);
 	tmpset = p->p_siglist;
 	SIGSETNAND(tmpset, td->td_sigmask);
-	SIGSETNAND(tmpset, p->p_sigignore);
+	mtx_lock(&p->p_sigacts->ps_mtx);
+	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
+	mtx_unlock(&p->p_sigacts->ps_mtx);
 	if (SIGNOTEMPTY(p->p_siglist) && NFSINT_SIGMASK(tmpset)) {
 		PROC_UNLOCK(p);
 		return (EINTR);
diff --git a/sys/pc98/i386/machdep.c b/sys/pc98/i386/machdep.c
index b9013a22da35..4797ae16317b 100644
--- a/sys/pc98/i386/machdep.c
+++ b/sys/pc98/i386/machdep.c
@@ -315,6 +315,7 @@ osendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
@@ -328,7 +329,6 @@ osendsig(catcher, sig, mask, code)
 #endif
 	} else
 		fp = (struct osigframe *)regs->tf_esp - 1;
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -337,8 +337,7 @@ osendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_arg2 = (register_t)&fp->sf_siginfo;
 		sf.sf_siginfo.si_signo = sig;
@@ -350,6 +349,7 @@ osendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/* Save most if not all of trap frame. */
@@ -422,6 +422,7 @@ osendsig(catcher, sig, mask, code)
 	load_gs(_udatasel);
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 #endif /* COMPAT_43 */
 
@@ -444,6 +445,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
@@ -467,7 +469,6 @@ freebsd4_sendsig(catcher, sig, mask, code)
 #endif
 	} else
 		sfp = (struct sigframe4 *)regs->tf_esp - 1;
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -476,8 +477,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_ucontext = (register_t)&sfp->sf_uc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_siginfo = (register_t)&sfp->sf_si;
 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
@@ -492,6 +492,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -543,6 +544,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	regs->tf_fs = _udatasel;
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 #endif	/* COMPAT_FREEBSD4 */
 
@@ -565,6 +567,7 @@ sendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx,.MA_OWNED);
 #ifdef COMPAT_FREEBSD4
 	if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
 		freebsd4_sendsig(catcher, sig, mask, code);
@@ -605,7 +608,6 @@ sendsig(catcher, sig, mask, code)
 		sp = (char *)regs->tf_esp - sizeof(struct sigframe);
 	/* Align to 16 bytes. */
 	sfp = (struct sigframe *)((unsigned int)sp & ~0xF);
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -614,8 +616,7 @@ sendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_ucontext = (register_t)&sfp->sf_uc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_siginfo = (register_t)&sfp->sf_si;
 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
@@ -630,6 +631,7 @@ sendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -681,6 +683,7 @@ sendsig(catcher, sig, mask, code)
 	regs->tf_fs = _udatasel;
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 /*
diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c
index b9013a22da35..4797ae16317b 100644
--- a/sys/pc98/pc98/machdep.c
+++ b/sys/pc98/pc98/machdep.c
@@ -315,6 +315,7 @@ osendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
@@ -328,7 +329,6 @@ osendsig(catcher, sig, mask, code)
 #endif
 	} else
 		fp = (struct osigframe *)regs->tf_esp - 1;
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -337,8 +337,7 @@ osendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_arg2 = (register_t)&fp->sf_siginfo;
 		sf.sf_siginfo.si_signo = sig;
@@ -350,6 +349,7 @@ osendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/* Save most if not all of trap frame. */
@@ -422,6 +422,7 @@ osendsig(catcher, sig, mask, code)
 	load_gs(_udatasel);
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 #endif /* COMPAT_43 */
 
@@ -444,6 +445,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_esp);
 
@@ -467,7 +469,6 @@ freebsd4_sendsig(catcher, sig, mask, code)
 #endif
 	} else
 		sfp = (struct sigframe4 *)regs->tf_esp - 1;
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -476,8 +477,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_ucontext = (register_t)&sfp->sf_uc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_siginfo = (register_t)&sfp->sf_si;
 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
@@ -492,6 +492,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -543,6 +544,7 @@ freebsd4_sendsig(catcher, sig, mask, code)
 	regs->tf_fs = _udatasel;
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 #endif	/* COMPAT_FREEBSD4 */
 
@@ -565,6 +567,7 @@ sendsig(catcher, sig, mask, code)
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx,.MA_OWNED);
 #ifdef COMPAT_FREEBSD4
 	if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
 		freebsd4_sendsig(catcher, sig, mask, code);
@@ -605,7 +608,6 @@ sendsig(catcher, sig, mask, code)
 		sp = (char *)regs->tf_esp - sizeof(struct sigframe);
 	/* Align to 16 bytes. */
 	sfp = (struct sigframe *)((unsigned int)sp & ~0xF);
-	PROC_UNLOCK(p);
 
 	/* Translate the signal if appropriate. */
 	if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
@@ -614,8 +616,7 @@ sendsig(catcher, sig, mask, code)
 	/* Build the argument list for the signal handler. */
 	sf.sf_signum = sig;
 	sf.sf_ucontext = (register_t)&sfp->sf_uc;
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* Signal handler installed with SA_SIGINFO. */
 		sf.sf_siginfo = (register_t)&sfp->sf_si;
 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
@@ -630,6 +631,7 @@ sendsig(catcher, sig, mask, code)
 		sf.sf_addr = regs->tf_err;
 		sf.sf_ahu.sf_handler = catcher;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	/*
@@ -681,6 +683,7 @@ sendsig(catcher, sig, mask, code)
 	regs->tf_fs = _udatasel;
 	regs->tf_ss = _udatasel;
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 /*
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c
index 81fb604a8b2f..62e46e91e2ef 100644
--- a/sys/powerpc/aim/machdep.c
+++ b/sys/powerpc/aim/machdep.c
@@ -408,7 +408,9 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 
 	td = curthread;
 	p = td->td_proc;
+	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	tf = td->td_frame;
 	oonstack = sigonstack(tf->fixreg[1]);
 
@@ -439,7 +441,6 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	} else {
 		sfp = (struct sigframe *)(tf->fixreg[1] - rndfsize);
 	}
-	PROC_UNLOCK(p);
 
 	/* 
 	 * Translate the signal if appropriate (Linux emu ?)
@@ -466,9 +467,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	tf->fixreg[1] = (register_t)sfp;
 	tf->fixreg[FIRSTARG] = sig;
 	tf->fixreg[FIRSTARG+2] = (register_t)&sfp->sf_uc;
-
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* 
 		 * Signal handler installed with SA_SIGINFO.
 		 */
@@ -484,6 +483,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 		/* Old FreeBSD-style arguments. */
 		tf->fixreg[FIRSTARG+1] = code;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	tf->srr0 = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode));
@@ -504,6 +504,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	     tf->srr0, tf->fixreg[1]);
 
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 int
diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c
index 81fb604a8b2f..62e46e91e2ef 100644
--- a/sys/powerpc/powerpc/machdep.c
+++ b/sys/powerpc/powerpc/machdep.c
@@ -408,7 +408,9 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 
 	td = curthread;
 	p = td->td_proc;
+	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	tf = td->td_frame;
 	oonstack = sigonstack(tf->fixreg[1]);
 
@@ -439,7 +441,6 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	} else {
 		sfp = (struct sigframe *)(tf->fixreg[1] - rndfsize);
 	}
-	PROC_UNLOCK(p);
 
 	/* 
 	 * Translate the signal if appropriate (Linux emu ?)
@@ -466,9 +467,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	tf->fixreg[1] = (register_t)sfp;
 	tf->fixreg[FIRSTARG] = sig;
 	tf->fixreg[FIRSTARG+2] = (register_t)&sfp->sf_uc;
-
-	PROC_LOCK(p);
-	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
+	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
 		/* 
 		 * Signal handler installed with SA_SIGINFO.
 		 */
@@ -484,6 +483,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 		/* Old FreeBSD-style arguments. */
 		tf->fixreg[FIRSTARG+1] = code;
 	}
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	tf->srr0 = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode));
@@ -504,6 +504,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	     tf->srr0, tf->fixreg[1]);
 
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 int
diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c
index 6cf0f6af2df8..669f4c7b30f5 100644
--- a/sys/sparc64/sparc64/machdep.c
+++ b/sys/sparc64/sparc64/machdep.c
@@ -403,7 +403,9 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	oonstack = 0;
 	td = curthread;
 	p = td->td_proc;
+	PROC_LOCK_ASSERT(p, MA_OWNED);
 	psp = p->p_sigacts;
+	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	tf = td->td_frame;
 	sp = tf->tf_sp + SPOFF;
 	oonstack = sigonstack(sp);
@@ -437,6 +439,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 		    p->p_sigstk.ss_size - sizeof(struct sigframe));
 	} else
 		sfp = (struct sigframe *)sp - 1;
+	mtx_unlock(&psp->ps_mtx);
 	PROC_UNLOCK(p);
 
 	fp = (struct frame *)sfp - 1;
@@ -476,6 +479,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 	    tf->tf_sp);
 
 	PROC_LOCK(p);
+	mtx_lock(&psp->ps_mtx);
 }
 
 #ifndef	_SYS_SYSPROTO_H_
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 92f97396287a..1b7982c11858 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -102,18 +102,6 @@ struct pgrp {
 	struct mtx	pg_mtx;		/*  Mutex to protect members */
 };
 
-struct procsig {
-	sigset_t ps_sigignore;		/* Signals being ignored. */
-	sigset_t ps_sigcatch;		/* Signals being caught by user. */
-	int	 ps_flag;
-	struct	 sigacts *ps_sigacts;	/* Signal actions, state. */
-	int	 ps_refcnt;
-};
-
-#define	PS_NOCLDWAIT	0x0001	/* No zombies if child dies */
-#define	PS_NOCLDSTOP	0x0002	/* No SIGCHLD when children stop. */
-#define	PS_CLDSIGIGN	0x0004	/* The SIGCHLD handler is SIG_IGN. */
-
 /*
  * pargs, used to hold a copy of the command line, if it had a sane length.
  */
@@ -157,6 +145,7 @@ struct pargs {
  *      o - ktrace lock
  *      p - select lock (sellock)
  *      r - p_peers lock
+ *      x - created at fork, only changes during single threading in exec
  *      z - zombie threads/kse/ksegroup lock
  *
  * If the locking key specifies two identifiers (for example, p_pptr) then
@@ -525,7 +514,7 @@ struct proc {
 	struct pstats	*p_stats;	/* (b) Accounting/statistics (CPU). */
 	struct plimit	*p_limit;	/* (c*) Process limits. */
 	struct vm_object *p_upages_obj; /* (a) Upages object. */
-	struct procsig	*p_procsig;	/* (c) Signal actions, state (CPU). */
+	struct sigacts	*p_sigacts;	/* (x) Signal actions, state (CPU). */
 
 	/*struct ksegrp	p_ksegrp;
 	struct kse	p_kse; */
@@ -614,9 +603,6 @@ struct proc {
 };
 
 #define	p_rlimit	p_limit->pl_rlimit
-#define	p_sigacts	p_procsig->ps_sigacts
-#define	p_sigignore	p_procsig->ps_sigignore
-#define	p_sigcatch	p_procsig->ps_sigcatch
 #define	p_session	p_pgrp->pg_session
 #define	p_pgid		p_pgrp->pg_id
 
diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h
index 1173d7836c75..5635ab2a4e6c 100644
--- a/sys/sys/signalvar.h
+++ b/sys/sys/signalvar.h
@@ -37,6 +37,8 @@
 #ifndef _SYS_SIGNALVAR_H_
 #define	_SYS_SIGNALVAR_H_
 
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
 #include <sys/signal.h>
 
 /*
@@ -45,8 +47,11 @@
  */
 
 /*
- * Process signal actions and state, needed only within the process
- * (not necessarily resident).
+ * Logical process signal actions and state, needed only within the process
+ * The mapping between sigacts and proc structures is 1:1 except for rfork()
+ * processes masquerading as threads which use one structure for the whole
+ * group.  All members are locked by the included mutex.  The reference count
+ * and mutex must be last for the bcopy in sigacts_copy() to work.
  */
 struct sigacts {
 	sig_t	ps_sigact[_SIG_MAXSIG];	/* Disposition of signals. */
@@ -56,11 +61,20 @@ struct sigacts {
 	sigset_t ps_sigreset;		/* Signals that reset when caught. */
 	sigset_t ps_signodefer;		/* Signals not masked while handled. */
 	sigset_t ps_siginfo;		/* Signals that want SA_SIGINFO args. */
-	sigset_t ps_freebsd4;		/* Signals using freebsd4 ucontext. */
+	sigset_t ps_sigignore;		/* Signals being ignored. */
+	sigset_t ps_sigcatch;		/* Signals being caught by user. */
+	sigset_t ps_freebsd4;		/* signals using freebsd4 ucontext. */
 	sigset_t ps_osigset;		/* Signals using <= 3.x osigset_t. */
-	sigset_t ps_usertramp;		/* SunOS compat; libc sigtramp XXX. */
+	sigset_t ps_usertramp;		/* SunOS compat; libc sigtramp. XXX */
+	int	ps_flag;
+	int	ps_refcnt;
+	struct mtx ps_mtx;
 };
 
+#define	PS_NOCLDWAIT	0x0001	/* No zombies if child dies */
+#define	PS_NOCLDSTOP	0x0002	/* No SIGCHLD when children stop. */
+#define	PS_CLDSIGIGN	0x0004	/* The SIGCHLD handler is SIG_IGN. */
+
 #if defined(_KERNEL) && defined(COMPAT_43)
 /*
  * Compatibility.
@@ -243,6 +257,11 @@ void	pgsigio(struct sigio **, int signum, int checkctty);
 void	pgsignal(struct pgrp *pgrp, int sig, int checkctty);
 void	postsig(int sig);
 void	psignal(struct proc *p, int sig);
+struct sigacts *sigacts_alloc(void);
+void	sigacts_copy(struct sigacts *dest, struct sigacts *src);
+void	sigacts_free(struct sigacts *ps);
+struct sigacts *sigacts_hold(struct sigacts *ps);
+int	sigacts_shared(struct sigacts *ps);
 void	sigexit(struct thread *td, int signum) __dead2;
 int	sig_ffs(sigset_t *set);
 void	siginit(struct proc *p);
diff --git a/sys/sys/user.h b/sys/sys/user.h
index 473480aed5f3..a52610f2680f 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -174,7 +174,6 @@ void fill_kinfo_proc(struct proc *, struct kinfo_proc *);
  * when the process isn't running (esp. when swapped out).
  */
 struct user {
-	struct	sigacts u_sigacts;	/* *p_sigacts */
 	struct	pstats u_stats;		/* *p_stats */
 	/*
 	 * Remaining field for a.out core dumps - not valid at other times!
diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c
index cd00c3345c26..3c42ccae5e72 100644
--- a/sys/vm/vm_glue.c
+++ b/sys/vm/vm_glue.c
@@ -441,23 +441,14 @@ vm_forkproc(td, p2, td2, flags)
 
 	/* XXXKSE this is unsatisfactory but should be adequate */
 	up = p2->p_uarea;
+	MPASS(p2->p_sigacts != NULL);
 
 	/*
 	 * p_stats currently points at fields in the user struct
 	 * but not at &u, instead at p_addr. Copy parts of
 	 * p_stats; zero the rest of p_stats (statistics).
-	 *
-	 * If procsig->ps_refcnt is 1 and p2->p_sigacts is NULL we dont' need
-	 * to share sigacts, so we use the up->u_sigacts.
 	 */
 	p2->p_stats = &up->u_stats;
-	if (p2->p_sigacts == NULL) {
-		if (p2->p_procsig->ps_refcnt != 1)
-			printf ("PID:%d NULL sigacts with refcnt not 1!\n",p2->p_pid);
-		p2->p_sigacts = &up->u_sigacts;
-		up->u_sigacts = *p1->p_sigacts;
-	}
-
 	bzero(&up->u_stats.pstat_startzero,
 	    (unsigned) ((caddr_t) &up->u_stats.pstat_endzero -
 		(caddr_t) &up->u_stats.pstat_startzero));
@@ -465,7 +456,6 @@ vm_forkproc(td, p2, td2, flags)
 	    ((caddr_t) &up->u_stats.pstat_endcopy -
 		(caddr_t) &up->u_stats.pstat_startcopy));
 
-
 	/*
 	 * cpu_fork will copy and update the pcb, set up the kernel stack,
 	 * and make the child ready to run.