Subject: removing duplicated code from compat version of sys_waitsys
To: None <tech-kern@netbsd.org>
From: David Laight <david@l8s.co.uk>
List: tech-kern
Date: 02/04/2003 16:03:06
The code of sys_waitsys() is replicated in 5 different parts of the
kernel source. The routine in non-trivial and it is quite easy for
the routines to get out of sync - as indeed they are at the moment.
The change below splits syswait_sys() into 3, only the smaller
part has to be replicated in the 'compat' routines.
The 2 new routines are:
int find_stopped_child(struct proc *, pid_t, int, struct proc **);
which searches for a child process in an appropriate state, and:
void proc_free(struct proc *);
which frees all the data areas associated with a process after it is
finished with.
I'm fairly happy that the standard sys_waitsys() if fine, however
I can't test the compat versions so it would be useful if someone
would volunteer. In particulat compat/irix only applies to sgimips,
compat/netbsd32 and compat/svr4_32 to sparc64 and I don't have
any binaries for compat/svr4.
A job control shell probably tests the important paths - the most
likely errors are (as always) inverted comparisons.
Oh, christos thinks this is a good idea :-)
These diffs make the changes look much worse than they actually are...
David
Index: sys/sys/proc.h
===================================================================
RCS file: /cvsroot/src/sys/sys/proc.h,v
retrieving revision 1.156
diff -u -r1.156 proc.h
--- sys/sys/proc.h 2003/02/01 06:23:51 1.156
+++ sys/sys/proc.h 2003/02/04 13:17:27
@@ -437,6 +437,8 @@
void reaper(void *);
void exit1(struct lwp *, int);
void exit2(struct lwp *);
+int find_stopped_child(struct proc *, pid_t, int, struct proc **);
+void proc_free(struct proc *);
void exit_lwps(struct lwp *l);
int fork1(struct lwp *, int, int, void *, size_t,
void (*)(void *), void *, register_t *, struct proc **);
Index: sys/sys/wait.h
===================================================================
RCS file: /cvsroot/src/sys/sys/wait.h,v
retrieving revision 1.17
diff -u -r1.17 wait.h
--- sys/sys/wait.h 2001/07/18 19:10:26 1.17
+++ sys/sys/wait.h 2003/02/04 13:17:28
@@ -95,6 +95,13 @@
*/
#define __WCLONE WALTSIG
#define __WALL WALLSIG
+
+/*
+ * These bits are used in order to support SVR4 (etc) functionality
+ * without replicating sys_wait4 5 times.
+ */
+#define WNOWAIT 0x00010000 /* Don't mark child 'P_WAITED' */
+#define WNOZOMBIE 0x00020000 /* Ignore zombies */
#endif /* ! _POSIX_SOURCE */
#ifndef _POSIX_SOURCE
Index: sys/kern/kern_exit.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_exit.c,v
retrieving revision 1.108
diff -u -r1.108 kern_exit.c
--- sys/kern/kern_exit.c 2003/01/27 20:30:32 1.108
+++ sys/kern/kern_exit.c 2003/02/04 13:17:24
@@ -610,140 +612,186 @@
syscallarg(int) options;
syscallarg(struct rusage *) rusage;
} */ *uap = v;
- struct proc *p, *q, *t;
- int nfound, status, error, s;
+ struct proc *child, *parent;
+ int status, error;
- q = l->l_proc;
+ parent = l->l_proc;
if (SCARG(uap, pid) == 0)
- SCARG(uap, pid) = -q->p_pgid;
- if (SCARG(uap, options) &~ (WUNTRACED|WNOHANG|WALTSIG))
+ SCARG(uap, pid) = -parent->p_pgid;
+ if (SCARG(uap, options) & ~(WUNTRACED|WNOHANG|WALTSIG|WALLSIG))
return (EINVAL);
- loop:
- nfound = 0;
- LIST_FOREACH(p, &q->p_children, p_sibling) {
- if (SCARG(uap, pid) != WAIT_ANY &&
- p->p_pid != SCARG(uap, pid) &&
- p->p_pgid != -SCARG(uap, pid))
- continue;
- /*
- * Wait for processes with p_exitsig != SIGCHLD processes only
- * if WALTSIG is set; wait for processes with p_exitsig ==
- * SIGCHLD only if WALTSIG is clear.
- */
- if (((SCARG(uap, options) & WALLSIG) == 0) &&
- ((SCARG(uap, options) & WALTSIG) ?
- (p->p_exitsig == SIGCHLD) : (P_EXITSIG(p) != SIGCHLD)))
- continue;
+ error = find_stopped_child(parent, SCARG(uap,pid), SCARG(uap,options),
+ &child);
+ if (error != 0)
+ return error;
+ if (child == NULL) {
+ *retval = 0;
+ return 0;
+ }
- nfound++;
- if (p->p_stat == SZOMB) {
- retval[0] = p->p_pid;
-
- if (SCARG(uap, status)) {
- status = p->p_xstat; /* convert to int */
- error = copyout((caddr_t)&status,
- (caddr_t)SCARG(uap, status),
- sizeof(status));
- if (error)
- return (error);
- }
- if (SCARG(uap, rusage) &&
- (error = copyout((caddr_t)p->p_ru,
- (caddr_t)SCARG(uap, rusage),
- sizeof(struct rusage))))
- return (error);
- /*
- * If we got the child via ptrace(2) or procfs, and
- * the parent is different (meaning the process was
- * attached, rather than run as a child), then we need
- * to give it back to the old parent, and send the
- * parent the exit signal. The rest of the cleanup
- * will be done when the old parent waits on the child.
- */
- if ((p->p_flag & P_TRACED) && p->p_opptr != p->p_pptr){
- t = p->p_opptr;
- proc_reparent(p, t ? t : initproc);
- p->p_opptr = NULL;
- p->p_flag &= ~(P_TRACED|P_WAITED|P_FSTRACE);
- if (p->p_exitsig != 0)
- psignal(p->p_pptr, P_EXITSIG(p));
- wakeup((caddr_t)p->p_pptr);
- return (0);
- }
- scheduler_wait_hook(q, p);
- p->p_xstat = 0;
- ruadd(&q->p_stats->p_cru, p->p_ru);
- pool_put(&rusage_pool, p->p_ru);
+ retval[0] = child->p_pid;
- /*
- * Finally finished with old proc entry.
- * Unlink it from its process group and free it.
- */
- leavepgrp(p);
+ if (child->p_stat == SZOMB) {
+ if (SCARG(uap, status)) {
+ status = child->p_xstat; /* convert to int */
+ error = copyout((caddr_t)&status,
+ (caddr_t)SCARG(uap, status),
+ sizeof(status));
+ if (error)
+ return (error);
+ }
+ if (SCARG(uap, rusage)) {
+ error = copyout((caddr_t)child->p_ru,
+ (caddr_t)SCARG(uap, rusage),
+ sizeof(struct rusage));
+ if (error)
+ return (error);
+ }
- s = proclist_lock_write();
- LIST_REMOVE(p, p_list); /* off zombproc */
- proclist_unlock_write(s);
+ proc_free(child);
+ return 0;
+ }
- LIST_REMOVE(p, p_sibling);
+ /* child state must be SSTOP */
+ if (SCARG(uap, status)) {
+ status = W_STOPCODE(child->p_xstat);
+ return copyout((caddr_t)&status,
+ (caddr_t)SCARG(uap, status),
+ sizeof(status));
+ }
+ return 0;
+}
- /*
- * Decrement the count of procs running with this uid.
- */
- (void)chgproccnt(p->p_cred->p_ruid, -1);
+int
+find_stopped_child(struct proc *parent, pid_t pid, int options,
+ struct proc **child_p)
+{
+ struct proc *child;
+ int c_found, error;
+ do {
+ c_found = 0;
+ LIST_FOREACH(child, &parent->p_children, p_sibling) {
+ if (pid != WAIT_ANY &&
+ child->p_pid != pid &&
+ child->p_pgid != -pid)
+ continue;
/*
- * Free up credentials.
+ * Wait for processes with p_exitsig != SIGCHLD
+ * processes only if WALTSIG is set; wait for
+ * processes with p_exitsig == * SIGCHLD only
+ * if WALTSIG is clear.
*/
- if (--p->p_cred->p_refcnt == 0) {
- crfree(p->p_cred->pc_ucred);
- pool_put(&pcred_pool, p->p_cred);
+ if (((options & WALLSIG) == 0) &&
+ (options & WALTSIG ? child->p_exitsig == SIGCHLD
+ : P_EXITSIG(child) != SIGCHLD))
+ continue;
+
+ c_found = 1;
+ if (child->p_stat == SZOMB &&
+ (options & WNOZOMBIE) == 0) {
+ *child_p = child;
+ return 0;
}
-
- /*
- * Release reference to text vnode
- */
- if (p->p_textvp)
- vrele(p->p_textvp);
- /*
- * Release any SA state
- */
- if (p->p_sa) {
- free(p->p_sa->sa_stacks, M_SA);
- pool_put(&sadata_pool, p->p_sa);
+ if (child->p_stat == SSTOP &&
+ (child->p_flag & P_WAITED) == 0 &&
+ (child->p_flag & P_TRACED || options & WUNTRACED)) {
+ if ((options & WNOWAIT) == 0)
+ child->p_flag |= P_WAITED;
+ *child_p = child;
+ return 0;
}
-
- pool_put(&proc_pool, p);
- nprocs--;
- return (0);
}
- if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 &&
- (p->p_flag & P_TRACED || SCARG(uap, options) & WUNTRACED)) {
- p->p_flag |= P_WAITED;
- retval[0] = p->p_pid;
-
- if (SCARG(uap, status)) {
- status = W_STOPCODE(p->p_xstat);
- error = copyout((caddr_t)&status,
- (caddr_t)SCARG(uap, status),
- sizeof(status));
- } else
- error = 0;
- return (error);
+ if (c_found == 0)
+ return (ECHILD);
+ if (options & WNOHANG) {
+ *child_p = 0;
+ return 0;
}
+ error = tsleep((caddr_t)parent, PWAIT | PCATCH, "wait", 0);
+ } while (error == 0);
+ return error;
+}
+
+/* Free a process after parent has taken all the state info... */
+
+void
+proc_free(struct proc *p)
+{
+ struct proc *parent = p->p_pptr;
+ int s;
+
+ /*
+ * If we got the child via ptrace(2) or procfs, and
+ * the parent is different (meaning the process was
+ * attached, rather than run as a child), then we need
+ * to give it back to the old parent, and send the
+ * parent the exit signal. The rest of the cleanup
+ * will be done when the old parent waits on the child.
+ */
+ if ((p->p_flag & P_TRACED) && p->p_opptr != parent){
+ parent = p->p_opptr;
+ if (parent == NULL)
+ parent = initproc;
+ proc_reparent(p, parent);
+ p->p_opptr = NULL;
+ p->p_flag &= ~(P_TRACED|P_WAITED|P_FSTRACE);
+ if (p->p_exitsig != 0)
+ psignal(parent, P_EXITSIG(p));
+ wakeup((caddr_t)parent);
+ return;
}
- if (nfound == 0)
- return (ECHILD);
- if (SCARG(uap, options) & WNOHANG) {
- retval[0] = 0;
- return (0);
- }
- if ((error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)) != 0)
- return (error);
- goto loop;
+
+ scheduler_wait_hook(parent, p);
+ p->p_xstat = 0;
+ ruadd(&parent->p_stats->p_cru, p->p_ru);
+ pool_put(&rusage_pool, p->p_ru);
+
+ /*
+ * Finally finished with old proc entry.
+ * Unlink it from its process group and free it.
+ */
+ leavepgrp(p);
+
+ s = proclist_lock_write();
+ LIST_REMOVE(p, p_list); /* off zombproc */
+ proclist_unlock_write(s);
+
+ LIST_REMOVE(p, p_sibling);
+
+ /*
+ * Decrement the count of procs running with this uid.
+ */
+ (void)chgproccnt(p->p_cred->p_ruid, -1);
+
+ /*
+ * Free up credentials.
+ */
+ if (--p->p_cred->p_refcnt == 0) {
+ crfree(p->p_cred->pc_ucred);
+ pool_put(&pcred_pool, p->p_cred);
+ }
+
+ /*
+ * Release reference to text vnode
+ */
+ if (p->p_textvp)
+ vrele(p->p_textvp);
+
+ /*
+ * Release any SA state
+ */
+ if (p->p_sa) {
+ free(p->p_sa->sa_stacks, M_SA);
+ pool_put(&sadata_pool, p->p_sa);
+ }
+
+ pool_put(&proc_pool, p);
+ nprocs--;
+ return;
}
/*
Index: sys/compat/irix/irix_signal.c
===================================================================
RCS file: /cvsroot/src/sys/compat/irix/irix_signal.c,v
retrieving revision 1.24
diff -u -r1.24 irix_signal.c
--- sys/compat/irix/irix_signal.c 2003/01/22 12:58:23 1.24
+++ sys/compat/irix/irix_signal.c 2003/02/04 13:17:09
@@ -837,16 +837,17 @@
syscallarg(int) options;
syscallarg(struct rusage *) ru;
} */ *uap = v;
- struct proc *p = l->l_proc;
+ struct proc *parent = l->l_proc;
int nfound, error, s;
- struct proc *q, *t;
+ struct proc *child, *t;
+ int options;
switch (SCARG(uap, type)) {
case SVR4_P_PID:
break;
case SVR4_P_PGID:
- SCARG(uap, pid) = -p->p_pgid;
+ SCARG(uap, pid) = -parent->p_pgid;
break;
case SVR4_P_ALL:
@@ -863,125 +864,57 @@
SCARG(uap, info), SCARG(uap, options), SCARG(uap, ru));
#endif
-loop:
- nfound = 0;
- for (q = p->p_children.lh_first; q != 0; q = q->p_sibling.le_next) {
- if (SCARG(uap, pid) != WAIT_ANY &&
- q->p_pid != SCARG(uap, pid) &&
- q->p_pgid != -SCARG(uap, pid)) {
-#ifdef DEBUG_IRIX
- printf("pid %d pgid %d != %d\n", q->p_pid,
- q->p_pgid, SCARG(uap, pid));
-#endif
- continue;
- }
- nfound++;
- if (q->p_stat == SZOMB &&
- ((SCARG(uap, options) & (SVR4_WEXITED|SVR4_WTRAPPED)))) {
- *retval = 0;
+ /* Translate options */
+ options = 0;
+ if (SCARG(uap, options) & SVR4_WNOWAIT)
+ options |= WNOWAIT;
+ if (SCARG(uap, options) & SVR4_WNOHANG)
+ options |= WNOHANG;
+ if ((SCARG(uap, options) & (SVR4_WEXITED|SVR4_WTRAPPED)) == 0)
+ options |= WNOZOMBIE;
+ if (SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED))
+ options |= WUNTRACED;
+
+ error = find_stopped_child(parent, SCARG(uap,pid), options, &child);
+ if (error != 0)
+ return error;
+ *retval = 0;
+ if (child == NULL)
+ return irix_wait_siginfo(NULL, 0, SCARG(uap, info));
+
+ if (child->p_stat == SZOMB) {
#ifdef DEBUG_IRIX
- printf("irix_sys_wait(): found %d\n", q->p_pid);
+ printf("irix_sys_wait(): found %d\n", child->p_pid);
#endif
- if ((error = irix_wait_siginfo(q, q->p_xstat,
+ if ((error = irix_wait_siginfo(child, child->p_xstat,
SCARG(uap, info))) != 0)
- return error;
+ return error;
- if ((SCARG(uap, options) & SVR4_WNOWAIT)) {
+ if ((SCARG(uap, options) & SVR4_WNOWAIT)) {
#ifdef DEBUG_IRIX
- printf(("irix_sys_wait(): Don't wait\n"));
+ printf(("irix_sys_wait(): Don't wait\n"));
#endif
- return 0;
- }
- if (SCARG(uap, ru) &&
- (error = copyout(&(p->p_stats->p_ru),
- (caddr_t)SCARG(uap, ru), sizeof(struct rusage))))
- return (error);
-
- /*
- * If we got the child via ptrace(2) or procfs, and
- * the parent is different (meaning the process was
- * attached, rather than run as a child), then we need
- * to give it back to the old parent, and send the
- * parent a SIGCHLD. The rest of the cleanup will be
- * done when the old parent waits on the child.
- */
- if ((q->p_flag & P_TRACED) && q->p_opptr != q->p_pptr){
- t = q->p_opptr;
- proc_reparent(q, t ? t : initproc);
- q->p_opptr = NULL;
- q->p_flag &= ~(P_TRACED|P_WAITED|P_FSTRACE);
- psignal(q->p_pptr, SIGCHLD);
- wakeup((caddr_t)q->p_pptr);
- return (0);
- }
- q->p_xstat = 0;
- ruadd(&p->p_stats->p_cru, q->p_ru);
- pool_put(&rusage_pool, q->p_ru);
-
- /*
- * Finally finished with old proc entry.
- * Unlink it from its process group and free it.
- */
- leavepgrp(q);
-
- s = proclist_lock_write();
- LIST_REMOVE(q, p_list); /* off zombproc */
- proclist_unlock_write(s);
-
- LIST_REMOVE(q, p_sibling);
-
- /*
- * Decrement the count of procs running with this uid.
- */
- (void)chgproccnt(q->p_cred->p_ruid, -1);
-
- /*
- * Free up credentials.
- */
- if (--q->p_cred->p_refcnt == 0) {
- crfree(q->p_cred->pc_ucred);
- pool_put(&pcred_pool, q->p_cred);
- }
-
- /*
- * Release reference to text vnode
- */
- if (q->p_textvp)
- vrele(q->p_textvp);
-
- pool_put(&proc_pool, q);
- nprocs--;
return 0;
- }
- if (q->p_stat == SSTOP && (q->p_flag & P_WAITED) == 0 &&
- (q->p_flag & P_TRACED ||
- (SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED)))) {
-#ifdef DEBUG_IRIX
- printf("jobcontrol %d\n", q->p_pid);
-#endif
- if (((SCARG(uap, options) & SVR4_WNOWAIT)) == 0)
- q->p_flag |= P_WAITED;
- *retval = 0;
- return irix_wait_siginfo(q, W_STOPCODE(q->p_xstat),
- SCARG(uap, info));
}
- }
-
- if (nfound == 0)
- return ECHILD;
-
- if (SCARG(uap, options) & SVR4_WNOHANG) {
- *retval = 0;
- if ((error = irix_wait_siginfo(NULL, 0, SCARG(uap, info))) != 0)
+ if (SCARG(uap, ru) &&
+ /* XXX (dsl) is this copying out the right data???
+ child->p_ru would seem more appropriate! */
+ (error = copyout(&(parent->p_stats->p_ru),
+ (caddr_t)SCARG(uap, ru), sizeof(struct rusage))))
return error;
+
+ proc_free(child);
return 0;
}
- if ((error = tsleep((caddr_t)p, PWAIT | PCATCH, "svr4_wait", 0)) != 0)
- return error;
- goto loop;
+ /* Child state must be SSTOP */
+#ifdef DEBUG_IRIX
+ printf("jobcontrol %d\n", child->p_pid);
+#endif
+ return irix_wait_siginfo(child, W_STOPCODE(child->p_xstat),
+ SCARG(uap, info));
}
int
Index: sys/compat/netbsd32/netbsd32_wait.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_wait.c,v
retrieving revision 1.5
diff -u -r1.5 netbsd32_wait.c
--- sys/compat/netbsd32/netbsd32_wait.c 2003/01/18 08:28:26 1.5
+++ sys/compat/netbsd32/netbsd32_wait.c 2003/02/04 13:17:10
@@ -58,121 +58,54 @@
syscallarg(int) options;
syscallarg(netbsd32_rusagep_t) rusage;
} */ *uap = v;
- struct proc *q = l->l_proc;
+ struct proc *parent = l->l_proc;
struct netbsd32_rusage ru32;
- int nfound;
- struct proc *p, *t;
+ struct proc *child;
int status, error;
if (SCARG(uap, pid) == 0)
- SCARG(uap, pid) = -q->p_pgid;
+ SCARG(uap, pid) = -parent->p_pgid;
if (SCARG(uap, options) &~ (WUNTRACED|WNOHANG))
return (EINVAL);
-loop:
- nfound = 0;
- for (p = q->p_children.lh_first; p != 0; p = p->p_sibling.le_next) {
- if (SCARG(uap, pid) != WAIT_ANY &&
- p->p_pid != SCARG(uap, pid) &&
- p->p_pgid != -SCARG(uap, pid))
- continue;
- nfound++;
- if (p->p_stat == SZOMB) {
- retval[0] = p->p_pid;
+ error = find_stopped_child(parent, SCARG(uap,pid), SCARG(uap,options),
+ &child);
+ if (error != 0)
+ return error;
+ if (child == NULL) {
+ retval[0] = 0;
+ return 0;
+ }
- if (SCARG(uap, status)) {
- status = p->p_xstat; /* convert to int */
- error = copyout((caddr_t)&status,
+ retval[0] = child->p_pid;
+ if (child->p_stat == SZOMB) {
+ if (SCARG(uap, status)) {
+ status = child->p_xstat; /* convert to int */
+ error = copyout((caddr_t)&status,
(caddr_t)NETBSD32PTR64(SCARG(uap, status)),
sizeof(status));
- if (error)
- return (error);
- }
- if (SCARG(uap, rusage)) {
- netbsd32_from_rusage(p->p_ru, &ru32);
- if ((error = copyout((caddr_t)&ru32,
- (caddr_t)NETBSD32PTR64(SCARG(uap, rusage)),
- sizeof(struct netbsd32_rusage))))
- return (error);
- }
- /*
- * If we got the child via ptrace(2) or procfs, and
- * the parent is different (meaning the process was
- * attached, rather than run as a child), then we need
- * to give it back to the old parent, and send the
- * parent a SIGCHLD. The rest of the cleanup will be
- * done when the old parent waits on the child.
- */
- if ((p->p_flag & P_TRACED) && p->p_opptr != p->p_pptr){
- t = p->p_opptr;
- proc_reparent(p, t ? t : initproc);
- p->p_opptr = NULL;
- p->p_flag &= ~(P_TRACED|P_WAITED|P_FSTRACE);
- psignal(p->p_pptr, SIGCHLD);
- wakeup((caddr_t)p->p_pptr);
- return (0);
- }
- p->p_xstat = 0;
- ruadd(&q->p_stats->p_cru, p->p_ru);
- pool_put(&rusage_pool, p->p_ru);
-
- /*
- * Finally finished with old proc entry.
- * Unlink it from its process group and free it.
- */
- leavepgrp(p);
-
- LIST_REMOVE(p, p_list); /* off zombproc */
-
- LIST_REMOVE(p, p_sibling);
-
- /*
- * Decrement the count of procs running with this uid.
- */
- (void)chgproccnt(p->p_cred->p_ruid, -1);
-
- /*
- * Free up credentials.
- */
- if (--p->p_cred->p_refcnt == 0) {
- crfree(p->p_cred->pc_ucred);
- pool_put(&pcred_pool, p->p_cred);
- }
-
- /*
- * Release reference to text vnode
- */
- if (p->p_textvp)
- vrele(p->p_textvp);
-
- pool_put(&proc_pool, p);
- nprocs--;
- return (0);
+ if (error)
+ return error;
}
- if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 &&
- (p->p_flag & P_TRACED || SCARG(uap, options) & WUNTRACED)) {
- p->p_flag |= P_WAITED;
- retval[0] = p->p_pid;
-
- if (SCARG(uap, status)) {
- status = W_STOPCODE(p->p_xstat);
- error = copyout((caddr_t)&status,
- (caddr_t)NETBSD32PTR64(SCARG(uap, status)),
- sizeof(status));
- } else
- error = 0;
- return (error);
+ if (SCARG(uap, rusage)) {
+ netbsd32_from_rusage(child->p_ru, &ru32);
+ error = copyout((caddr_t)&ru32,
+ (caddr_t)NETBSD32PTR64(SCARG(uap, rusage)),
+ sizeof(struct netbsd32_rusage));
+ if (error)
+ return error;
}
+ proc_free(child);
+ return 0;
}
- if (nfound == 0)
- return (ECHILD);
- if (SCARG(uap, options) & WNOHANG) {
- retval[0] = 0;
- return (0);
+
+ if (SCARG(uap, status)) {
+ status = W_STOPCODE(child->p_xstat);
+ return copyout((caddr_t)&status,
+ (caddr_t)NETBSD32PTR64(SCARG(uap, status)),
+ sizeof(status));
}
- if ((error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)) != 0)
- return (error);
- goto loop;
+ return 0;
}
int
Index: sys/compat/svr4/svr4_misc.c
===================================================================
RCS file: /cvsroot/src/sys/compat/svr4/svr4_misc.c,v
retrieving revision 1.101
diff -u -r1.101 svr4_misc.c
--- sys/compat/svr4/svr4_misc.c 2003/01/29 07:00:39 1.101
+++ sys/compat/svr4/svr4_misc.c 2003/02/04 13:17:15
@@ -1182,17 +1182,17 @@
register_t *retval;
{
struct svr4_sys_waitsys_args *uap = v;
- int nfound, error, s;
- struct proc *p = l->l_proc;
- struct proc *q, *t;
+ int options;
+ int error;
+ struct proc *parent = l->l_proc;
+ struct proc *child;
-
switch (SCARG(uap, grp)) {
case SVR4_P_PID:
break;
case SVR4_P_PGID:
- SCARG(uap, id) = -p->p_pgid;
+ SCARG(uap, id) = -parent->p_pgid;
break;
case SVR4_P_ALL:
@@ -1203,116 +1203,47 @@
return EINVAL;
}
+ /* Translate options */
+ options = 0;
+ if (SCARG(uap, options) & SVR4_WNOWAIT)
+ options |= WNOWAIT;
+ if (SCARG(uap, options) & SVR4_WNOHANG)
+ options |= WNOHANG;
+ if ((SCARG(uap, options) & (SVR4_WEXITED|SVR4_WTRAPPED)) == 0)
+ options |= WNOZOMBIE;
+ if (SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED))
+ options |= WUNTRACED;
+
DPRINTF(("waitsys(%d, %d, %p, %x)\n",
SCARG(uap, grp), SCARG(uap, id),
SCARG(uap, info), SCARG(uap, options)));
-loop:
- nfound = 0;
- for (q = p->p_children.lh_first; q != 0; q = q->p_sibling.le_next) {
- if (SCARG(uap, id) != WAIT_ANY &&
- q->p_pid != SCARG(uap, id) &&
- q->p_pgid != -SCARG(uap, id)) {
- DPRINTF(("pid %d pgid %d != %d\n", q->p_pid,
- q->p_pgid, SCARG(uap, id)));
- continue;
- }
- nfound++;
- if (q->p_stat == SZOMB &&
- ((SCARG(uap, options) & (SVR4_WEXITED|SVR4_WTRAPPED)))) {
- *retval = 0;
- DPRINTF(("found %d\n", q->p_pid));
- if ((error = svr4_setinfo(q, q->p_xstat,
- SCARG(uap, info))) != 0)
- return error;
-
-
- if ((SCARG(uap, options) & SVR4_WNOWAIT)) {
- DPRINTF(("Don't wait\n"));
- return 0;
- }
-
- /*
- * If we got the child via ptrace(2) or procfs, and
- * the parent is different (meaning the process was
- * attached, rather than run as a child), then we need
- * to give it back to the old parent, and send the
- * parent a SIGCHLD. The rest of the cleanup will be
- * done when the old parent waits on the child.
- */
- if ((q->p_flag & P_TRACED) && q->p_opptr != q->p_pptr){
- t = q->p_opptr;
- proc_reparent(q, t ? t : initproc);
- q->p_opptr = NULL;
- q->p_flag &= ~(P_TRACED|P_WAITED|P_FSTRACE);
- psignal(q->p_pptr, SIGCHLD);
- wakeup((caddr_t)q->p_pptr);
- return (0);
- }
- q->p_xstat = 0;
- ruadd(&p->p_stats->p_cru, q->p_ru);
- pool_put(&rusage_pool, q->p_ru);
-
- /*
- * Finally finished with old proc entry.
- * Unlink it from its process group and free it.
- */
- leavepgrp(q);
-
- s = proclist_lock_write();
- LIST_REMOVE(q, p_list); /* off zombproc */
- proclist_unlock_write(s);
-
- LIST_REMOVE(q, p_sibling);
-
- /*
- * Decrement the count of procs running with this uid.
- */
- (void)chgproccnt(q->p_cred->p_ruid, -1);
-
- /*
- * Free up credentials.
- */
- if (--q->p_cred->p_refcnt == 0) {
- crfree(q->p_cred->pc_ucred);
- pool_put(&pcred_pool, q->p_cred);
- }
-
- /*
- * Release reference to text vnode
- */
- if (q->p_textvp)
- vrele(q->p_textvp);
+ error = find_stopped_child(parent, SCARG(uap, id), options, &child);
+ if (error != 0)
+ return error;
+ *retval = 0;
+ if (child == NULL)
+ return svr4_setinfo(NULL, 0, SCARG(uap, info));
+
+ if (child->p_stat == SZOMB) {
+ DPRINTF(("found %d\n", child->p_pid));
+ if ((error = svr4_setinfo(child, child->p_xstat,
+ SCARG(uap, info))) != 0)
+ return error;
+
- pool_put(&proc_pool, q);
- nprocs--;
+ if ((SCARG(uap, options) & SVR4_WNOWAIT)) {
+ DPRINTF(("Don't wait\n"));
return 0;
}
- if (q->p_stat == SSTOP && (q->p_flag & P_WAITED) == 0 &&
- (q->p_flag & P_TRACED ||
- (SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED)))) {
- DPRINTF(("jobcontrol %d\n", q->p_pid));
- if (((SCARG(uap, options) & SVR4_WNOWAIT)) == 0)
- q->p_flag |= P_WAITED;
- *retval = 0;
- return svr4_setinfo(q, W_STOPCODE(q->p_xstat),
- SCARG(uap, info));
- }
- }
-
- if (nfound == 0)
- return ECHILD;
- if (SCARG(uap, options) & SVR4_WNOHANG) {
- *retval = 0;
- if ((error = svr4_setinfo(NULL, 0, SCARG(uap, info))) != 0)
- return error;
+ proc_free(child);
return 0;
}
- if ((error = tsleep((caddr_t)p, PWAIT | PCATCH, "svr4_wait", 0)) != 0)
- return error;
- goto loop;
+ DPRINTF(("jobcontrol %d\n", child->p_pid));
+ return svr4_setinfo(child, W_STOPCODE(child->p_xstat),
+ SCARG(uap, info));
}
Index: sys/compat/svr4_32/svr4_32_misc.c
===================================================================
RCS file: /cvsroot/src/sys/compat/svr4_32/svr4_32_misc.c,v
retrieving revision 1.16
diff -u -r1.16 svr4_32_misc.c
--- sys/compat/svr4_32/svr4_32_misc.c 2003/01/29 07:00:40 1.16
+++ sys/compat/svr4_32/svr4_32_misc.c 2003/02/04 13:17:20
@@ -1201,17 +1201,16 @@
register_t *retval;
{
struct svr4_32_sys_waitsys_args *uap = v;
- struct proc *p = l->l_proc;
- int nfound, error, s;
- struct proc *q, *t;
+ struct proc *parent = l->l_proc;
+ int options, error;
+ struct proc *child;
-
switch (SCARG(uap, grp)) {
case SVR4_P_PID:
break;
case SVR4_P_PGID:
- SCARG(uap, id) = -p->p_pgid;
+ SCARG(uap, id) = -parent->p_pgid;
break;
case SVR4_P_ALL:
@@ -1226,112 +1225,42 @@
SCARG(uap, grp), SCARG(uap, id),
SCARG(uap, info), SCARG(uap, options)));
-loop:
- nfound = 0;
- for (q = p->p_children.lh_first; q != 0; q = q->p_sibling.le_next) {
- if (SCARG(uap, id) != WAIT_ANY &&
- q->p_pid != SCARG(uap, id) &&
- q->p_pgid != -SCARG(uap, id)) {
- DPRINTF(("pid %d pgid %d != %d\n", q->p_pid,
- q->p_pgid, SCARG(uap, id)));
- continue;
- }
- nfound++;
- if (q->p_stat == SZOMB &&
- ((SCARG(uap, options) & (SVR4_WEXITED|SVR4_WTRAPPED)))) {
- *retval = 0;
- DPRINTF(("found %d\n", q->p_pid));
- if ((error =
- svr4_32_setinfo(q, q->p_xstat, SCARG(uap, info))) != 0)
- return error;
-
-
- if ((SCARG(uap, options) & SVR4_WNOWAIT)) {
- DPRINTF(("Don't wait\n"));
- return 0;
- }
-
- /*
- * If we got the child via ptrace(2) or procfs, and
- * the parent is different (meaning the process was
- * attached, rather than run as a child), then we need
- * to give it back to the old parent, and send the
- * parent a SIGCHLD. The rest of the cleanup will be
- * done when the old parent waits on the child.
- */
- if ((q->p_flag & P_TRACED) && q->p_opptr != q->p_pptr){
- t = q->p_opptr;
- proc_reparent(q, t ? t : initproc);
- q->p_opptr = NULL;
- q->p_flag &= ~(P_TRACED|P_WAITED|P_FSTRACE);
- psignal(q->p_pptr, SIGCHLD);
- wakeup((caddr_t)q->p_pptr);
- return (0);
- }
- q->p_xstat = 0;
- ruadd(&p->p_stats->p_cru, q->p_ru);
- pool_put(&rusage_pool, q->p_ru);
-
- /*
- * Finally finished with old proc entry.
- * Unlink it from its process group and free it.
- */
- leavepgrp(q);
-
- s = proclist_lock_write();
- LIST_REMOVE(q, p_list); /* off zombproc */
- proclist_unlock_write(s);
-
- LIST_REMOVE(q, p_sibling);
-
- /*
- * Decrement the count of procs running with this uid.
- */
- (void)chgproccnt(q->p_cred->p_ruid, -1);
-
- /*
- * Free up credentials.
- */
- if (--q->p_cred->p_refcnt == 0) {
- crfree(q->p_cred->pc_ucred);
- pool_put(&pcred_pool, q->p_cred);
- }
-
- /*
- * Release reference to text vnode
- */
- if (q->p_textvp)
- vrele(q->p_textvp);
+ /* Translate options */
+ options = 0;
+ if (SCARG(uap, options) & SVR4_WNOWAIT)
+ options |= WNOWAIT;
+ if (SCARG(uap, options) & SVR4_WNOHANG)
+ options |= WNOHANG;
+ if ((SCARG(uap, options) & (SVR4_WEXITED|SVR4_WTRAPPED)) == 0)
+ options |= WNOZOMBIE;
+ if (SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED))
+ options |= WUNTRACED;
+
+ error = find_stopped_child(parent, SCARG(uap, id), options, &child);
+ if (error != 0)
+ return error;
+ *retval = 0;
+ if (child == NULL)
+ return svr4_32_setinfo(NULL, 0, SCARG(uap, info));
+
+ if (child->p_stat == SZOMB) {
+ DPRINTF(("found %d\n", child->p_pid));
+ error = svr4_32_setinfo(child, child->p_xstat, SCARG(uap,info));
+ if (error)
+ return error;
- pool_put(&proc_pool, q);
- nprocs--;
+ if ((SCARG(uap, options) & SVR4_WNOWAIT)) {
+ DPRINTF(("Don't wait\n"));
return 0;
}
- if (q->p_stat == SSTOP && (q->p_flag & P_WAITED) == 0 &&
- (q->p_flag & P_TRACED ||
- (SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED)))) {
- DPRINTF(("jobcontrol %d\n", q->p_pid));
- if (((SCARG(uap, options) & SVR4_WNOWAIT)) == 0)
- q->p_flag |= P_WAITED;
- *retval = 0;
- return svr4_32_setinfo(q, W_STOPCODE(q->p_xstat),
- SCARG(uap, info));
- }
- }
-
- if (nfound == 0)
- return ECHILD;
- if (SCARG(uap, options) & SVR4_WNOHANG) {
- *retval = 0;
- if ((error = svr4_32_setinfo(NULL, 0, SCARG(uap, info))) != 0)
- return error;
+ proc_free(child);
return 0;
}
- if ((error = tsleep((caddr_t)p, PWAIT | PCATCH, "svr4_32_wait", 0)) != 0)
- return error;
- goto loop;
+ DPRINTF(("jobcontrol %d\n", child->p_pid));
+ return svr4_32_setinfo(child, W_STOPCODE(child->p_xstat),
+ SCARG(uap, info));
}
--
David Laight: david@l8s.co.uk