예제 #1
0
int
lwp_park(struct timespec *ts, const void *hint)
{
	struct timespec tsx;
	sleepq_t *sq;
	kmutex_t *mp;
	wchan_t wchan;
	int timo, error;
	lwp_t *l;

	/* Fix up the given timeout value. */
	if (ts != NULL) {
		getnanotime(&tsx);
		timespecsub(ts, &tsx, &tsx);
		if (tsx.tv_sec < 0 || (tsx.tv_sec == 0 && tsx.tv_nsec <= 0))
			return ETIMEDOUT;
		if ((error = itimespecfix(&tsx)) != 0)
			return error;
		timo = tstohz(&tsx);
		KASSERT(timo != 0);
	} else
		timo = 0;

	/* Find and lock the sleep queue. */
	l = curlwp;
	wchan = lwp_park_wchan(l->l_proc, hint);
	sq = sleeptab_lookup(&lwp_park_tab, wchan, &mp);

	/*
	 * Before going the full route and blocking, check to see if an
	 * unpark op is pending.
	 */
	lwp_lock(l);
	if ((l->l_flag & (LW_CANCELLED | LW_UNPARKED)) != 0) {
		l->l_flag &= ~(LW_CANCELLED | LW_UNPARKED);
		lwp_unlock(l);
		mutex_spin_exit(mp);
		return EALREADY;
	}
	lwp_unlock_to(l, mp);
	l->l_biglocks = 0;
	sleepq_enqueue(sq, wchan, "parked", &lwp_park_sobj);
	error = sleepq_block(timo, true);
	switch (error) {
	case EWOULDBLOCK:
		error = ETIMEDOUT;
		break;
	case ERESTART:
		error = EINTR;
		break;
	default:
		/* nothing */
		break;
	}
	return error;
}
예제 #2
0
파일: kern_time.c 프로젝트: ryo/netbsd-src
int
nanosleep1(struct lwp *l, clockid_t clock_id, int flags, struct timespec *rqt,
    struct timespec *rmt)
{
	struct timespec rmtstart;
	int error, timo;

	if ((error = ts2timo(clock_id, flags, rqt, &timo, &rmtstart)) != 0) {
		if (error == ETIMEDOUT) {
			error = 0;
			if (rmt != NULL)
				rmt->tv_sec = rmt->tv_nsec = 0;
		}
		return error;
	}

	/*
	 * Avoid inadvertently sleeping forever
	 */
	if (timo == 0)
		timo = 1;
again:
	error = kpause("nanoslp", true, timo, NULL);
	if (rmt != NULL || error == 0) {
		struct timespec rmtend;
		struct timespec t0;
		struct timespec *t;

		(void)clock_gettime1(clock_id, &rmtend);
		t = (rmt != NULL) ? rmt : &t0;
		if (flags & TIMER_ABSTIME) {
			timespecsub(rqt, &rmtend, t);
		} else {
			timespecsub(&rmtend, &rmtstart, t);
			timespecsub(rqt, t, t);
		}
		if (t->tv_sec < 0)
			timespecclear(t);
		if (error == 0) {
			timo = tstohz(t);
			if (timo > 0)
				goto again;
		}
	}

	if (error == ERESTART)
		error = EINTR;
	if (error == EWOULDBLOCK)
		error = 0;

