/* * Like cv_timedwait_sig(), but takes an absolute hires future time * rather than a future time in clock ticks. Will not return showing * that a timeout occurred until the future time is passed. * If 'when' is a NULL pointer, no timeout will occur. * Returns: * Function result in order of presidence: * 0 if a signal was received * -1 if timeout occured * >0 if awakened via cv_signal() or cv_broadcast() * or by a spurious wakeup. * (might return time remaining) * As a special test, if someone abruptly resets the system time * (but not through adjtime(2); drifting of the clock is allowed and * expected [see timespectohz_adj()]), then we force a return of -1 * so the caller can return a premature timeout to the calling process * so it can reevaluate the situation in light of the new system time. * (The system clock has been reset if timecheck != timechanged.) */ int cv_waituntil_sig(kcondvar_t *cvp, kmutex_t *mp, timestruc_t *when, int timecheck) { timestruc_t now; timestruc_t delta; int rval; if (when == NULL) return (cv_wait_sig_swap(cvp, mp)); gethrestime(&now); delta = *when; timespecsub(&delta, &now); if (delta.tv_sec < 0 || (delta.tv_sec == 0 && delta.tv_nsec == 0)) { /* * We have already reached the absolute future time. * Call cv_timedwait_sig() just to check for signals. * We will return immediately with either 0 or -1. */ rval = cv_timedwait_sig(cvp, mp, lbolt); } else { if (timecheck == timechanged) { rval = cv_timedwait_sig(cvp, mp, lbolt + timespectohz_adj(when, now)); } else { /* * Someone reset the system time; * just force an immediate timeout. */ rval = -1; } if (rval == -1 && timecheck == timechanged) { /* * Even though cv_timedwait_sig() returned showing a * timeout, the future time may not have passed yet. * If not, change rval to indicate a normal wakeup. */ gethrestime(&now); delta = *when; timespecsub(&delta, &now); if (delta.tv_sec > 0 || (delta.tv_sec == 0 && delta.tv_nsec > 0)) rval = 1; } } return (rval); }
int sigsuspend(sigset_t *setp) { sigset_t set; k_sigset_t kset; proc_t *p = curproc; if (copyin((caddr_t)setp, (caddr_t)&set, sizeof (sigset_t))) return (set_errno(EFAULT)); sigutok(&set, &kset); mutex_enter(&p->p_lock); schedctl_finish_sigblock(curthread); ttolwp(curthread)->lwp_sigoldmask = curthread->t_hold; curthread->t_hold = kset; curthread->t_sig_check = 1; /* so post-syscall will re-evaluate */ curthread->t_flag |= T_TOMASK; /* pause() */ while (cv_wait_sig_swap(&curthread->t_delay_cv, &p->p_lock)) ; mutex_exit(&p->p_lock); return (set_errno(EINTR)); }
/* * Wait system call. * Search for a terminated (zombie) child, * finally lay it to rest, and collect its status. * Look also for stopped children, * and pass back status from them. */ int waitid(idtype_t idtype, id_t id, k_siginfo_t *ip, int options) { int found; proc_t *cp, *pp; int proc_gone; int waitflag = !(options & WNOWAIT); /* * Obsolete flag, defined here only for binary compatibility * with old statically linked executables. Delete this when * we no longer care about these old and broken applications. */ #define _WNOCHLD 0400 options &= ~_WNOCHLD; if (options == 0 || (options & ~WOPTMASK)) return (EINVAL); switch (idtype) { case P_PID: case P_PGID: if (id < 0 || id >= maxpid) return (EINVAL); /* FALLTHROUGH */ case P_ALL: break; default: return (EINVAL); } pp = ttoproc(curthread); /* * lock parent mutex so that sibling chain can be searched. */ mutex_enter(&pidlock); /* * if we are only looking for exited processes and child_ns list * is empty no reason to look at all children. */ if (idtype == P_ALL && (options & ~WNOWAIT) == (WNOHANG | WEXITED) && pp->p_child_ns == NULL) { if (pp->p_child) { mutex_exit(&pidlock); bzero(ip, sizeof (k_siginfo_t)); return (0); } mutex_exit(&pidlock); return (ECHILD); } while (pp->p_child != NULL) { proc_gone = 0; for (cp = pp->p_child_ns; cp != NULL; cp = cp->p_sibling_ns) { if (idtype != P_PID && (cp->p_pidflag & CLDWAITPID)) continue; if (idtype == P_PID && id != cp->p_pid) continue; if (idtype == P_PGID && id != cp->p_pgrp) continue; switch (cp->p_wcode) { case CLD_TRAPPED: case CLD_STOPPED: case CLD_CONTINUED: cmn_err(CE_PANIC, "waitid: wrong state %d on the p_newstate" " list", cp->p_wcode); break; case CLD_EXITED: case CLD_DUMPED: case CLD_KILLED: if (!(options & WEXITED)) { /* * Count how many are already gone * for good. */ proc_gone++; break; } if (!waitflag) { winfo(cp, ip, 0); } else { winfo(cp, ip, 1); freeproc(cp); } mutex_exit(&pidlock); if (waitflag) { /* accept SIGCLD */ sigcld_delete(ip); sigcld_repost(); } return (0); } if (idtype == P_PID) break; } /* * Wow! None of the threads on the p_sibling_ns list were * interesting threads. Check all the kids! */ found = 0; for (cp = pp->p_child; cp != NULL; cp = cp->p_sibling) { if (idtype == P_PID && id != cp->p_pid) continue; if (idtype == P_PGID && id != cp->p_pgrp) continue; switch (cp->p_wcode) { case CLD_TRAPPED: if (!(options & WTRAPPED)) break; winfo(cp, ip, waitflag); mutex_exit(&pidlock); if (waitflag) { /* accept SIGCLD */ sigcld_delete(ip); sigcld_repost(); } return (0); case CLD_STOPPED: if (!(options & WSTOPPED)) break; /* Is it still stopped? */ mutex_enter(&cp->p_lock); if (!jobstopped(cp)) { mutex_exit(&cp->p_lock); break; } mutex_exit(&cp->p_lock); winfo(cp, ip, waitflag); mutex_exit(&pidlock); if (waitflag) { /* accept SIGCLD */ sigcld_delete(ip); sigcld_repost(); } return (0); case CLD_CONTINUED: if (!(options & WCONTINUED)) break; winfo(cp, ip, waitflag); mutex_exit(&pidlock); if (waitflag) { /* accept SIGCLD */ sigcld_delete(ip); sigcld_repost(); } return (0); case CLD_EXITED: case CLD_DUMPED: case CLD_KILLED: if (idtype != P_PID && (cp->p_pidflag & CLDWAITPID)) continue; /* * Don't complain if a process was found in * the first loop but we broke out of the loop * because of the arguments passed to us. */ if (proc_gone == 0) { cmn_err(CE_PANIC, "waitid: wrong state on the" " p_child list"); } else { break; } } found++; if (idtype == P_PID) break; } /* * If we found no interesting processes at all, * break out and return ECHILD. */ if (found + proc_gone == 0) break; if (options & WNOHANG) { mutex_exit(&pidlock); bzero(ip, sizeof (k_siginfo_t)); /* * We should set ip->si_signo = SIGCLD, * but there is an SVVS test that expects * ip->si_signo to be zero in this case. */ return (0); } /* * If we found no processes of interest that could * change state while we wait, we don't wait at all. * Get out with ECHILD according to SVID. */ if (found == proc_gone) break; if (!cv_wait_sig_swap(&pp->p_cv, &pidlock)) { mutex_exit(&pidlock); return (EINTR); } } mutex_exit(&pidlock); return (ECHILD); }