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
This commit is contained in:
kib 2015-07-18 09:02:50 +00:00
parent cad9ad69e5
commit 48ccbdea81
18 changed files with 99 additions and 74 deletions

View File

@ -362,6 +362,15 @@ field set to
and the
.Fa si_pid
field set to the process ID of the process reporting status.
For the exited process, the
.Fa si_status
field of the
.Dv siginfo_t
structure contains the full 32 bit exit status passed to
.Xr _exit 2 ;
the
.Fa status
argument of other calls only returns 8 lowest bits of the exit status.
.Pp
When the
.Dv WNOHANG
@ -656,13 +665,6 @@ is an extension;
.Tn POSIX
only permits this flag with
.Fn waitid .
.Pp
.Tn POSIX
requires
.Fn waitid
to return the full 32 bits passed to
.Xr _exit 2 ;
this implementation only returns 8 bits like the other calls.
.Sh HISTORY
The
.Fn wait

View File

@ -66,6 +66,8 @@ __FBSDID("$FreeBSD$");
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/conf.h>
#define _WANT_KW_EXITCODE
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -389,7 +391,7 @@ kvm_proclist(kvm_t *kd, int what, int arg, struct proc *p,
kp->ki_siglist = proc.p_siglist;
SIGSETOR(kp->ki_siglist, mtd.td_siglist);
kp->ki_sigmask = mtd.td_sigmask;
kp->ki_xstat = proc.p_xstat;
kp->ki_xstat = KW_EXITCODE(proc.p_xexit, proc.p_xsig);
kp->ki_acflag = proc.p_acflag;
kp->ki_lock = proc.p_lock;
if (proc.p_state != PRS_ZOMBIE) {

View File

@ -57,7 +57,7 @@ cloudabi_sys_proc_exit(struct thread *td,
struct cloudabi_sys_proc_exit_args *uap)
{
exit1(td, W_EXITCODE(uap->rval, 0));
exit1(td, uap->rval, 0);
/* NOTREACHED */
}

View File

@ -398,7 +398,7 @@ linux_exit(struct thread *td, struct linux_exit_args *args)
* exit via pthread_exit() try thr_exit() first.
*/
kern_thr_exit(td);
exit1(td, W_EXITCODE(args->rval, 0));
exit1(td, args->rval, 0);
/* NOTREACHED */
}

View File

@ -1839,7 +1839,7 @@ linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
* SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?)
* as it doesnt occur often.
*/
exit1(td, W_EXITCODE(args->error_code, 0));
exit1(td, args->error_code, 0);
/* NOTREACHED */
}

View File

@ -1277,7 +1277,7 @@ svr4_sys_waitsys(td, uap)
/* Found a zombie, so cache info in local variables. */
pid = p->p_pid;
status = p->p_xstat;
status = KW_EXITCODE(p->p_xexit, p->p_xsig);
ru = p->p_ru;
PROC_STATLOCK(p);
calcru(p, &ru.ru_utime, &ru.ru_stime);
@ -1304,7 +1304,7 @@ svr4_sys_waitsys(td, uap)
p->p_flag |= P_WAITED;
sx_sunlock(&proctree_lock);
pid = p->p_pid;
status = W_STOPCODE(p->p_xstat);
status = W_STOPCODE(p->p_xsig);
ru = p->p_ru;
PROC_STATLOCK(p);
calcru(p, &ru.ru_utime, &ru.ru_stime);

View File

