diff options
author | davidxu <davidxu@FreeBSD.org> | 2005-04-19 08:11:28 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2005-04-19 08:11:28 +0000 |
commit | 913d50be4f7a504fccc225b02332779ccf41a5be (patch) | |
tree | d99227ec181130a6116e223dfb758d2137d8b9b3 /sys/kern/kern_sig.c | |
parent | 02615ff23a48b27178d931718a5a2e57e770175c (diff) | |
download | FreeBSD-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.c | 26 |
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) { |