- Replace wait1() with a kern_wait() function that accepts the pid,
options, status pointer and rusage pointer as arguments. It is up to the caller to copyout the status and rusage to userland if needed. This lets us axe the 'compat' argument and hide all that functionality in owait(), by the way. This also cleans up some locking in kern_wait() since it no longer has to drop locks around copyout() since all the copyout()'s are deferred. - Convert owait(), wait4(), and the various ABI compat wait() syscalls to use kern_wait() rather than wait1() or wait4(). This removes a bit more stackgap usage. Tested on: i386 Compiled on: i386, alpha, amd64
This commit is contained in:
parent
cb8c2e1cd2
commit
b7e23e826c
@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/user.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_kern.h>
|
||||
@ -1376,27 +1377,23 @@ osf1_wait4(td, uap)
|
||||
struct thread *td;
|
||||
struct osf1_wait4_args *uap;
|
||||
{
|
||||
int error;
|
||||
caddr_t sg;
|
||||
struct osf1_rusage *orusage, oru;
|
||||
struct rusage *rusage = NULL, ru;
|
||||
int error, status;
|
||||
struct osf1_rusage oru;
|
||||
struct rusage ru;
|
||||
|
||||
orusage = uap->rusage;
|
||||
if (orusage) {
|
||||
sg = stackgap_init();
|
||||
rusage = stackgap_alloc(&sg, sizeof(struct rusage));
|
||||
uap->rusage = (struct osf1_rusage *)rusage;
|
||||
}
|
||||
if ((error = wait4(td, (struct wait_args *)uap)))
|
||||
return error;
|
||||
if (orusage && (error = copyin(rusage, &ru, sizeof(ru)) == 0)){
|
||||
error = kern_wait(td, uap->pid, &status, uap->options, &ru);
|
||||
if (error)
|
||||
return (error);
|
||||
if (uap->status != NULL)
|
||||
error = copyout(&status, uap->status, sizeof(status));
|
||||
if (uap->rusage != NULL && error == 0) {
|
||||
TV_CP(ru.ru_utime, oru.ru_utime);
|
||||
TV_CP(ru.ru_stime, oru.ru_stime);
|
||||
bcopy(&ru.ru_first, &oru.ru_first,
|
||||
(&(oru.ru_last) - &(oru.ru_first)));
|
||||
copyout(&oru, orusage, sizeof (struct osf1_rusage));
|
||||
error = copyout(&oru, uap->rusage, sizeof (struct osf1_rusage));
|
||||
}
|
||||
return (0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
|
@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/user.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_kern.h>
|
||||
@ -88,21 +89,16 @@ CTASSERT(sizeof(struct rusage32) == 72);
|
||||
int
|
||||
freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
|
||||
{
|
||||
int error;
|
||||
caddr_t sg;
|
||||
struct rusage32 *rusage32, ru32;
|
||||
struct rusage *rusage = NULL, ru;
|
||||
int error, status;
|
||||
struct rusage32 ru32;
|
||||
struct rusage ru;
|
||||
|
||||
rusage32 = uap->rusage;
|
||||
if (rusage32) {
|
||||
sg = stackgap_init();
|
||||
rusage = stackgap_alloc(&sg, sizeof(struct rusage));
|
||||
uap->rusage = (struct rusage32 *)rusage;
|
||||
}
|
||||
error = wait4(td, (struct wait_args *)uap);
|
||||
error = kern_wait(td, uap->pid, &status, uap->options, &ru);
|
||||
if (error)
|
||||
return (error);
|
||||
if (rusage32 && (error = copyin(rusage, &ru, sizeof(ru)) == 0)) {
|
||||
if (uap->status != NULL)
|
||||
error = copyout(&status, uap->status, sizeof(status));
|
||||
if (uap->rusage != NULL && error == 0) {
|
||||
TV_CP(ru, ru32, ru_utime);
|
||||
TV_CP(ru, ru32, ru_stime);
|
||||
CP(ru, ru32, ru_maxrss);
|
||||
@ -119,7 +115,7 @@ freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
|
||||
CP(ru, ru32, ru_nsignals);
|
||||
CP(ru, ru32, ru_nvcsw);
|
||||
CP(ru, ru32, ru_nivcsw);
|
||||
error = copyout(&ru32, rusage32, sizeof(ru32));
|
||||
error = copyout(&ru32, uap->rusage, sizeof(ru32));
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
@ -795,13 +795,7 @@ linux_utime(struct thread *td, struct linux_utime_args *args)
|
||||
int
|
||||
linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
|
||||
{
|
||||
struct wait_args /* {
|
||||
int pid;
|
||||
int *status;
|
||||
int options;
|
||||
struct rusage *rusage;
|
||||
} */ tmp;
|
||||
int error, tmpstat;
|
||||
int error, options, tmpstat;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(waitpid))
|
||||
@ -809,20 +803,16 @@ linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
|
||||
args->pid, (void *)args->status, args->options);
|
||||
#endif
|
||||
|
||||
tmp.pid = args->pid;
|
||||
tmp.status = args->status;
|
||||
tmp.options = (args->options & (WNOHANG | WUNTRACED));
|
||||
options = (args->options & (WNOHANG | WUNTRACED));
|
||||
/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
|
||||
if (args->options & __WCLONE)
|
||||
tmp.options |= WLINUXCLONE;
|
||||
tmp.rusage = NULL;
|
||||
options |= WLINUXCLONE;
|
||||
|
||||
if ((error = wait4(td, &tmp)) != 0)
|
||||
error = kern_wait(td, args->pid, &tmpstat, options, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (args->status) {
|
||||
if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
|
||||
return error;
|
||||
tmpstat &= 0xffff;
|
||||
if (WIFSIGNALED(tmpstat))
|
||||
tmpstat = (tmpstat & 0xffffff80) |
|
||||
@ -840,13 +830,8 @@ linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
|
||||
int
|
||||
linux_wait4(struct thread *td, struct linux_wait4_args *args)
|
||||
{
|
||||
struct wait_args /* {
|
||||
int pid;
|
||||
int *status;
|
||||
int options;
|
||||
struct rusage *rusage;
|
||||
} */ tmp;
|
||||
int error, tmpstat;
|
||||
int error, options, tmpstat;
|
||||
struct rusage ru;
|
||||
struct proc *p;
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -856,15 +841,13 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args)
|
||||
(void *)args->rusage);
|
||||
#endif
|
||||
|
||||
tmp.pid = args->pid;
|
||||
tmp.status = args->status;
|
||||
tmp.options = (args->options & (WNOHANG | WUNTRACED));
|
||||
options = (args->options & (WNOHANG | WUNTRACED));
|
||||
/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
|
||||
if (args->options & __WCLONE)
|
||||
tmp.options |= WLINUXCLONE;
|
||||
tmp.rusage = (struct rusage *)args->rusage;
|
||||
options |= WLINUXCLONE;
|
||||
|
||||
if ((error = wait4(td, &tmp)) != 0)
|
||||
error = kern_wait(td, args->pid, &tmpstat, options, &ru);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
p = td->td_proc;
|
||||
@ -873,8 +856,6 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args)
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
if (args->status) {
|
||||
if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
|
||||
return error;
|
||||
tmpstat &= 0xffff;
|
||||
if (WIFSIGNALED(tmpstat))
|
||||
tmpstat = (tmpstat & 0xffffff80) |
|
||||
@ -882,10 +863,12 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args)
|
||||
else if (WIFSTOPPED(tmpstat))
|
||||
tmpstat = (tmpstat & 0xffff00ff) |
|
||||
(BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
|
||||
return copyout(&tmpstat, args->status, sizeof(int));
|
||||
error = copyout(&tmpstat, args->status, sizeof(int));
|
||||
}
|
||||
if (args->rusage != NULL && error == 0)
|
||||
error = copyout(&ru, args->rusage, sizeof(ru));
|
||||
|
||||
return 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -130,29 +130,12 @@ svr4_sys_wait(td, uap)
|
||||
struct thread *td;
|
||||
struct svr4_sys_wait_args *uap;
|
||||
{
|
||||
struct wait_args w4;
|
||||
int error, *retval = td->td_retval, st, sig;
|
||||
size_t sz = sizeof(*w4.status);
|
||||
int error, st, sig;
|
||||
|
||||
w4.rusage = NULL;
|
||||
w4.options = 0;
|
||||
|
||||
if (uap->status == NULL) {
|
||||
caddr_t sg = stackgap_init();
|
||||
|
||||
w4.status = stackgap_alloc(&sg, sz);
|
||||
}
|
||||
else
|
||||
w4.status = uap->status;
|
||||
|
||||
w4.pid = WAIT_ANY;
|
||||
|
||||
if ((error = wait4(td, &w4)) != 0)
|
||||
return error;
|
||||
error = kern_wait(td, WAIT_ANY, &st, 0, NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if ((error = copyin(w4.status, &st, sizeof(st))) != 0)
|
||||
return error;
|
||||
|
||||
if (WIFSIGNALED(st)) {
|
||||
sig = WTERMSIG(st);
|
||||
if (sig >= 0 && sig < NSIG)
|
||||
@ -167,13 +150,12 @@ svr4_sys_wait(td, uap)
|
||||
* It looks like wait(2) on svr4/solaris/2.4 returns
|
||||
* the status in retval[1], and the pid on retval[0].
|
||||
*/
|
||||
retval[1] = st;
|
||||
td->td_retval[1] = st;
|
||||
|
||||
if (uap->status)
|
||||
if ((error = copyout(&st, uap->status, sizeof(st))) != 0)
|
||||
return error;
|
||||
error = copyout(&st, uap->status, sizeof(st));
|
||||
|
||||
return 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -144,36 +144,29 @@ ibcs2_wait(td, uap)
|
||||
struct thread *td;
|
||||
struct ibcs2_wait_args *uap;
|
||||
{
|
||||
int error, status;
|
||||
struct wait_args w4;
|
||||
int error, options, status;
|
||||
int *statusp;
|
||||
pid_t pid;
|
||||
struct trapframe *tf = td->td_frame;
|
||||
|
||||
w4.rusage = NULL;
|
||||
if ((tf->tf_eflags & (PSL_Z|PSL_PF|PSL_N|PSL_V))
|
||||
if ((tf->tf_eflags & (PSL_Z|PSL_PF|PSL_N|PSL_V))
|
||||
== (PSL_Z|PSL_PF|PSL_N|PSL_V)) {
|
||||
/* waitpid */
|
||||
w4.pid = uap->a1;
|
||||
w4.status = (int *)uap->a2;
|
||||
w4.options = uap->a3;
|
||||
pid = uap->a1;
|
||||
statusp = (int *)uap->a2;
|
||||
options = uap->a3;
|
||||
} else {
|
||||
/* wait */
|
||||
w4.pid = WAIT_ANY;
|
||||
w4.status = (int *)uap->a1;
|
||||
w4.options = 0;
|
||||
pid = WAIT_ANY;
|
||||
statusp = (int *)uap->a1;
|
||||
options = 0;
|
||||
}
|
||||
if ((error = wait4(td, &w4)) != 0)
|
||||
error = kern_wait(td, pid, &status, options, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
if (w4.status) { /* this is real iBCS brain-damage */
|
||||
error = copyin((caddr_t)w4.status, (caddr_t)&status,
|
||||
sizeof(w4.status));
|
||||
if(error)
|
||||
return error;
|
||||
|
||||
if (statusp) {
|
||||
/*
|
||||
* Convert status/signal result. We must validate the
|
||||
* signal number stored in the exit status in case
|
||||
* the user changed it between wait4()'s copyout()
|
||||
* and our copyin().
|
||||
* Convert status/signal result.
|
||||
*/
|
||||
if (WIFSTOPPED(status)) {
|
||||
if (WSTOPSIG(status) <= 0 ||
|
||||
@ -191,8 +184,7 @@ ibcs2_wait(td, uap)
|
||||
|
||||
/* record result/status */
|
||||
td->td_retval[1] = status;
|
||||
return copyout((caddr_t)&status, (caddr_t)w4.status,
|
||||
sizeof(w4.status));
|
||||
return copyout(&status, statusp, sizeof(status));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -85,8 +85,6 @@ __FBSDID("$FreeBSD$");
|
||||
/* Required to be non-static for SysVR4 emulator */
|
||||
MALLOC_DEFINE(M_ZOMBIE, "zombie", "zombie proc status");
|
||||
|
||||
static int wait1(struct thread *, struct wait_args *, int);
|
||||
|
||||
/*
|
||||
* exit --
|
||||
* Death of process.
|
||||
@ -551,57 +549,59 @@ exit1(struct thread *td, int rv)
|
||||
|
||||
#ifdef COMPAT_43
|
||||
/*
|
||||
* MPSAFE. The dirty work is handled by wait1().
|
||||
* MPSAFE. The dirty work is handled by kern_wait().
|
||||
*/
|
||||
int
|
||||
owait(struct thread *td, struct owait_args *uap __unused)
|
||||
{
|
||||
struct wait_args w;
|
||||
int error, status;
|
||||
|
||||
w.options = 0;
|
||||
w.rusage = NULL;
|
||||
w.pid = WAIT_ANY;
|
||||
w.status = NULL;
|
||||
return (wait1(td, &w, 1));
|
||||
error = kern_wait(td, WAIT_ANY, &status, 0, NULL);
|
||||
if (error == 0)
|
||||
td->td_retval[1] = status;
|
||||
return (error);
|
||||
}
|
||||
#endif /* COMPAT_43 */
|
||||
|
||||
/*
|
||||
* MPSAFE. The dirty work is handled by wait1().
|
||||
* MPSAFE. The dirty work is handled by kern_wait().
|
||||
*/
|
||||
int
|
||||
wait4(struct thread *td, struct wait_args *uap)
|
||||
{
|
||||
struct rusage ru;
|
||||
int error, status;
|
||||
|
||||
return (wait1(td, uap, 0));
|
||||
error = kern_wait(td, uap->pid, &status, uap->options, &ru);
|
||||
if (uap->status != NULL && error == 0)
|
||||
error = copyout(&status, uap->status, sizeof(status));
|
||||
if (uap->rusage != NULL && error == 0)
|
||||
error = copyout(&ru, uap->rusage, sizeof(struct rusage));
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* MPSAFE
|
||||
*/
|
||||
static int
|
||||
wait1(struct thread *td, struct wait_args *uap, int compat)
|
||||
int
|
||||
kern_wait(struct thread *td, pid_t pid, int *status, int options, struct rusage *rusage)
|
||||
{
|
||||
struct rusage ru;
|
||||
int nfound;
|
||||
struct proc *p, *q, *t;
|
||||
int status, error;
|
||||
int error;
|
||||
|
||||
q = td->td_proc;
|
||||
if (uap->pid == 0) {
|
||||
if (pid == 0) {
|
||||
PROC_LOCK(q);
|
||||
uap->pid = -q->p_pgid;
|
||||
pid = -q->p_pgid;
|
||||
PROC_UNLOCK(q);
|
||||
}
|
||||
if (uap->options &~ (WUNTRACED|WNOHANG|WCONTINUED|WLINUXCLONE))
|
||||
if (options &~ (WUNTRACED|WNOHANG|WCONTINUED|WLINUXCLONE))
|
||||
return (EINVAL);
|
||||
loop:
|
||||
nfound = 0;
|
||||
sx_xlock(&proctree_lock);
|
||||
LIST_FOREACH(p, &q->p_children, p_sibling) {
|
||||
PROC_LOCK(p);
|
||||
if (uap->pid != WAIT_ANY &&
|
||||
p->p_pid != uap->pid && p->p_pgid != -uap->pid) {
|
||||
if (pid != WAIT_ANY &&
|
||||
p->p_pid != pid && p->p_pgid != -pid) {
|
||||
PROC_UNLOCK(p);
|
||||
continue;
|
||||
}
|
||||
@ -615,7 +615,7 @@ loop:
|
||||
* signifies we want to wait for threads and not processes.
|
||||
*/
|
||||
if ((p->p_sigparent != SIGCHLD) ^
|
||||
((uap->options & WLINUXCLONE) != 0)) {
|
||||
((options & WLINUXCLONE) != 0)) {
|
||||
PROC_UNLOCK(p);
|
||||
continue;
|
||||
}
|
||||
@ -623,37 +623,16 @@ loop:
|
||||
nfound++;
|
||||
if (p->p_state == PRS_ZOMBIE) {
|
||||
td->td_retval[0] = p->p_pid;
|
||||
#ifdef COMPAT_43
|
||||
if (compat)
|
||||
td->td_retval[1] = p->p_xstat;
|
||||
else
|
||||
#endif
|
||||
if (uap->status) {
|
||||
status = p->p_xstat; /* convert to int */
|
||||
PROC_UNLOCK(p);
|
||||
if ((error = copyout(&status,
|
||||
uap->status, sizeof(status)))) {
|
||||
sx_xunlock(&proctree_lock);
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
PROC_LOCK(p);
|
||||
}
|
||||
if (uap->rusage) {
|
||||
bcopy(p->p_ru, &ru, sizeof(ru));
|
||||
PROC_UNLOCK(p);
|
||||
if ((error = copyout(&ru,
|
||||
uap->rusage, sizeof (struct rusage)))) {
|
||||
sx_xunlock(&proctree_lock);
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
} else
|
||||
PROC_UNLOCK(p);
|
||||
if (status)
|
||||
*status = p->p_xstat; /* convert to int */
|
||||
if (rusage)
|
||||
bcopy(p->p_ru, rusage, sizeof(struct rusage));
|
||||
|
||||
/*
|
||||
* If we got the child via a ptrace 'attach',
|
||||
* we need to give it back to the old parent.
|
||||
*/
|
||||
PROC_UNLOCK(p);
|
||||
if (p->p_oppid && (t = pfind(p->p_oppid)) != NULL) {
|
||||
PROC_LOCK(p);
|
||||
p->p_oppid = 0;
|
||||
@ -725,7 +704,7 @@ loop:
|
||||
mac_destroy_proc(p);
|
||||
#endif
|
||||
KASSERT(FIRST_THREAD_IN_PROC(p),
|
||||
("wait1: no residual thread!"));
|
||||
("kern_wait: no residual thread!"));
|
||||
uma_zfree(proc_zone, p);
|
||||
sx_xlock(&allproc_lock);
|
||||
nprocs--;
|
||||
@ -735,44 +714,26 @@ loop:
|
||||
mtx_lock_spin(&sched_lock);
|
||||
if (P_SHOULDSTOP(p) && (p->p_suspcount == p->p_numthreads) &&
|
||||
((p->p_flag & P_WAITED) == 0) &&
|
||||
(p->p_flag & P_TRACED || uap->options & WUNTRACED)) {
|
||||
(p->p_flag & P_TRACED || options & WUNTRACED)) {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
p->p_flag |= P_WAITED;
|
||||
sx_xunlock(&proctree_lock);
|
||||
td->td_retval[0] = p->p_pid;
|
||||
#ifdef COMPAT_43
|
||||
if (compat) {
|
||||
td->td_retval[1] = W_STOPCODE(p->p_xstat);
|
||||
PROC_UNLOCK(p);
|
||||
error = 0;
|
||||
} else
|
||||
#endif
|
||||
if (uap->status) {
|
||||
status = W_STOPCODE(p->p_xstat);
|
||||
PROC_UNLOCK(p);
|
||||
error = copyout(&status,
|
||||
uap->status, sizeof(status));
|
||||
} else {
|
||||
PROC_UNLOCK(p);
|
||||
error = 0;
|
||||
}
|
||||
return (error);
|
||||
if (status)
|
||||
*status = W_STOPCODE(p->p_xstat);
|
||||
PROC_UNLOCK(p);
|
||||
return (0);
|
||||
}
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
if (uap->options & WCONTINUED && (p->p_flag & P_CONTINUED)) {
|
||||
if (options & WCONTINUED && (p->p_flag & P_CONTINUED)) {
|
||||
sx_xunlock(&proctree_lock);
|
||||
td->td_retval[0] = p->p_pid;
|
||||
p->p_flag &= ~P_CONTINUED;
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
if (uap->status) {
|
||||
status = SIGCONT;
|
||||
error = copyout(&status,
|
||||
uap->status, sizeof(status));
|
||||
} else
|
||||
error = 0;
|
||||
|
||||
return (error);
|
||||
if (status)
|
||||
*status = SIGCONT;
|
||||
return (0);
|
||||
}
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
@ -780,7 +741,7 @@ loop:
|
||||
sx_xunlock(&proctree_lock);
|
||||
return (ECHILD);
|
||||
}
|
||||
if (uap->options & WNOHANG) {
|
||||
if (options & WNOHANG) {
|
||||
sx_xunlock(&proctree_lock);
|
||||
td->td_retval[0] = 0;
|
||||
return (0);
|
||||
|
@ -96,7 +96,11 @@
|
||||
#define WAIT_MYPGRP 0 /* any process in my process group */
|
||||
#endif /* __BSD_VISIBLE */
|
||||
|
||||
#ifndef _KERNEL
|
||||
#ifdef _KERNEL
|
||||
int kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
||||
struct rusage *rusage);
|
||||
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
Loading…
x
Reference in New Issue
Block a user