@ -142,7 +142,7 @@ procfs_control(struct thread *td, struct proc *p, int op)
*/
p->p_flag |= P_TRACED;
faultin(p);
p->p_xstat = 0; /* XXX ? */
p->p_xsig = 0; /* XXX ? */
p->p_oppid = p->p_pptr->p_pid;
if (p->p_pptr != td->td_proc) {
proc_reparent(p, td->td_proc);
@ -198,7 +198,7 @@ procfs_control(struct thread *td, struct proc *p, int op)
* To continue with a signal, just send
* the signal name to the ctl file
*/
p->p_xstat = 0;
p->p_xsig = 0;
switch (op) {
/*
@ -340,7 +340,7 @@ procfs_doprocctl(PFS_FILL_ARGS)
PROC_LOCK(p);
if (TRACE_WAIT_P(td->td_proc, p)) {
p->p_xstat = nm->nm_val;
p->p_xsig = nm->nm_val;
#ifdef FIX_SSTEP
FIX_SSTEP(FIRST_THREAD_IN_PROC(p));
#endif

View File

@ -140,7 +140,7 @@ procfs_ioctl(PFS_IOCTL_ARGS)
ps->flags = 0; /* nope */
ps->events = p->p_stops;
ps->why = p->p_step ? p->p_stype : 0;
ps->val = p->p_step ? p->p_xstat : 0;
ps->val = p->p_step ? p->p_xsig : 0;
break;
#ifdef COMPAT_FREEBSD32
case PIOCWAIT32:
@ -160,7 +160,7 @@ procfs_ioctl(PFS_IOCTL_ARGS)
ps32->flags = 0; /* nope */
ps32->events = p->p_stops;
ps32->why = p->p_step ? p->p_stype : 0;
ps32->val = p->p_step ? p->p_xstat : 0;
ps32->val = p->p_step ? p->p_xsig : 0;
break;
#endif
#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
@ -182,7 +182,7 @@ procfs_ioctl(PFS_IOCTL_ARGS)
#if 0
p->p_step = 0;
if (P_SHOULDSTOP(p)) {
p->p_xstat = sig;
p->p_xsig = sig;
p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG);
PROC_SLOCK(p);
thread_unsuspend(p);

View File

@ -436,7 +436,7 @@ filt_proc(struct knote *kn, long hint)
kn->kn_flags |= EV_EOF | EV_ONESHOT;
kn->kn_ptr.p_proc = NULL;
if (kn->kn_fflags & NOTE_EXIT)
kn->kn_data = p->p_xstat;
kn->kn_data = KW_EXITCODE(p->p_xexit, p->p_xsig);
if (kn->kn_fflags == 0)
kn->kn_flags |= EV_DROP;
return (1);

View File

@ -920,7 +920,7 @@ do_execve(td, args, mac_p)
if (error && imgp->vmspace_destroyed) {
/* sorry, no more process anymore. exit gracefully */
exit1(td, W_EXITCODE(0, SIGABRT));
exit1(td, 0, SIGABRT);
/* NOT REACHED */
}

View File

@ -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 @@ sys_abort2(struct thread *td, struct abort2_args *uap)
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 @@ kern_wait6(struct thread *td, idtype_t idtype, id_t id, int *status,
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 @@ kern_wait6(struct thread *td, idtype_t idtype, id_t id, int *status,
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 @@ kern_wait6(struct thread *td, idtype_t idtype, id_t id, int *status,
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) {

View File

@ -162,7 +162,7 @@ kproc_exit(int ecode)
wakeup(p);
/* Buh-bye! */
exit1(td, W_EXITCODE(ecode, 0));
exit1(td, ecode, 0);
}
/*

View File

@ -41,7 +41,9 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/elf.h>
#include <sys/eventhandler.h>
#include <sys/exec.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/lock.h>
@ -68,9 +70,8 @@ __FBSDID("$FreeBSD$");
#include <sys/sdt.h>
#include <sys/sx.h>
#include <sys/user.h>
#include <sys/jail.h>
#include <sys/vnode.h>
#include <sys/eventhandler.h>
#include <sys/wait.h>
#ifdef DDB
#include <ddb/ddb.h>
@ -920,7 +921,7 @@ fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp)
p->p_sysent->sv_name[0] != '\0')
strlcpy(kp->ki_emul, p->p_sysent->sv_name, sizeof(kp->ki_emul));
kp->ki_siglist = p->p_siglist;
kp->ki_xstat = p->p_xstat;
kp->ki_xstat = KW_EXITCODE(p->p_xexit, p->p_xsig);
kp->ki_acflag = p->p_acflag;
kp->ki_lock = p->p_lock;
if (p->p_pptr) {

View File

@ -2227,7 +2227,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
if (p->p_numthreads == p->p_suspcount) {
PROC_SUNLOCK(p);
p->p_flag |= P_CONTINUED;
p->p_xstat = SIGCONT;
p->p_xsig = SIGCONT;
PROC_LOCK(p->p_pptr);
childproc_continued(p);
PROC_UNLOCK(p->p_pptr);
@ -2306,7 +2306,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
if (p->p_flag & (P_PPWAIT|P_WEXIT))
goto out;
p->p_flag |= P_STOPPED_SIG;
p->p_xstat = sig;
p->p_xsig = sig;
PROC_SLOCK(p);
sig_suspend_threads(td, p, 1);
if (p->p_numthreads == p->p_suspcount) {
@ -2319,7 +2319,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
*/
thread_stopped(p);
PROC_SUNLOCK(p);
sigqueue_delete_proc(p, p->p_xstat);
sigqueue_delete_proc(p, p->p_xsig);
} else
PROC_SUNLOCK(p);
goto out;
@ -2491,7 +2491,7 @@ ptracestop(struct thread *td, int sig)
* Just make wait() to work, the last stopped thread
* will win.
*/
p->p_xstat = sig;
p->p_xsig = sig;
p->p_xthread = td;
p->p_flag |= (P_STOPPED_SIG|P_STOPPED_TRACE);
sig_suspend_threads(td, p, 0);
@ -2684,7 +2684,7 @@ issignal(struct thread *td)
/*
* If parent wants us to take the signal,
* then it will leave it in p->p_xstat;
* then it will leave it in p->p_xsig;
* otherwise we just look for signals again.
*/
if (newsig == 0)
@ -2761,7 +2761,7 @@ issignal(struct thread *td)
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK,
&p->p_mtx.lock_object, "Catching SIGSTOP");
p->p_flag |= P_STOPPED_SIG;
p->p_xstat = sig;
p->p_xsig = sig;
PROC_SLOCK(p);
sig_suspend_threads(td, p, 0);
thread_suspend_switch(td, p);
@ -2965,7 +2965,7 @@ sigexit(td, sig)
sig & WCOREFLAG ? " (core dumped)" : "");
} else
PROC_UNLOCK(p);
exit1(td, W_EXITCODE(0, sig));
exit1(td, 0, sig);
/* NOTREACHED */
}
@ -3020,8 +3020,8 @@ childproc_jobstate(struct proc *p, int reason, int sig)
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);
childproc_jobstate(p, reason, p->p_xsig);
}
void
@ -3033,16 +3033,18 @@ childproc_continued(struct proc *p)
void
childproc_exited(struct proc *p)
{
int reason;
int xstat = p->p_xstat; /* convert to int */
int status;
int reason, status;
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);
if (WCOREDUMP(p->p_xsig)) {
reason = CLD_DUMPED;
status = WTERMSIG(p->p_xsig);
} else if (WIFSIGNALED(p->p_xsig)) {
reason = CLD_KILLED;
status = WTERMSIG(p->p_xsig);
} else {
reason = CLD_EXITED;
status = p->p_xexit;
}
/*
* XXX avoid calling wakeup(p->p_pptr), the work is
* done in exit1().

View File

@ -295,7 +295,7 @@ procdesc_exit(struct proc *p)
("procdesc_exit: closed && parent not init"));
pd->pd_flags |= PDF_EXITED;
pd->pd_xstat = p->p_xstat;
pd->pd_xstat = KW_EXITCODE(p->p_xexit, p->p_xsig);
/*
* If the process descriptor has been closed, then we have nothing

View File

@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/pioctl.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/vnode.h>
@ -975,7 +976,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
sx_xunlock(&proctree_lock);
proctree_locked = 0;
}
p->p_xstat = data;
p->p_xsig = data;
p->p_xthread = NULL;
if ((p->p_flag & (P_STOPPED_SIG | P_STOPPED_TRACE)) != 0) {
/* deliver or queue signal */
@ -1300,7 +1301,8 @@ stopevent(struct proc *p, unsigned int event, unsigned int val)
CTR3(KTR_PTRACE, "stopevent: pid %d event %u val %u", p->p_pid, event,
val);
do {
p->p_xstat = val;
if (event != S_EXIT)
p->p_xsig = val;
p->p_xthread = NULL;
p->p_stype = event; /* Which event caused the stop? */
wakeup(&p->p_stype); /* Wake up any PIOCWAIT'ing procs */

View File

@ -585,10 +585,10 @@ struct proc {
pid_t p_reapsubtree; /* (e) Pid of the direct child of the
reaper which spawned
our subtree. */
u_int p_xexit; /* (c) Exit code. */
u_int p_xsig; /* (c) Stop/kill sig. */
/* End area that is copied on creation. */
#define p_endcopy p_xstat
u_short p_xstat; /* (c) Exit status; also stop sig. */
#define p_endcopy p_xsig
struct knlist p_klist; /* (c) Knotes attached to this proc. */
int p_numthreads; /* (c) Number of threads. */
struct mdproc p_md; /* Any machine-dependent fields. */
@ -970,7 +970,7 @@ void unsleep(struct thread *);
void userret(struct thread *, struct trapframe *);
void cpu_exit(struct thread *);
void exit1(struct thread *, int) __dead2;
void exit1(struct thread *, int, int) __dead2;
struct syscall_args;
int cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa);
void cpu_fork(struct thread *, struct proc *, struct thread *, int);

View File

@ -138,7 +138,19 @@ typedef enum
#define WAIT_MYPGRP 0 /* any process in my process group */
#endif /* __BSD_VISIBLE */
#if defined(_KERNEL) || defined(_WANT_KW_EXITCODE)
/*
* Clamp the return code to the low 8 bits from full 32 bit value.
* Should be used in kernel to construct the wait(2)-compatible process
* status to usermode.
*/
#define KW_EXITCODE(ret, sig) W_EXITCODE((ret) & 0xff, (sig))
#endif /* _KERNEL || _WANT_KW_EXITCODE */
#ifndef _KERNEL
#include <sys/types.h>
__BEGIN_DECLS