diff options
author | jilles <jilles@FreeBSD.org> | 2014-01-01 20:22:29 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2014-01-01 20:22:29 +0000 |
commit | f948fdf9e9c8f3e33fa0b06ffba7d6fccc436694 (patch) | |
tree | 444e613ddde85e05d25deb24f27b98693ebbb2ba /sys/kern | |
parent | e876d4736cec7a72c621f94d97df99a81f04693a (diff) | |
download | FreeBSD-src-f948fdf9e9c8f3e33fa0b06ffba7d6fccc436694.zip FreeBSD-src-f948fdf9e9c8f3e33fa0b06ffba7d6fccc436694.tar.gz |
MFC r258281: Fix siginfo_t.si_status for wait6/waitid/SIGCHLD.
Per POSIX, si_status should contain the value passed to exit() for
si_code==CLD_EXITED and the signal number for other si_code. This was
incorrect for CLD_EXITED and CLD_DUMPED.
This is still not fully POSIX-compliant (Austin group issue #594 says that
the full value passed to exit() shall be returned via si_status, not just
the low 8 bits) but is sufficient for a si_status-related test in libnih
(upstart, Debian/kFreeBSD).
PR: kern/184002
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_exit.c | 11 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 19 |
2 files changed, 18 insertions, 12 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index f0be10e..1a68bf5 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -974,16 +974,19 @@ proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id, * This is still a rough estimate. We will fix the * cases TRAPPED, STOPPED, and CONTINUED later. */ - if (WCOREDUMP(p->p_xstat)) + if (WCOREDUMP(p->p_xstat)) { siginfo->si_code = CLD_DUMPED; - else if (WIFSIGNALED(p->p_xstat)) + siginfo->si_status = WTERMSIG(p->p_xstat); + } else if (WIFSIGNALED(p->p_xstat)) { siginfo->si_code = CLD_KILLED; - else + siginfo->si_status = WTERMSIG(p->p_xstat); + } else { siginfo->si_code = CLD_EXITED; + siginfo->si_status = WEXITSTATUS(p->p_xstat); + } siginfo->si_pid = p->p_pid; siginfo->si_uid = p->p_ucred->cr_uid; - siginfo->si_status = p->p_xstat; /* * The si_addr field would be useful additional diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 1797ebc..ea4ac26 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -2959,7 +2959,7 @@ sigparent(struct proc *p, int reason, int status) } static void -childproc_jobstate(struct proc *p, int reason, int status) +childproc_jobstate(struct proc *p, int reason, int sig) { struct sigacts *ps; @@ -2979,7 +2979,7 @@ childproc_jobstate(struct proc *p, int reason, int status) mtx_lock(&ps->ps_mtx); if ((ps->ps_flag & PS_NOCLDSTOP) == 0) { mtx_unlock(&ps->ps_mtx); - sigparent(p, reason, status); + sigparent(p, reason, sig); } else mtx_unlock(&ps->ps_mtx); } @@ -2987,6 +2987,7 @@ childproc_jobstate(struct proc *p, int reason, int status) void childproc_stopped(struct proc *p, int reason) { + /* p_xstat is a plain signal number, not a full wait() status here. */ childproc_jobstate(p, reason, p->p_xstat); } @@ -3000,13 +3001,15 @@ void childproc_exited(struct proc *p) { int reason; - int status = p->p_xstat; /* convert to int */ + int xstat = p->p_xstat; /* convert to int */ + int status; - reason = CLD_EXITED; - if (WCOREDUMP(status)) - reason = CLD_DUMPED; - else if (WIFSIGNALED(status)) - reason = CLD_KILLED; + if (WCOREDUMP(xstat)) + reason = CLD_DUMPED, status = WTERMSIG(xstat); + else if (WIFSIGNALED(xstat)) + reason = CLD_KILLED, status = WTERMSIG(xstat); + else + reason = CLD_EXITED, status = WEXITSTATUS(xstat); /* * XXX avoid calling wakeup(p->p_pptr), the work is * done in exit1(). |