+ if ((error = tsleep0((caddr_t)q, PWAIT | PCATCH, "wait", 0, wait1continue)))
+ return (error);
+
+ goto loop;
+}
+
+
+int
+waitidcontinue(int result)
+{
+ void *vt;
+ thread_t thread;
+ int *retval;
+ struct proc *p;
+
+ if (result)
+ return(result);
+
+ p = current_proc();
+ thread = current_thread();
+ vt = get_bsduthreadarg(thread);
+ retval = get_bsduthreadrval(thread);
+ return(waitid((struct proc *)p, (struct waitid_args *)vt, retval));
+}
+
+/*
+ * Description: Suspend the calling thread until one child of the process
+ * containing the calling thread changes state.
+ *
+ * Parameters: uap->idtype one of P_PID, P_PGID, P_ALL
+ * uap->id pid_t or gid_t or ignored
+ * uap->infop Address of signinfo_t struct in
+ * user space into which to return status
+ * uap->options flag values
+ *
+ * Returns: 0 Success
+ * !0 Error returning status to user space
+ */
+int
+waitid(struct proc *q, struct waitid_args *uap, register_t *retval)
+{
+ user_siginfo_t collect64; /* siginfo data to return to caller */
+
+ register int nfound;
+ register struct proc *p;
+ int error;
+
+loop:
+ nfound = 0;
+ for (p = q->p_children.lh_first; p != 0; p = p->p_sibling.le_next) {
+ switch(uap->idtype) {
+ case P_PID: /* child with process ID equal to... */
+ if (p->p_pid != (pid_t)uap->id)
+ continue;
+ break;
+ case P_PGID: /* child with process group ID equal to... */
+ if (p->p_pgid != (pid_t)uap->id)
+ continue;
+ break;
+ case P_ALL: /* any child */
+ break;
+ }
+
+ /* XXX This is racy because we don't get the lock!!!! */
+
+ /*
+ * Wait collision; go to sleep and restart; used to maintain
+ * the single return for waited process guarantee.
+ */
+ if (p->p_lflag & P_LWAITING) {
+ (void)tsleep(&p->p_stat, PWAIT, "waitidcoll", 0);
+ goto loop;
+ }
+ p->p_lflag |= P_LWAITING; /* mark busy */
+
+ nfound++;
+
+ /*
+ * Types of processes we are interested in
+ *
+ * XXX Don't know what to do for WCONTINUED?!?
+ */
+ switch(p->p_stat) {
+ case SZOMB: /* Exited */
+ if (!(uap->options & WEXITED))
+ break;
+
+ /* Collect "siginfo" information for caller */
+ collect64.si_signo = 0;
+ collect64.si_code = 0;
+ collect64.si_errno = 0;
+ collect64.si_pid = 0;
+ collect64.si_uid = 0;
+ collect64.si_addr = 0;
+ collect64.si_status = p->p_xstat;
+ collect64.si_band = 0;
+
+ if (IS_64BIT_PROCESS(p)) {
+ error = copyout((caddr_t)&collect64,
+ uap->infop,
+ sizeof(collect64));
+ } else {
+ siginfo_t collect;
+ siginfo_64to32(&collect64,&collect);
+ error = copyout((caddr_t)&collect,
+ uap->infop,
+ sizeof(collect));
+ }
+ /* information unavailable? */
+ if (error) {
+ p->p_lflag &= ~P_LWAITING;
+ wakeup(&p->p_stat);
+ return (error);
+ }
+
+ /* Prevent other process for waiting for this event? */
+ if (!(uap->options & WNOWAIT)) {
+ /* Clean up */
+ if (!reap_child_process(q, p)) {
+ p->p_lflag &= ~P_LWAITING;
+ wakeup(&p->p_stat);
+ }
+ }
+
+ return (0);
+
+ case SSTOP: /* Stopped */
+ /*
+ * If we are not interested in stopped processes, then
+ * ignore this one.
+ */
+ if (!(uap->options & WSTOPPED))
+ break;
+
+ /*
+ * If someone has already waited it, we lost a race
+ * to be the one to return status.
+ */
+ if ((p->p_flag & P_WAITED) != 0)
+ break;
+
+ /*
+ * If this is not a traced process, and they haven't
+ * indicated an interest in untraced processes, then
+ * ignore this one.
+ */
+ if (!(p->p_flag & P_TRACED) && !(uap->options & WUNTRACED))
+ break;
+
+ /* Collect "siginfo" information for caller */
+ collect64.si_signo = 0;
+ collect64.si_code = 0;
+ collect64.si_errno = 0;
+ collect64.si_pid = 0;
+ collect64.si_uid = 0;
+ collect64.si_addr = 0;
+ collect64.si_status = p->p_xstat;
+ collect64.si_band = 0;
+
+ if (IS_64BIT_PROCESS(p)) {
+ error = copyout((caddr_t)&collect64,
+ uap->infop,
+ sizeof(collect64));
+ } else {
+ siginfo_t collect;
+ siginfo_64to32(&collect64,&collect);
+ error = copyout((caddr_t)&collect,
+ uap->infop,
+ sizeof(collect));
+ }
+ /* information unavailable? */
+ if (error) {
+ p->p_lflag &= ~P_LWAITING;
+ wakeup(&p->p_stat);
+ return (error);
+ }
+
+ /* Prevent other process for waiting for this event? */
+ if (!(uap->options & WNOWAIT)) {
+ p->p_flag |= P_WAITED;
+ }
+
+ p->p_lflag &= ~P_LWAITING;
+ wakeup(&p->p_stat);
+ return (0);
+
+ default: /* All others */
+ /* ...meaning Continued */
+ if (!(uap->options & WCONTINUED))
+ break;
+
+ /*
+ * If the flag isn't set, then this process has not
+ * been stopped and continued, or the status has
+ * already been reaped by another caller of waitid().
+ */
+ if ((p->p_flag & P_CONTINUED) == 0)
+ break;
+
+ /* Collect "siginfo" information for caller */
+ collect64.si_signo = 0;
+ collect64.si_code = 0;
+ collect64.si_errno = 0;
+ collect64.si_pid = 0;
+ collect64.si_uid = 0;
+ collect64.si_addr = 0;
+ collect64.si_status = p->p_xstat;
+ collect64.si_band = 0;
+
+ if (IS_64BIT_PROCESS(p)) {
+ error = copyout((caddr_t)&collect64,
+ uap->infop,
+ sizeof(collect64));
+ } else {
+ siginfo_t collect;
+ siginfo_64to32(&collect64,&collect);
+ error = copyout((caddr_t)&collect,
+ uap->infop,
+ sizeof(collect));
+ }
+ /* information unavailable? */
+ if (error) {
+ p->p_lflag &= ~P_LWAITING;
+ wakeup(&p->p_stat);
+ return (error);
+ }
+
+ /* Prevent other process for waiting for this event? */
+ if (!(uap->options & WNOWAIT)) {
+ p->p_flag &= ~P_CONTINUED;
+ }
+
+ p->p_lflag &= ~P_LWAITING;
+ wakeup(&p->p_stat);
+ return (0);
+
+ break;
+ }
+
+
+ /* Not a process we are interested in; go on to next child */
+ p->p_lflag &= ~P_LWAITING;
+ wakeup(&p->p_stat);
+ }
+
+ /* No child processes that could possibly satisfy the request? */
+ if (nfound == 0)
+ return (ECHILD);
+
+ if (uap->options & WNOHANG) {
+ retval[0] = 0;
+ return (0);
+ }
+
+ if ((error = tsleep0((caddr_t)q, PWAIT | PCATCH, "waitid", 0, waitidcontinue)))