	return error;
}
예제 #3
0
static int
jzsmb_transfer_write(device_t dev, struct iic_msg *msg, int stop_hold)
{
	struct jzsmb_softc *sc;
	struct timespec start, diff;
	uint16_t con, resid;
	int timeo;

	sc = device_get_softc(dev);
	timeo = JZSMB_TIMEOUT * msg->len;

	SMB_ASSERT_LOCKED(sc);

	con = SMB_READ(sc, SMBCON);
	con |= SMBCON_STPHLD;
	SMB_WRITE(sc, SMBCON, con);

	getnanouptime(&start);
	for (resid = msg->len; resid > 0; resid--) {
		for (;;) {
			getnanouptime(&diff);
			timespecsub(&diff, &start);
			if ((SMB_READ(sc, SMBST) & SMBST_TFNF) != 0) {
				SMB_WRITE(sc, SMBDC,
				    msg->buf[msg->len - resid]);
				break;
			} else
				DELAY((1000 * hz) / JZSMB_TIMEOUT);

			if (tstohz(&diff) >= timeo) {
				device_printf(dev,
				    "write timeout (status=0x%02x)\n",
				    SMB_READ(sc, SMBST));
				return (EIO);
			}
		}
	}

	if (!stop_hold) {
		con = SMB_READ(sc, SMBCON);
		con &= ~SMBCON_STPHLD;
		SMB_WRITE(sc, SMBCON, con);
	}

	return (0);
}
예제 #4
0
static int
jzsmb_transfer_read(device_t dev, struct iic_msg *msg)
{
	struct jzsmb_softc *sc;
	struct timespec start, diff;
	uint16_t con, resid;
	int timeo;

	sc = device_get_softc(dev);
	timeo = JZSMB_TIMEOUT * msg->len;

	SMB_ASSERT_LOCKED(sc);

	con = SMB_READ(sc, SMBCON);
	con |= SMBCON_STPHLD;
	SMB_WRITE(sc, SMBCON, con);

	getnanouptime(&start);
	for (resid = msg->len; resid > 0; resid--) {
		for (int i = 0; i < min(resid, 8); i++)
			SMB_WRITE(sc, SMBDC, SMBDC_CMD);
		for (;;) {
			getnanouptime(&diff);
			timespecsub(&diff, &start);
			if ((SMB_READ(sc, SMBST) & SMBST_RFNE) != 0) {
				msg->buf[msg->len - resid] =
				    SMB_READ(sc, SMBDC) & SMBDC_DAT;
				break;
			} else
				DELAY(1000);

			if (tstohz(&diff) >= timeo) {
				device_printf(dev,
				    "read timeout (status=0x%02x)\n",
				    SMB_READ(sc, SMBST));
				return (EIO);
			}
		}
	}

	con = SMB_READ(sc, SMBCON);
	con &= ~SMBCON_STPHLD;
	SMB_WRITE(sc, SMBCON, con);

	return (0);
}
예제 #5
0
int
sigtimedwait1(struct lwp *l, const struct sys_____sigtimedwait50_args *uap,
    register_t *retval, copyin_t fetchss, copyout_t storeinf, copyin_t fetchts,
    copyout_t storets)
{
	/* {
		syscallarg(const sigset_t *) set;
		syscallarg(siginfo_t *) info;
		syscallarg(struct timespec *) timeout;
	} */
	struct proc *p = l->l_proc;
	int error, signum, timo;
	struct timespec ts, tsstart, tsnow;
	ksiginfo_t ksi;

	/*
	 * Calculate timeout, if it was specified.
	 *
	 * NULL pointer means an infinite timeout.
	 * {.tv_sec = 0, .tv_nsec = 0} means do not block.
	 */
	if (SCARG(uap, timeout)) {
		error = (*fetchts)(SCARG(uap, timeout), &ts, sizeof(ts));
		if (error)
			return error;

		if ((error = itimespecfix(&ts)) != 0)
			return error;

		timo = tstohz(&ts);
		if (timo == 0) {
			if (ts.tv_sec == 0 && ts.tv_nsec == 0)
				timo = -1; /* do not block */
			else
				timo = 1; /* the shortest possible timeout */
		}

		/*
		 * Remember current uptime, it would be used in
		 * ECANCELED/ERESTART case.
		 */
		getnanouptime(&tsstart);
	} else {
		memset(&tsstart, 0, sizeof(tsstart)); /* XXXgcc */
		timo = 0; /* infinite timeout */
	}

	error = (*fetchss)(SCARG(uap, set), &l->l_sigwaitset,
	    sizeof(l->l_sigwaitset));
	if (error)
		return error;

	/*
	 * Silently ignore SA_CANTMASK signals. psignal1() would ignore
	 * SA_CANTMASK signals in waitset, we do this only for the below
	 * siglist check.
	 */
	sigminusset(&sigcantmask, &l->l_sigwaitset);

	mutex_enter(p->p_lock);

	/* Check for pending signals in the process, if no - then in LWP. */
	if ((signum = sigget(&p->p_sigpend, &ksi, 0, &l->l_sigwaitset)) == 0)
		signum = sigget(&l->l_sigpend, &ksi, 0, &l->l_sigwaitset);

	if (signum != 0) {
		/* If found a pending signal, just copy it out to the user. */
		mutex_exit(p->p_lock);
		goto out;
	}

	if (timo < 0) {
		/* If not allowed to block, return an error */
		mutex_exit(p->p_lock);
		return EAGAIN;
	}

	/*
	 * Set up the sigwait list and wait for signal to arrive.
	 * We can either be woken up or time out.
	 */
	l->l_sigwaited = &ksi;
	LIST_INSERT_HEAD(&p->p_sigwaiters, l, l_sigwaiter);
	error = cv_timedwait_sig(&l->l_sigcv, p->p_lock, timo);

	/*
	 * Need to find out if we woke as a result of _lwp_wakeup() or a
	 * signal outside our wait set.
	 */
	if (l->l_sigwaited != NULL) {
		if (error == EINTR) {
			/* Wakeup via _lwp_wakeup(). */
			error = ECANCELED;
		} else if (!error) {
			/* Spurious wakeup - arrange for syscall restart. */
			error = ERESTART;
		}
		l->l_sigwaited = NULL;
		LIST_REMOVE(l, l_sigwaiter);
	}
	mutex_exit(p->p_lock);

	/*
	 * If the sleep was interrupted (either by signal or wakeup), update
	 * the timeout and copyout new value back.  It would be used when
	 * the syscall would be restarted or called again.
	 */
	if (timo && (error == ERESTART || error == ECANCELED)) {
		getnanouptime(&tsnow);

		/* Compute how much time has passed since start. */
		timespecsub(&tsnow, &tsstart, &tsnow);

		/* Substract passed time from timeout. */
		timespecsub(&ts, &tsnow, &ts);

		if (ts.tv_sec < 0)
			error = EAGAIN;
		else {
			/* Copy updated timeout to userland. */
			error = (*storets)(&ts, SCARG(uap, timeout),
			    sizeof(ts));
		}
	}
out:
	/*
	 * If a signal from the wait set arrived, copy it to userland.
	 * Copy only the used part of siginfo, the padding part is
	 * left unchanged (userland is not supposed to touch it anyway).
	 */
	if (error == 0 && SCARG(uap, info)) {
		error = (*storeinf)(&ksi.ksi_info, SCARG(uap, info),
		    sizeof(ksi.ksi_info));
	}
	if (error == 0)
		*retval = ksi.ksi_info._signo;
	return error;
}