Ejemplo n.º 1
0
int
__thr_umtx_timedlock(volatile umtx_t *mtx, const struct timespec *timeout)
{
    struct timespec ts, ts2, ts3;
    int timo, ret;

    if ((timeout->tv_sec < 0) ||
        (timeout->tv_sec == 0 && timeout->tv_nsec <= 0))
	return (ETIMEDOUT);

    /* XXX there should have MONO timer! */
    clock_gettime(CLOCK_REALTIME, &ts);
    TIMESPEC_ADD(&ts, &ts, timeout);
    ts2 = *timeout;

    for (;;) {
    	if (ts2.tv_nsec) {
	    timo = (int)(ts2.tv_nsec / 1000);
	    if (timo == 0)
		timo = 1;
	} else {
	    timo = 1000000;
	}
	ret = __thr_umtx_lock(mtx, timo);
	if (ret != ETIMEDOUT)
	    break;
	clock_gettime(CLOCK_REALTIME, &ts3);
	TIMESPEC_SUB(&ts2, &ts, &ts3);
	if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) {
	    ret = ETIMEDOUT;
	    break;
	}
    }
    return (ret);
}
Ejemplo n.º 2
0
/*
 * Regular umtx wait that cannot return EINTR
 */
int
_thr_umtx_wait(volatile umtx_t *mtx, int exp, const struct timespec *timeout,
	       int clockid)
{
	struct timespec ts, ts2, ts3;
	int timo, errval, ret = 0;

	cpu_ccfence();
	if (*mtx != exp)
		return (0);

	if (timeout == NULL) {
		/*
		 * NOTE: If no timeout, EINTR cannot be returned.  Ignore
		 *	 EINTR.
		 */
		while ((errval = _umtx_sleep_err(mtx, exp, 10000000)) > 0) {
			if (errval == EBUSY)
				break;
#if 0
			if (errval == ETIMEDOUT || errval == EWOULDBLOCK) {
				if (*mtx != exp) {
					fprintf(stderr,
					    "thr_umtx_wait: FAULT VALUE CHANGE "
					    "%d -> %d oncond %p\n",
					    exp, *mtx, mtx);
				}
			}
#endif
			if (*mtx != exp)
				return(0);
		}
		return (ret);
	}

	/*
	 * Timed waits can return EINTR
	 */
	if ((timeout->tv_sec < 0) ||
	    (timeout->tv_sec == 0 && timeout->tv_nsec <= 0))
	return (ETIMEDOUT);

	clock_gettime(clockid, &ts);
	TIMESPEC_ADD(&ts, &ts, timeout);
	ts2 = *timeout;

	for (;;) {
		if (ts2.tv_nsec) {
			timo = (int)(ts2.tv_nsec / 1000);
			if (timo == 0)
				timo = 1;
		} else {
			timo = 1000000;
		}

		if ((errval = _umtx_sleep_err(mtx, exp, timo)) > 0) {
			if (errval == EBUSY) {
				ret = 0;
				break;
			}
			if (errval == EINTR) {
				ret = EINTR;
				break;
			}
		}

		clock_gettime(clockid, &ts3);
		TIMESPEC_SUB(&ts2, &ts, &ts3);
		if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) {
			ret = ETIMEDOUT;
			break;
		}
	}
	return (ret);
}
Ejemplo n.º 3
0
int
_nanosleep(const struct timespec *time_to_sleep,
    struct timespec *time_remaining)
{
	struct pthread	*curthread = _get_curthread();
	int             ret = 0;
	struct timespec ts, ts1;
	struct timespec remaining_time;
	struct timespec wakeup_time;

	/* Check if the time to sleep is legal: */
	if ((time_to_sleep == NULL) || (time_to_sleep->tv_sec < 0) ||
	    (time_to_sleep->tv_nsec < 0) ||
	    (time_to_sleep->tv_nsec >= 1000000000)) {
		/* Return an EINVAL error : */
		errno = EINVAL;
		ret = -1;
	} else {
		if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
			return (__sys_nanosleep(time_to_sleep, time_remaining));
			
		KSE_GET_TOD(curthread->kse, &ts);

		/* Calculate the time for the current thread to wake up: */
		TIMESPEC_ADD(&wakeup_time, &ts, time_to_sleep);

		THR_LOCK_SWITCH(curthread);
		curthread->interrupted = 0;
		curthread->wakeup_time = wakeup_time;
		THR_SET_STATE(curthread, PS_SLEEP_WAIT);

		/* Reschedule the current thread to sleep: */
		_thr_sched_switch_unlocked(curthread);

		/* Calculate the remaining time to sleep: */
		KSE_GET_TOD(curthread->kse, &ts1);
		remaining_time.tv_sec = time_to_sleep->tv_sec
		    + ts.tv_sec - ts1.tv_sec;
		remaining_time.tv_nsec = time_to_sleep->tv_nsec
		    + ts.tv_nsec - ts1.tv_nsec;

		/* Check if the nanosecond field has underflowed: */
		if (remaining_time.tv_nsec < 0) {
			/* Handle the underflow: */
			remaining_time.tv_sec -= 1;
			remaining_time.tv_nsec += 1000000000;
		}
		/* Check if the nanosecond field has overflowed: */
		else if (remaining_time.tv_nsec >= 1000000000) {
			/* Handle the overflow: */
			remaining_time.tv_sec += 1;
			remaining_time.tv_nsec -= 1000000000;
		}

		/* Check if the sleep was longer than the required time: */
		if (remaining_time.tv_sec < 0) {
			/* Reset the time left: */
			remaining_time.tv_sec = 0;
			remaining_time.tv_nsec = 0;
		}

		/* Check if the time remaining is to be returned: */
		if (time_remaining != NULL) {
			/* Return the actual time slept: */
			time_remaining->tv_sec = remaining_time.tv_sec;
			time_remaining->tv_nsec = remaining_time.tv_nsec;
		}

		/* Check if the sleep was interrupted: */
		if (curthread->interrupted) {
			/* Return an EINTR error : */
			errno = EINTR;
			ret = -1;
		}
	}
	return (ret);
}