Add the wait6(2) system call. It takes POSIX waitid()-like process
designator to select a process which is waited for. The system call optionally returns siginfo_t which would be otherwise provided to SIGCHLD handler, as well as extended structure accounting for child and cumulative grandchild resource usage. Allow to get the current rusage information for non-exited processes as well, similar to Solaris. The explicit WEXITED flag is required to wait for exited processes, allowing for more fine-grained control of the events the waiter is interested in. Fix the handling of siginfo for WNOWAIT option for all wait*(2) family, by not removing the queued signal state. PR: standards/170346 Submitted by: "Jukka A. Ukkonen" <jau@iki.fi> MFC after: 1 month
This commit is contained in:
parent
84590fd8e5
commit
f13b5a0f01
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=242958
@ -602,6 +602,7 @@
|
|||||||
#define AUE_PDKILL 43198 /* FreeBSD. */
|
#define AUE_PDKILL 43198 /* FreeBSD. */
|
||||||
#define AUE_PDGETPID 43199 /* FreeBSD. */
|
#define AUE_PDGETPID 43199 /* FreeBSD. */
|
||||||
#define AUE_PDWAIT 43200 /* FreeBSD. */
|
#define AUE_PDWAIT 43200 /* FreeBSD. */
|
||||||
|
#define AUE_WAIT6 43201 /* FreeBSD. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
|
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
|
||||||
|
@ -51,6 +51,7 @@ extern "C" {
|
|||||||
#define P_INITUID 0
|
#define P_INITUID 0
|
||||||
#define P_INITPGID 0
|
#define P_INITPGID 0
|
||||||
|
|
||||||
|
#ifndef _IDTYPE_T_DECLARED
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following defines the values for an identifier type. It
|
* The following defines the values for an identifier type. It
|
||||||
@ -81,6 +82,9 @@ typedef enum
|
|||||||
P_PSETID /* Processor set identifier */
|
P_PSETID /* Processor set identifier */
|
||||||
} idtype_t;
|
} idtype_t;
|
||||||
|
|
||||||
|
#define _IDTYPE_T_DECLARED
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following defines the operations which can be performed to
|
* The following defines the operations which can be performed to
|
||||||
|
@ -88,6 +88,11 @@ struct rusage32 {
|
|||||||
int32_t ru_nivcsw;
|
int32_t ru_nivcsw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wrusage32 {
|
||||||
|
struct rusage32 wru_self;
|
||||||
|
struct rusage32 wru_children;
|
||||||
|
};
|
||||||
|
|
||||||
struct itimerval32 {
|
struct itimerval32 {
|
||||||
struct timeval32 it_interval;
|
struct timeval32 it_interval;
|
||||||
struct timeval32 it_value;
|
struct timeval32 it_value;
|
||||||
|
@ -180,6 +180,44 @@ freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
|
|||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
freebsd32_wait6(struct thread *td, struct freebsd32_wait6_args *uap)
|
||||||
|
{
|
||||||
|
struct wrusage32 wru32;
|
||||||
|
struct __wrusage wru, *wrup;
|
||||||
|
struct siginfo32 si32;
|
||||||
|
struct __siginfo si, *sip;
|
||||||
|
int error, status;
|
||||||
|
|
||||||
|
if (uap->wrusage != NULL)
|
||||||
|
wrup = &wru;
|
||||||
|
else
|
||||||
|
wrup = NULL;
|
||||||
|
|
||||||
|
if (uap->info != NULL) {
|
||||||
|
sip = &si;
|
||||||
|
bzero(sip, sizeof(*sip));
|
||||||
|
} else
|
||||||
|
sip = NULL;
|
||||||
|
|
||||||
|
error = kern_wait6(td, uap->idtype, uap->id, &status, uap->options,
|
||||||
|
wrup, sip);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
if (uap->status != NULL)
|
||||||
|
error = copyout(&status, uap->status, sizeof(status));
|
||||||
|
if (uap->wrusage != NULL && error == 0) {
|
||||||
|
freebsd32_rusage_out(&wru.wru_self, &wru32.wru_self);
|
||||||
|
freebsd32_rusage_out(&wru.wru_children, &wru32.wru_children);
|
||||||
|
error = copyout(&wru32, uap->wrusage, sizeof(wru32));
|
||||||
|
}
|
||||||
|
if (uap->info != NULL && error == 0) {
|
||||||
|
siginfo_to_siginfo32 (&si, &si32);
|
||||||
|
error = copyout(&si32, uap->info, sizeof(si32));
|
||||||
|
}
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef COMPAT_FREEBSD4
|
#ifdef COMPAT_FREEBSD4
|
||||||
static void
|
static void
|
||||||
copy_statfs(struct statfs *in, struct statfs32 *out)
|
copy_statfs(struct statfs *in, struct statfs32 *out)
|
||||||
|
@ -1000,3 +1000,8 @@
|
|||||||
uint32_t offset1, uint32_t offset2,\
|
uint32_t offset1, uint32_t offset2,\
|
||||||
uint32_t len1, uint32_t len2, \
|
uint32_t len1, uint32_t len2, \
|
||||||
int advice); }
|
int advice); }
|
||||||
|
532 AUE_WAIT6 STD { int freebsd32_wait6(int idtype, int id, \
|
||||||
|
int *status, int options, \
|
||||||
|
struct wrusage32 *wrusage, \
|
||||||
|
siginfo_t *info); }
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ exit1(struct thread *td, int rv)
|
|||||||
* XXX in case we're rebooting we just let init die in order to
|
* XXX in case we're rebooting we just let init die in order to
|
||||||
* work around an unsolved stack overflow seen very late during
|
* work around an unsolved stack overflow seen very late during
|
||||||
* shutdown on sparc64 when the gmirror worker process exists.
|
* shutdown on sparc64 when the gmirror worker process exists.
|
||||||
*/
|
*/
|
||||||
if (p == initproc && rebooting == 0) {
|
if (p == initproc && rebooting == 0) {
|
||||||
printf("init died (signal %d, exit %d)\n",
|
printf("init died (signal %d, exit %d)\n",
|
||||||
WTERMSIG(rv), WEXITSTATUS(rv));
|
WTERMSIG(rv), WEXITSTATUS(rv));
|
||||||
@ -617,7 +617,7 @@ sys_abort2(struct thread *td, struct abort2_args *uap)
|
|||||||
sbuf_clear(sb);
|
sbuf_clear(sb);
|
||||||
sbuf_printf(sb, "%s(pid %d uid %d) aborted: ",
|
sbuf_printf(sb, "%s(pid %d uid %d) aborted: ",
|
||||||
p->p_comm, p->p_pid, td->td_ucred->cr_uid);
|
p->p_comm, p->p_pid, td->td_ucred->cr_uid);
|
||||||
/*
|
/*
|
||||||
* Since we can't return from abort2(), send SIGKILL in cases, where
|
* Since we can't return from abort2(), send SIGKILL in cases, where
|
||||||
* abort2() was called improperly
|
* abort2() was called improperly
|
||||||
*/
|
*/
|
||||||
@ -689,7 +689,7 @@ owait(struct thread *td, struct owait_args *uap __unused)
|
|||||||
* The dirty work is handled by kern_wait().
|
* The dirty work is handled by kern_wait().
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sys_wait4(struct thread *td, struct wait_args *uap)
|
sys_wait4(struct thread *td, struct wait4_args *uap)
|
||||||
{
|
{
|
||||||
struct rusage ru, *rup;
|
struct rusage ru, *rup;
|
||||||
int error, status;
|
int error, status;
|
||||||
@ -706,14 +706,51 @@ sys_wait4(struct thread *td, struct wait_args *uap)
|
|||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sys_wait6(struct thread *td, struct wait6_args *uap)
|
||||||
|
{
|
||||||
|
struct __wrusage wru, *wrup;
|
||||||
|
siginfo_t si, *sip;
|
||||||
|
int error, status;
|
||||||
|
idtype_t idtype;
|
||||||
|
id_t id;
|
||||||
|
|
||||||
|
idtype = uap->idtype;
|
||||||
|
id = uap->id;
|
||||||
|
|
||||||
|
if (uap->wrusage != NULL)
|
||||||
|
wrup = &wru;
|
||||||
|
else
|
||||||
|
wrup = NULL;
|
||||||
|
|
||||||
|
if (uap->info != NULL) {
|
||||||
|
sip = &si;
|
||||||
|
bzero(sip, sizeof(*sip));
|
||||||
|
} else
|
||||||
|
sip = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We expect all callers of wait6() to know about WEXITED and
|
||||||
|
* WTRAPPED.
|
||||||
|
*/
|
||||||
|
error = kern_wait6(td, idtype, id, &status, uap->options, wrup, sip);
|
||||||
|
|
||||||
|
if (uap->status != NULL && error == 0)
|
||||||
|
error = copyout(&status, uap->status, sizeof(status));
|
||||||
|
if (uap->wrusage != NULL && error == 0)
|
||||||
|
error = copyout(&wru, uap->wrusage, sizeof(wru));
|
||||||
|
if (uap->info != NULL && error == 0)
|
||||||
|
error = copyout(&si, uap->info, sizeof(si));
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reap the remains of a zombie process and optionally return status and
|
* Reap the remains of a zombie process and optionally return status and
|
||||||
* rusage. Asserts and will release both the proctree_lock and the process
|
* rusage. Asserts and will release both the proctree_lock and the process
|
||||||
* lock as part of its work.
|
* lock as part of its work.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
proc_reap(struct thread *td, struct proc *p, int *status, int options,
|
proc_reap(struct thread *td, struct proc *p, int *status, int options)
|
||||||
struct rusage *rusage)
|
|
||||||
{
|
{
|
||||||
struct proc *q, *t;
|
struct proc *q, *t;
|
||||||
|
|
||||||
@ -723,10 +760,7 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options,
|
|||||||
KASSERT(p->p_state == PRS_ZOMBIE, ("proc_reap: !PRS_ZOMBIE"));
|
KASSERT(p->p_state == PRS_ZOMBIE, ("proc_reap: !PRS_ZOMBIE"));
|
||||||
|
|
||||||
q = td->td_proc;
|
q = td->td_proc;
|
||||||
if (rusage) {
|
|
||||||
*rusage = p->p_ru;
|
|
||||||
calcru(p, &rusage->ru_utime, &rusage->ru_stime);
|
|
||||||
}
|
|
||||||
PROC_SUNLOCK(p);
|
PROC_SUNLOCK(p);
|
||||||
td->td_retval[0] = p->p_pid;
|
td->td_retval[0] = p->p_pid;
|
||||||
if (status)
|
if (status)
|
||||||
@ -839,20 +873,74 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
proc_to_reap(struct thread *td, struct proc *p, pid_t pid, int *status,
|
proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id,
|
||||||
int options, struct rusage *rusage)
|
int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo)
|
||||||
{
|
{
|
||||||
struct proc *q;
|
struct proc *q;
|
||||||
|
struct rusage *rup;
|
||||||
|
|
||||||
sx_assert(&proctree_lock, SA_XLOCKED);
|
sx_assert(&proctree_lock, SA_XLOCKED);
|
||||||
|
|
||||||
q = td->td_proc;
|
q = td->td_proc;
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
if (pid != WAIT_ANY && p->p_pid != pid && p->p_pgid != -pid) {
|
|
||||||
|
switch (idtype) {
|
||||||
|
case P_ALL:
|
||||||
|
break;
|
||||||
|
case P_PID:
|
||||||
|
if (p->p_pid != (pid_t)id) {
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P_PGID:
|
||||||
|
if (p->p_pgid != (pid_t)id) {
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P_SID:
|
||||||
|
if (p->p_session->s_sid != (pid_t)id) {
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P_UID:
|
||||||
|
if (p->p_ucred->cr_uid != (uid_t)id) {
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P_GID:
|
||||||
|
if (p->p_ucred->cr_gid != (gid_t)id) {
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P_JAILID:
|
||||||
|
if (p->p_ucred->cr_prison == NULL ||
|
||||||
|
(p->p_ucred->cr_prison->pr_id != (int)id)) {
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* It seems that the thread structures get zeroed out
|
||||||
|
* at process exit. This makes it impossible to
|
||||||
|
* support P_SETID, P_CID or P_CPUID.
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
return (0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_canwait(td, p)) {
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (p_canwait(td, p)) {
|
|
||||||
|
if (((options & WEXITED) == 0) && (p->p_state == PRS_ZOMBIE)) {
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -872,8 +960,59 @@ proc_to_reap(struct thread *td, struct proc *p, pid_t pid, int *status,
|
|||||||
}
|
}
|
||||||
|
|
||||||
PROC_SLOCK(p);
|
PROC_SLOCK(p);
|
||||||
|
|
||||||
|
if (siginfo != NULL) {
|
||||||
|
bzero (siginfo, sizeof (*siginfo));
|
||||||
|
siginfo->si_errno = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SUSv4 requires that the si_signo value is always
|
||||||
|
* SIGCHLD. Obey it despite the rfork(2) interface
|
||||||
|
* allows to request other signal for child exit
|
||||||
|
* notification.
|
||||||
|
*/
|
||||||
|
siginfo->si_signo = SIGCHLD;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is still a rough estimate. We will fix the
|
||||||
|
* cases TRAPPED, STOPPED, and CONTINUED later.
|
||||||
|
*/
|
||||||
|
if (WCOREDUMP(p->p_xstat))
|
||||||
|
siginfo->si_code = CLD_DUMPED;
|
||||||
|
else if (WIFSIGNALED(p->p_xstat))
|
||||||
|
siginfo->si_code = CLD_KILLED;
|
||||||
|
else
|
||||||
|
siginfo->si_code = CLD_EXITED;
|
||||||
|
|
||||||
|
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
|
||||||
|
* detail, but apparently the PC value may be lost
|
||||||
|
* when we reach this point. bzero() above sets
|
||||||
|
* siginfo->si_addr to NULL.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There should be no reason to limit resources usage info to
|
||||||
|
* exited processes only. A snapshot about any resources used
|
||||||
|
* by a stopped process may be exactly what is needed.
|
||||||
|
*/
|
||||||
|
if (wrusage != NULL) {
|
||||||
|
rup = &wrusage->wru_self;
|
||||||
|
*rup = p->p_ru;
|
||||||
|
calcru(p, &rup->ru_utime, &rup->ru_stime);
|
||||||
|
|
||||||
|
rup = &wrusage->wru_children;
|
||||||
|
*rup = p->p_stats->p_cru;
|
||||||
|
calccru(p, &rup->ru_utime, &rup->ru_stime);
|
||||||
|
}
|
||||||
|
|
||||||
if (p->p_state == PRS_ZOMBIE) {
|
if (p->p_state == PRS_ZOMBIE) {
|
||||||
proc_reap(td, p, status, options, rusage);
|
proc_reap(td, p, status, options);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
PROC_SUNLOCK(p);
|
PROC_SUNLOCK(p);
|
||||||
@ -884,22 +1023,72 @@ proc_to_reap(struct thread *td, struct proc *p, pid_t pid, int *status,
|
|||||||
int
|
int
|
||||||
kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
||||||
struct rusage *rusage)
|
struct rusage *rusage)
|
||||||
|
{
|
||||||
|
struct __wrusage wru, *wrup;
|
||||||
|
idtype_t idtype;
|
||||||
|
id_t id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (pid == WAIT_ANY) {
|
||||||
|
idtype = P_ALL;
|
||||||
|
id = 0;
|
||||||
|
}
|
||||||
|
else if (pid <= 0) {
|
||||||
|
idtype = P_PGID;
|
||||||
|
id = (id_t)-pid;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
idtype = P_PID;
|
||||||
|
id = (id_t)pid;
|
||||||
|
}
|
||||||
|
if (rusage != NULL)
|
||||||
|
wrup = &wru;
|
||||||
|
else
|
||||||
|
wrup = NULL;
|
||||||
|
/*
|
||||||
|
* For backward compatibility we implicitly add flags WEXITED
|
||||||
|
* and WTRAPPED here.
|
||||||
|
*/
|
||||||
|
options |= WEXITED | WTRAPPED;
|
||||||
|
ret = kern_wait6(td, idtype, id, status, options, wrup, NULL);
|
||||||
|
if (rusage != NULL)
|
||||||
|
*rusage = wru.wru_self;
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
kern_wait6(struct thread *td, idtype_t idtype, id_t id, int *status,
|
||||||
|
int options, struct __wrusage *wrusage, siginfo_t *siginfo)
|
||||||
{
|
{
|
||||||
struct proc *p, *q;
|
struct proc *p, *q;
|
||||||
int error, nfound, ret;
|
int error, nfound, ret;
|
||||||
|
|
||||||
AUDIT_ARG_PID(pid);
|
AUDIT_ARG_VALUE((int)idtype); /* XXX - This is likely wrong! */
|
||||||
|
AUDIT_ARG_PID((pid_t)id); /* XXX - This may be wrong! */
|
||||||
AUDIT_ARG_VALUE(options);
|
AUDIT_ARG_VALUE(options);
|
||||||
|
|
||||||
q = td->td_proc;
|
q = td->td_proc;
|
||||||
if (pid == 0) {
|
|
||||||
PROC_LOCK(q);
|
if ((pid_t)id == WAIT_MYPGRP &&
|
||||||
pid = -q->p_pgid;
|
(idtype == P_PID || idtype == P_PGID)) {
|
||||||
PROC_UNLOCK(q);
|
id = (id_t)q->p_pgid;
|
||||||
|
idtype = P_PGID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we don't know the option, just return. */
|
/* If we don't know the option, just return. */
|
||||||
if (options & ~(WUNTRACED|WNOHANG|WCONTINUED|WNOWAIT|WLINUXCLONE))
|
if ((options & ~(WUNTRACED | WNOHANG | WCONTINUED | WNOWAIT |
|
||||||
|
WEXITED | WTRAPPED | WLINUXCLONE)) != 0)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
|
if ((options & (WEXITED | WUNTRACED | WCONTINUED | WTRAPPED)) == 0) {
|
||||||
|
/*
|
||||||
|
* We will be unable to find any matching processes,
|
||||||
|
* because there are no known events to look for.
|
||||||
|
* Prefer to return error instead of blocking
|
||||||
|
* indefinitely.
|
||||||
|
*/
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
if (q->p_flag & P_STATCHILD) {
|
if (q->p_flag & P_STATCHILD) {
|
||||||
PROC_LOCK(q);
|
PROC_LOCK(q);
|
||||||
@ -909,7 +1098,8 @@ kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
|||||||
nfound = 0;
|
nfound = 0;
|
||||||
sx_xlock(&proctree_lock);
|
sx_xlock(&proctree_lock);
|
||||||
LIST_FOREACH(p, &q->p_children, p_sibling) {
|
LIST_FOREACH(p, &q->p_children, p_sibling) {
|
||||||
ret = proc_to_reap(td, p, pid, status, options, rusage);
|
ret = proc_to_reap(td, p, idtype, id, status, options,
|
||||||
|
wrusage, siginfo);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
continue;
|
continue;
|
||||||
else if (ret == 1)
|
else if (ret == 1)
|
||||||
@ -919,37 +1109,77 @@ kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
|||||||
|
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
PROC_SLOCK(p);
|
PROC_SLOCK(p);
|
||||||
if ((p->p_flag & P_STOPPED_SIG) &&
|
|
||||||
|
if ((options & WTRAPPED) != 0 &&
|
||||||
|
(p->p_flag & P_TRACED) != 0 &&
|
||||||
|
(p->p_flag & (P_STOPPED_TRACE | P_STOPPED_SIG)) != 0 &&
|
||||||
(p->p_suspcount == p->p_numthreads) &&
|
(p->p_suspcount == p->p_numthreads) &&
|
||||||
(p->p_flag & P_WAITED) == 0 &&
|
((p->p_flag & P_WAITED) == 0)) {
|
||||||
(p->p_flag & P_TRACED || options & WUNTRACED)) {
|
|
||||||
PROC_SUNLOCK(p);
|
PROC_SUNLOCK(p);
|
||||||
p->p_flag |= P_WAITED;
|
if ((options & WNOWAIT) == 0)
|
||||||
|
p->p_flag |= P_WAITED;
|
||||||
sx_xunlock(&proctree_lock);
|
sx_xunlock(&proctree_lock);
|
||||||
td->td_retval[0] = p->p_pid;
|
td->td_retval[0] = p->p_pid;
|
||||||
if (status)
|
|
||||||
|
if (status != NULL)
|
||||||
*status = W_STOPCODE(p->p_xstat);
|
*status = W_STOPCODE(p->p_xstat);
|
||||||
|
if (siginfo != NULL) {
|
||||||
|
siginfo->si_status = p->p_xstat;
|
||||||
|
siginfo->si_code = CLD_TRAPPED;
|
||||||
|
}
|
||||||
|
if ((options & WNOWAIT) == 0) {
|
||||||
|
PROC_LOCK(q);
|
||||||
|
sigqueue_take(p->p_ksi);
|
||||||
|
PROC_UNLOCK(q);
|
||||||
|
}
|
||||||
|
|
||||||
PROC_LOCK(q);
|
|
||||||
sigqueue_take(p->p_ksi);
|
|
||||||
PROC_UNLOCK(q);
|
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
if ((options & WUNTRACED) != 0 &&
|
||||||
|
(p->p_flag & P_STOPPED_SIG) != 0 &&
|
||||||
|
(p->p_suspcount == p->p_numthreads) &&
|
||||||
|
((p->p_flag & P_WAITED) == 0)) {
|
||||||
|
PROC_SUNLOCK(p);
|
||||||
|
if ((options & WNOWAIT) == 0)
|
||||||
|
p->p_flag |= P_WAITED;
|
||||||
|
sx_xunlock(&proctree_lock);
|
||||||
|
td->td_retval[0] = p->p_pid;
|
||||||
|
|
||||||
|
if (status != NULL)
|
||||||
|
*status = W_STOPCODE(p->p_xstat);
|
||||||
|
if (siginfo != NULL) {
|
||||||
|
siginfo->si_status = p->p_xstat;
|
||||||
|
siginfo->si_code = CLD_STOPPED;
|
||||||
|
}
|
||||||
|
if ((options & WNOWAIT) == 0) {
|
||||||
|
PROC_LOCK(q);
|
||||||
|
sigqueue_take(p->p_ksi);
|
||||||
|
PROC_UNLOCK(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_UNLOCK(p);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
PROC_SUNLOCK(p);
|
PROC_SUNLOCK(p);
|
||||||
if (options & WCONTINUED && (p->p_flag & P_CONTINUED)) {
|
if ((options & WCONTINUED) != 0 &&
|
||||||
|
(p->p_flag & P_CONTINUED) != 0) {
|
||||||
sx_xunlock(&proctree_lock);
|
sx_xunlock(&proctree_lock);
|
||||||
td->td_retval[0] = p->p_pid;
|
td->td_retval[0] = p->p_pid;
|
||||||
p->p_flag &= ~P_CONTINUED;
|
if ((options & WNOWAIT) == 0) {
|
||||||
|
p->p_flag &= ~P_CONTINUED;
|
||||||
PROC_LOCK(q);
|
PROC_LOCK(q);
|
||||||
sigqueue_take(p->p_ksi);
|
sigqueue_take(p->p_ksi);
|
||||||
PROC_UNLOCK(q);
|
PROC_UNLOCK(q);
|
||||||
|
}
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
|
|
||||||
if (status)
|
if (status != NULL)
|
||||||
*status = SIGCONT;
|
*status = SIGCONT;
|
||||||
|
if (siginfo != NULL) {
|
||||||
|
siginfo->si_status = SIGCONT;
|
||||||
|
siginfo->si_code = CLD_CONTINUED;
|
||||||
|
}
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
@ -968,7 +1198,8 @@ kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
|||||||
* to successfully wait until the child becomes a zombie.
|
* to successfully wait until the child becomes a zombie.
|
||||||
*/
|
*/
|
||||||
LIST_FOREACH(p, &q->p_orphans, p_orphan) {
|
LIST_FOREACH(p, &q->p_orphans, p_orphan) {
|
||||||
ret = proc_to_reap(td, p, pid, status, options, rusage);
|
ret = proc_to_reap(td, p, idtype, id, status, options,
|
||||||
|
wrusage, siginfo);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
continue;
|
continue;
|
||||||
else if (ret == 1)
|
else if (ret == 1)
|
||||||
@ -994,7 +1225,7 @@ kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
|||||||
error = msleep(q, &q->p_mtx, PWAIT | PCATCH, "wait", 0);
|
error = msleep(q, &q->p_mtx, PWAIT | PCATCH, "wait", 0);
|
||||||
PROC_UNLOCK(q);
|
PROC_UNLOCK(q);
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +374,7 @@ procdesc_close(struct file *fp, struct thread *td)
|
|||||||
*/
|
*/
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
PROC_SLOCK(p);
|
PROC_SLOCK(p);
|
||||||
proc_reap(curthread, p, NULL, 0, NULL);
|
proc_reap(curthread, p, NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If the process is not yet dead, we need to kill it, but we
|
* If the process is not yet dead, we need to kill it, but we
|
||||||
|
@ -71,8 +71,7 @@
|
|||||||
; XXX man page says `mode_t mode'.
|
; XXX man page says `mode_t mode'.
|
||||||
6 AUE_CLOSE STD { int close(int fd); }
|
6 AUE_CLOSE STD { int close(int fd); }
|
||||||
7 AUE_WAIT4 STD { int wait4(int pid, int *status, \
|
7 AUE_WAIT4 STD { int wait4(int pid, int *status, \
|
||||||
int options, struct rusage *rusage); } \
|
int options, struct rusage *rusage); }
|
||||||
wait4 wait_args int
|
|
||||||
8 AUE_CREAT COMPAT { int creat(char *path, int mode); }
|
8 AUE_CREAT COMPAT { int creat(char *path, int mode); }
|
||||||
9 AUE_LINK STD { int link(char *path, char *link); }
|
9 AUE_LINK STD { int link(char *path, char *link); }
|
||||||
10 AUE_UNLINK STD { int unlink(char *path); }
|
10 AUE_UNLINK STD { int unlink(char *path); }
|
||||||
@ -952,5 +951,9 @@
|
|||||||
off_t offset, off_t len); }
|
off_t offset, off_t len); }
|
||||||
531 AUE_NULL STD { int posix_fadvise(int fd, off_t offset, \
|
531 AUE_NULL STD { int posix_fadvise(int fd, off_t offset, \
|
||||||
off_t len, int advice); }
|
off_t len, int advice); }
|
||||||
|
532 AUE_WAIT6 STD { int wait6(int idtype, int id, \
|
||||||
|
int *status, int options, \
|
||||||
|
struct __wrusage *wrusage, \
|
||||||
|
siginfo_t *info); }
|
||||||
; Please copy any additions and changes to the following compatability tables:
|
; Please copy any additions and changes to the following compatability tables:
|
||||||
; sys/compat/freebsd32/syscalls.master
|
; sys/compat/freebsd32/syscalls.master
|
||||||
|
@ -885,8 +885,7 @@ int proc_getenvv(struct thread *td, struct proc *p, struct sbuf *sb);
|
|||||||
void procinit(void);
|
void procinit(void);
|
||||||
void proc_linkup0(struct proc *p, struct thread *td);
|
void proc_linkup0(struct proc *p, struct thread *td);
|
||||||
void proc_linkup(struct proc *p, struct thread *td);
|
void proc_linkup(struct proc *p, struct thread *td);
|
||||||
void proc_reap(struct thread *td, struct proc *p, int *status, int options,
|
void proc_reap(struct thread *td, struct proc *p, int *status, int options);
|
||||||
struct rusage *rusage);
|
|
||||||
void proc_reparent(struct proc *child, struct proc *newparent);
|
void proc_reparent(struct proc *child, struct proc *newparent);
|
||||||
struct pstats *pstats_alloc(void);
|
struct pstats *pstats_alloc(void);
|
||||||
void pstats_fork(struct pstats *src, struct pstats *dst);
|
void pstats_fork(struct pstats *src, struct pstats *dst);
|
||||||
|
@ -79,6 +79,13 @@ struct rusage {
|
|||||||
#define ru_last ru_nivcsw
|
#define ru_last ru_nivcsw
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
struct __wrusage {
|
||||||
|
struct rusage wru_self;
|
||||||
|
struct rusage wru_children;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resource limits
|
* Resource limits
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +43,7 @@ struct msghdr;
|
|||||||
struct msqid_ds;
|
struct msqid_ds;
|
||||||
struct rlimit;
|
struct rlimit;
|
||||||
struct rusage;
|
struct rusage;
|
||||||
|
struct __wrusage;
|
||||||
union semun;
|
union semun;
|
||||||
struct sockaddr;
|
struct sockaddr;
|
||||||
struct stat;
|
struct stat;
|
||||||
@ -234,6 +235,8 @@ int kern_utimesat(struct thread *td, int fd, char *path,
|
|||||||
enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg);
|
enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg);
|
||||||
int kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
int kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
||||||
struct rusage *rup);
|
struct rusage *rup);
|
||||||
|
int kern_wait6(struct thread *td, idtype_t idtype, id_t id, int *status,
|
||||||
|
int options, struct __wrusage *wrup, siginfo_t *sip);
|
||||||
int kern_writev(struct thread *td, int fd, struct uio *auio);
|
int kern_writev(struct thread *td, int fd, struct uio *auio);
|
||||||
int kern_socketpair(struct thread *td, int domain, int type, int protocol,
|
int kern_socketpair(struct thread *td, int domain, int type, int protocol,
|
||||||
int *rsv);
|
int *rsv);
|
||||||
|
@ -141,6 +141,46 @@ typedef __id_t id_t; /* can hold a uid_t or pid_t */
|
|||||||
#define _ID_T_DECLARED
|
#define _ID_T_DECLARED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _IDTYPE_T_DECLARED
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
#if defined(__BSD_VISIBLE)
|
||||||
|
idtype /* pollutes XPG4.2 namespace */
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* These names were mostly lifted from Solaris source code and
|
||||||
|
* still use Solaris style naming to avoid breaking any
|
||||||
|
* OpenSolaris code which has been ported to FreeBSD. There
|
||||||
|
* is no clear FreeBSD counterpart for all of the names, but
|
||||||
|
* some have a clear correspondence to FreeBSD entities.
|
||||||
|
*/
|
||||||
|
P_PID, /* A process identifier. */
|
||||||
|
P_PPID, /* A parent process identifier. */
|
||||||
|
P_PGID, /* A process group identifier. */
|
||||||
|
P_SID, /* A session identifier. */
|
||||||
|
P_CID, /* A scheduling class identifier. */
|
||||||
|
P_UID, /* A user identifier. */
|
||||||
|
P_GID, /* A group identifier. */
|
||||||
|
P_ALL, /* All processes. */
|
||||||
|
P_LWPID, /* An LWP identifier. */
|
||||||
|
P_TASKID, /* A task identifier. */
|
||||||
|
P_PROJID, /* A project identifier. */
|
||||||
|
P_POOLID, /* A pool identifier. */
|
||||||
|
P_JAILID, /* A zone identifier. */
|
||||||
|
P_CTID, /* A (process) contract identifier. */
|
||||||
|
P_CPUID, /* CPU identifier. */
|
||||||
|
P_PSETID /* Processor set identifier */
|
||||||
|
} idtype_t; /* The type of id_t we are using. */
|
||||||
|
|
||||||
|
#if defined(__BSD_VISIBLE)
|
||||||
|
#define P_ZONEID P_JAILID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _IDTYPE_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef _INO_T_DECLARED
|
#ifndef _INO_T_DECLARED
|
||||||
typedef __ino_t ino_t; /* inode number */
|
typedef __ino_t ino_t; /* inode number */
|
||||||
#define _INO_T_DECLARED
|
#define _INO_T_DECLARED
|
||||||
|
@ -80,6 +80,9 @@
|
|||||||
#define WSTOPPED WUNTRACED /* SUS compatibility */
|
#define WSTOPPED WUNTRACED /* SUS compatibility */
|
||||||
#define WCONTINUED 4 /* Report a job control continued process. */
|
#define WCONTINUED 4 /* Report a job control continued process. */
|
||||||
#define WNOWAIT 8 /* Poll only. Don't delete the proc entry. */
|
#define WNOWAIT 8 /* Poll only. Don't delete the proc entry. */
|
||||||
|
#define WEXITED 16 /* Wait for exited processes. */
|
||||||
|
#define WTRAPPED 32 /* Wait for a process to hit a trap or
|
||||||
|
a breakpoint. */
|
||||||
|
|
||||||
#if __BSD_VISIBLE
|
#if __BSD_VISIBLE
|
||||||
#define WLINUXCLONE 0x80000000 /* Wait for kthread spawned from linux_clone. */
|
#define WLINUXCLONE 0x80000000 /* Wait for kthread spawned from linux_clone. */
|
||||||
@ -87,6 +90,8 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Tokens for special values of the "pid" parameter to wait4.
|
* Tokens for special values of the "pid" parameter to wait4.
|
||||||
|
* Extended struct __wrusage to collect rusage for both the target
|
||||||
|
* process and its children within one wait6() call.
|
||||||
*/
|
*/
|
||||||
#if __BSD_VISIBLE
|
#if __BSD_VISIBLE
|
||||||
#define WAIT_ANY (-1) /* any process */
|
#define WAIT_ANY (-1) /* any process */
|
||||||
@ -97,12 +102,19 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
struct __siginfo;
|
||||||
pid_t wait(int *);
|
pid_t wait(int *);
|
||||||
pid_t waitpid(pid_t, int *, int);
|
pid_t waitpid(pid_t, int *, int);
|
||||||
|
#if __POSIX_VISIBLE >= 200112
|
||||||
|
int waitid(idtype_t, id_t, struct __siginfo *, int);
|
||||||
|
#endif
|
||||||
#if __BSD_VISIBLE
|
#if __BSD_VISIBLE
|
||||||
struct rusage;
|
struct rusage;
|
||||||
|
struct __wrusage;
|
||||||
pid_t wait3(int *, int, struct rusage *);
|
pid_t wait3(int *, int, struct rusage *);
|
||||||
pid_t wait4(pid_t, int *, int, struct rusage *);
|
pid_t wait4(pid_t, int *, int, struct rusage *);
|
||||||
|
pid_t wait6(idtype_t, id_t, int *, int, struct __wrusage *,
|
||||||
|
struct __siginfo *);
|
||||||
#endif
|
#endif
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
#endif /* !_KERNEL */
|
#endif /* !_KERNEL */
|
||||||
|
Loading…
Reference in New Issue
Block a user