diff options
author | kib <kib@FreeBSD.org> | 2015-07-18 09:02:50 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2015-07-18 09:02:50 +0000 |
commit | 48ccbdea817fb25a05eb4024844eec6ec81249a7 (patch) | |
tree | 5d1411f5124df7d1ff8fb76e514e51a232fa0406 /sys/kern/kern_exit.c | |
parent | cad9ad69e50ec0e79836106ef79f5c6e37973b3d (diff) | |
download | FreeBSD-src-48ccbdea817fb25a05eb4024844eec6ec81249a7.zip FreeBSD-src-48ccbdea817fb25a05eb4024844eec6ec81249a7.tar.gz |
The si_status field of the siginfo_t, provided by the waitid(2) and
SIGCHLD signal, should keep full 32 bits of the status passed to the
_exit(2).
Split the combined p_xstat of the struct proc into the separate exit
status p_xexit for normal process exit, and signalled termination
information p_xsig. Kernel-visible macro KW_EXITCODE() reconstructs
old p_xstat from p_xexit and p_xsig. p_xexit contains complete status
and copied out into si_status.
Requested by: Joerg Schilling
Reviewed by: jilles (previous version), pho
Tested by: pho
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/kern/kern_exit.c')
-rw-r--r-- | sys/kern/kern_exit.c | 52 |
1 files changed, 28 insertions, 24 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 8fe968e..3310d1d 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -175,7 +175,7 @@ void sys_sys_exit(struct thread *td, struct sys_exit_args *uap) { - exit1(td, W_EXITCODE(uap->rval, 0)); + exit1(td, uap->rval, 0); /* NOTREACHED */ } @@ -185,13 +185,14 @@ sys_sys_exit(struct thread *td, struct sys_exit_args *uap) * and rusage for wait(). Check for child processes and orphan them. */ void -exit1(struct thread *td, int rv) +exit1(struct thread *td, int rval, int signo) { struct proc *p, *nq, *q, *t; struct thread *tdt; struct vnode *ttyvp = NULL; mtx_assert(&Giant, MA_NOTOWNED); + KASSERT(rval == 0 || signo == 0, ("exit1 rv %d sig %d", rval, signo)); p = td->td_proc; /* @@ -200,8 +201,7 @@ exit1(struct thread *td, int rv) * shutdown on sparc64 when the gmirror worker process exists. */ if (p == initproc && rebooting == 0) { - printf("init died (signal %d, exit %d)\n", - WTERMSIG(rv), WEXITSTATUS(rv)); + printf("init died (signal %d, exit %d)\n", signo, rval); panic("Going nowhere without my init!"); } @@ -257,6 +257,11 @@ exit1(struct thread *td, int rv) KASSERT(p->p_numthreads == 1, ("exit1: proc %p exiting with %d threads", p, p->p_numthreads)); racct_sub(p, RACCT_NTHR, 1); + + /* Let event handler change exit status */ + p->p_xexit = rval; + p->p_xsig = signo; + /* * Wakeup anyone in procfs' PIOCWAIT. They should have a hold * on our vmspace, so we should block below until they have @@ -264,7 +269,7 @@ exit1(struct thread *td, int rv) * requested S_EXIT stops we will block here until they ack * via PIOCCONT. */ - _STOPEVENT(p, S_EXIT, rv); + _STOPEVENT(p, S_EXIT, 0); /* * Ignore any pending request to stop due to a stop signal. @@ -289,7 +294,6 @@ exit1(struct thread *td, int rv) while (p->p_lock > 0) msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0); - p->p_xstat = rv; /* Let event handler change exit status */ PROC_UNLOCK(p); /* Drain the limit callout while we don't have the proc locked */ callout_drain(&p->p_limco); @@ -301,7 +305,7 @@ exit1(struct thread *td, int rv) * it was. The exit status is WEXITSTATUS(rv), but it's not clear * what the return value is. */ - AUDIT_ARG_EXIT(WEXITSTATUS(rv), 0); + AUDIT_ARG_EXIT(rval, 0); AUDIT_SYSCALL_EXIT(0, td); #endif @@ -322,7 +326,8 @@ exit1(struct thread *td, int rv) /* * Check if any loadable modules need anything done at process exit. - * E.g. SYSV IPC stuff + * E.g. SYSV IPC stuff. + * Event handler could change exit status. * XXX what if one of these generates an error? */ EVENTHANDLER_INVOKE(process_exit, p); @@ -332,7 +337,6 @@ exit1(struct thread *td, int rv) * P_PPWAIT is set; we will wakeup the parent below. */ PROC_LOCK(p); - rv = p->p_xstat; /* Event handler could change exit status */ stopprofclock(p); p->p_flag &= ~(P_TRACED | P_PPWAIT | P_PPTRACE); @@ -561,9 +565,9 @@ exit1(struct thread *td, int rv) #ifdef KDTRACE_HOOKS int reason = CLD_EXITED; - if (WCOREDUMP(rv)) + if (WCOREDUMP(signo)) reason = CLD_DUMPED; - else if (WIFSIGNALED(rv)) + else if (WIFSIGNALED(signo)) reason = CLD_KILLED; SDT_PROBE(proc, kernel, , exit, reason, 0, 0, 0, 0); #endif @@ -742,7 +746,7 @@ out: sbuf_finish(sb); log(LOG_INFO, "%s", sbuf_data(sb)); sbuf_delete(sb); - exit1(td, W_EXITCODE(0, sig)); + exit1(td, 0, sig); return (0); } @@ -841,7 +845,7 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options) PROC_SUNLOCK(p); if (status) - *status = p->p_xstat; /* convert to int */ + *status = KW_EXITCODE(p->p_xexit, p->p_xsig); if (options & WNOWAIT) { /* * Only poll, returning the status. Caller does not wish to @@ -905,7 +909,7 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options) * nothing can reach this process anymore. As such further locking * is unnecessary. */ - p->p_xstat = 0; /* XXX: why? */ + p->p_xexit = p->p_xsig = 0; /* XXX: why? */ PROC_LOCK(q); ruadd(&q->p_stats->p_cru, &q->p_crux, &p->p_ru, &p->p_rux); @@ -1064,15 +1068,15 @@ 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_xsig)) { siginfo->si_code = CLD_DUMPED; - siginfo->si_status = WTERMSIG(p->p_xstat); - } else if (WIFSIGNALED(p->p_xstat)) { + siginfo->si_status = WTERMSIG(p->p_xsig); + } else if (WIFSIGNALED(p->p_xsig)) { siginfo->si_code = CLD_KILLED; - siginfo->si_status = WTERMSIG(p->p_xstat); + siginfo->si_status = WTERMSIG(p->p_xsig); } else { siginfo->si_code = CLD_EXITED; - siginfo->si_status = WEXITSTATUS(p->p_xstat); + siginfo->si_status = p->p_xexit; } siginfo->si_pid = p->p_pid; @@ -1223,9 +1227,9 @@ loop: sx_xunlock(&proctree_lock); if (status != NULL) - *status = W_STOPCODE(p->p_xstat); + *status = W_STOPCODE(p->p_xsig); if (siginfo != NULL) { - siginfo->si_status = p->p_xstat; + siginfo->si_status = p->p_xsig; siginfo->si_code = CLD_TRAPPED; } if ((options & WNOWAIT) == 0) { @@ -1236,7 +1240,7 @@ loop: CTR4(KTR_PTRACE, "wait: returning trapped pid %d status %#x (xstat %d) xthread %d", - p->p_pid, W_STOPCODE(p->p_xstat), p->p_xstat, + p->p_pid, W_STOPCODE(p->p_xsig), p->p_xsig, p->p_xthread != NULL ? p->p_xthread->td_tid : -1); PROC_UNLOCK(p); td->td_retval[0] = pid; @@ -1252,9 +1256,9 @@ loop: sx_xunlock(&proctree_lock); if (status != NULL) - *status = W_STOPCODE(p->p_xstat); + *status = W_STOPCODE(p->p_xsig); if (siginfo != NULL) { - siginfo->si_status = p->p_xstat; + siginfo->si_status = p->p_xsig; siginfo->si_code = CLD_STOPPED; } if ((options & WNOWAIT) == 0) { |