+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));
+ }
+ /* information unavailable? */
+ if (error)
+ goto out;
+
+ /* Prevent other process for waiting for this event? */
+ if (!(uap->options & WNOWAIT)) {
+ /* Clean up */
+ if (!reap_child_locked(q, p, 0, 0, 0)) {
+ proc_list_lock();
+ p->p_listflag &= ~P_LIST_WAITING;
+ wakeup(&p->p_stat);
+ proc_list_unlock();
+ }
+ } else {
+ proc_list_lock();
+ p->p_listflag &= ~P_LIST_WAITING;
+ proc_list_unlock();
+ }
+
+ 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_lflag & P_LWAITED) != 0)
+ 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;
+ proc_lock(p);
+ collect64.si_status = p->p_xstat;
+ proc_unlock(p);
+ 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)
+ goto out;
+
+ /* Prevent other process for waiting for this event? */
+ if (!(uap->options & WNOWAIT)) {
+ proc_lock(p);
+ p->p_lflag |= P_LWAITED;
+ proc_unlock(p);
+ }
+
+ error = 0;
+ goto out;
+
+ 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;
+
+ /* drop the lock and the thread is going to return */
+ proc_list_unlock();
+
+ /* Collect "siginfo" information for caller */
+ proc_lock(p);
+ collect64.si_signo = SIGCHLD;
+ collect64.si_code = CLD_CONTINUED;
+ collect64.si_errno = 0;
+ collect64.si_pid = p->p_contproc;
+ collect64.si_uid = 0;
+ collect64.si_addr = 0;
+ collect64.si_status = p->p_xstat;
+ collect64.si_band = 0;
+ proc_unlock(p);
+
+ 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)
+ goto out;
+
+ /* Prevent other process for waiting for this event? */
+ if (!(uap->options & WNOWAIT)) {
+ OSBitAndAtomic(~((uint32_t)P_CONTINUED), (UInt32 *)&p->p_flag);
+ }
+
+ error = 0;
+ goto out;
+ }
+ /* LIST LOCK IS HELD HERE */
+ /* Not a process we are interested in; go on to next child */
+
+ p->p_listflag &= ~P_LIST_WAITING;
+ wakeup(&p->p_stat);
+ }
+
+ /* list lock is always held */
+ /* No child processes that could possibly satisfy the request? */
+ if (nfound == 0) {
+ proc_list_unlock();
+ return (ECHILD);
+ }
+
+ if (uap->options & WNOHANG) {
+ proc_list_unlock();
+ return (0);
+ }
+
+ if ((error = msleep0((caddr_t)q, proc_list_mlock, PWAIT | PCATCH | PDROP, "waitid", 0, waitidcontinue)))
+ return (error);
+
+ goto loop;
+out:
+ proc_list_lock();
+ p->p_listflag &= ~P_LIST_WAITING;
+ wakeup(&p->p_stat);
+ proc_list_unlock();
+ return (error);
+}
+
+/*
+ * make process 'parent' the new parent of process 'child'.
+ */
+void
+proc_reparentlocked(proc_t child, proc_t parent, int cansignal, int locked)
+{
+ proc_t oldparent = PROC_NULL;