summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_sig.c
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2005-04-19 08:11:28 +0000
committerdavidxu <davidxu@FreeBSD.org>2005-04-19 08:11:28 +0000
commit913d50be4f7a504fccc225b02332779ccf41a5be (patch)
treed99227ec181130a6116e223dfb758d2137d8b9b3 /sys/kern/kern_sig.c
parent02615ff23a48b27178d931718a5a2e57e770175c (diff)
downloadFreeBSD-src-913d50be4f7a504fccc225b02332779ccf41a5be.zip
FreeBSD-src-913d50be4f7a504fccc225b02332779ccf41a5be.tar.gz
Oops, forgot to update this file.
Fix a race condition between kern_wait() and thread_stopped(). Problem is in kern_wait(), parent process steps through children list, once a child process is skipped, and later even if the child is stopped, parent process still sleeps in msleep(), the race happens if parent masked SIGCHLD. Submitted by : Peter Edwards peadar.edwards at gmail dot com MFC after : 4 days
Diffstat (limited to 'sys/kern/kern_sig.c')
-rw-r--r--sys/kern/kern_sig.c26
1 files changed, 9 insertions, 17 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 71427d7..1cd5ca7 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -85,7 +85,6 @@ static char *expand_name(const char *, uid_t, pid_t);
static int killpg1(struct thread *td, int sig, int pgid, int all);
static int issignal(struct thread *p);
static int sigprop(int sig);
-static void stop(struct proc *);
static void tdsigwakeup(struct thread *td, int sig, sig_t action);
static int filt_sigattach(struct knote *kn);
static void filt_sigdetach(struct knote *kn);
@@ -2250,21 +2249,6 @@ issignal(td)
}
/*
- * Put the argument process into the stopped state and notify the parent
- * via wakeup. Signals are handled elsewhere. The process must not be
- * on the run queue. Must be called with the proc p locked.
- */
-static void
-stop(struct proc *p)
-{
-
- PROC_LOCK_ASSERT(p, MA_OWNED);
- p->p_flag |= P_STOPPED_SIG;
- p->p_flag &= ~P_WAITED;
- wakeup(p->p_pptr);
-}
-
-/*
* MPSAFE
*/
void
@@ -2281,8 +2265,16 @@ thread_stopped(struct proc *p)
n++;
if ((p->p_flag & P_STOPPED_SIG) && (n == p->p_numthreads)) {
mtx_unlock_spin(&sched_lock);
- stop(p);
+ p->p_flag &= ~P_WAITED;
PROC_LOCK(p->p_pptr);
+ /*
+ * Wake up parent sleeping in kern_wait(), also send
+ * SIGCHLD to parent, but SIGCHLD does not guarantee
+ * that parent will awake, because parent may masked
+ * the signal.
+ */
+ p->p_pptr->p_flag |= P_STATCHILD;
+ wakeup(p->p_pptr);
ps = p->p_pptr->p_sigacts;
mtx_lock(&ps->ps_mtx);
if ((ps->ps_flag & PS_NOCLDSTOP) == 0) {
OpenPOWER on IntegriCloud