+
+ return (0);
+ }
+ if (p->p_stat == SSTOP && (p->p_lflag & P_LWAITED) == 0 &&
+ (p->p_lflag & P_LTRACED || uap->options & WUNTRACED)) {
+ proc_list_unlock();
+#if CONFIG_MACF
+ if ((error = mac_proc_check_wait(q, p)) != 0)
+ goto out;
+#endif
+ proc_lock(p);
+ p->p_lflag |= P_LWAITED;
+ proc_unlock(p);
+ retval[0] = p->p_pid;
+ if (uap->status) {
+ status = W_STOPCODE(p->p_xstat);
+ error = copyout((caddr_t)&status,
+ uap->status,
+ sizeof(status));
+ } else
+ error = 0;
+ goto out;
+ }
+ /*
+ * If we are waiting for continued processses, and this
+ * process was continued
+ */
+ if ((uap->options & WCONTINUED) &&
+ (p->p_flag & P_CONTINUED)) {
+ proc_list_unlock();
+#if CONFIG_MACF
+ if ((error = mac_proc_check_wait(q, p)) != 0)
+ goto out;
+#endif
+
+ /* Prevent other process for waiting for this event */
+ OSBitAndAtomic(~((uint32_t)P_CONTINUED), (UInt32 *)&p->p_flag);
+ retval[0] = p->p_pid;
+ if (uap->status) {
+ status = W_STOPCODE(SIGCONT);
+ error = copyout((caddr_t)&status,
+ uap->status,
+ sizeof(status));
+ } else
+ error = 0;
+ goto out;
+ }
+ p->p_listflag &= ~P_LIST_WAITING;
+ wakeup(&p->p_stat);
+ }
+ /* list lock is held when we get here any which way */
+ if (nfound == 0) {
+ proc_list_unlock();
+ return (ECHILD);
+ }
+
+ if (uap->options & WNOHANG) {
+ retval[0] = 0;
+ proc_list_unlock();
+ return (0);
+ }
+
+ if ((error = msleep0((caddr_t)q, proc_list_mlock, PWAIT | PCATCH | PDROP, "wait", 0, wait1continue)))
+ return (error);
+
+ goto loop;
+out:
+ proc_list_lock();
+ p->p_listflag &= ~P_LIST_WAITING;
+ wakeup(&p->p_stat);
+ proc_list_unlock();
+ return (error);
+}
+
+
+int
+waitidcontinue(int result)
+{
+ void *vt;
+ thread_t thread;
+ int *retval;
+
+ if (result)
+ return(result);
+
+ thread = current_thread();
+ vt = get_bsduthreadarg(thread);
+ retval = get_bsduthreadrval(thread);
+ return(waitid(current_proc(), (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(proc_t q, struct waitid_args *uap, register_t *retval)
+{
+ __pthread_testcancel(1);
+ return(waitid_nocancel(q, (struct waitid_nocancel_args *)uap, retval));
+}
+
+int
+waitid_nocancel(proc_t q, struct waitid_nocancel_args *uap, __unused register_t *retval)
+{
+ user_siginfo_t collect64; /* siginfo data to return to caller */
+
+ int nfound;
+ proc_t p;
+ int error;
+
+ /*
+ * Forced validation of options for T.waitpid 21; should be a TSD!
+ * This will pass the test, but note that we have more bits than the
+ * standard specifies that we will allow in, in this case. The test
+ * passes because they light all the bits, not just the ones we allow,
+ * and so the following check returns EINVAL like the test wants.
+ */
+ if (((uap->options & (WNOHANG|WNOWAIT|WCONTINUED|WUNTRACED|WSTOPPED|WEXITED)) != uap->options) ||
+ (uap->options == 0))
+ return (EINVAL); /* bits set that aren't recognized */
+
+ /*
+ * Overly critical options checking, per POSIX
+ */
+ switch(uap->idtype) {
+ case P_PID: /* child with process ID equal to... */
+ case P_PGID: /* child with process group ID equal to... */
+ if (((int)uap->id) < 0)
+ return (EINVAL);
+ break;
+ case P_ALL: /* any child */
+ break;
+ }
+
+loop:
+ proc_list_lock();
+loop1:
+ 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_pgrpid != (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_listflag & P_LIST_WAITING) {
+ (void)msleep(&p->p_stat, proc_list_mlock, PWAIT, "waitidcoll", 0);
+ goto loop1;
+ }
+ p->p_listflag |= P_LIST_WAITING; /* 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;
+
+ /* drop the lock and the thread is going to return */
+ proc_list_unlock();
+
+ /* Collect "siginfo" information for caller */
+ collect64.si_signo = SIGCHLD;
+ collect64.si_code = 0;
+ collect64.si_errno = 0;
+ collect64.si_pid = 0;
+ collect64.si_uid = 0;
+ collect64.si_addr = 0;
+ collect64.si_status = WEXITSTATUS(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));