예제 #1
0
파일: condvar.c 프로젝트: BjoKaSH/mac-zfs
/*
 * 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);
}
예제 #2
0
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));
}
예제 #3
0
파일: exit.c 프로젝트: apprisi/illumos-gate
/*
 * 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);
}