예제 #1
0
파일: ethr_event.c 프로젝트: 1153/otp
static ETHR_INLINE int
wait__(ethr_event *e, int spincount)
{
    unsigned sc = spincount;
    int res;
    ethr_sint32_t val;
    int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;

    if (spincount < 0)
	ETHR_FATAL_ERROR__(EINVAL);

    while (1) {
	while (1) {
	    val = ethr_atomic32_read(&e->futex);
	    if (val == ETHR_EVENT_ON__)
		return 0;
	    if (sc == 0)
		break;
	    sc--;
	    ETHR_SPIN_BODY;
	    if (--until_yield == 0) {
		until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
		res = ETHR_YIELD();
		if (res != 0)
		    ETHR_FATAL_ERROR__(res);
	    }
	}

	if (val != ETHR_EVENT_OFF_WAITER__) {
	    val = ethr_atomic32_cmpxchg(&e->futex,
					ETHR_EVENT_OFF_WAITER__,
					ETHR_EVENT_OFF__);

	    if (val == ETHR_EVENT_ON__)
		return 0;
	    ETHR_ASSERT(val == ETHR_EVENT_OFF__);
	}

	res = ETHR_FUTEX__(&e->futex,
			   ETHR_FUTEX_WAIT__,
			   ETHR_EVENT_OFF_WAITER__);
	if (res == EINTR)
	    break;
	if (res != 0 && res != EWOULDBLOCK)
	    ETHR_FATAL_ERROR__(res);
    }

    return res;
}
예제 #2
0
static ETHR_INLINE int
wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
{
    unsigned sc = spincount;
    int res;
    ethr_sint32_t val;
    int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
    ethr_sint64_t time = 0; /* SHUT UP annoying faulty warning... */
    struct timespec ts, *tsp;
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
    ethr_sint64_t start = 0; /* SHUT UP annoying faulty warning... */
#endif

    if (spincount < 0)
        ETHR_FATAL_ERROR__(EINVAL);

    if (timeout < 0) {
        tsp = NULL;
    }
    else {
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
        start = ethr_get_monotonic_time();
#endif
        tsp = &ts;
        time = timeout;
        if (spincount == 0) {
            val = ethr_atomic32_read(&e->futex);
            if (val == ETHR_EVENT_ON__)
                goto return_event_on;
            goto set_timeout;
        }
    }

    while (1) {
        while (1) {
            val = ethr_atomic32_read(&e->futex);
            if (val == ETHR_EVENT_ON__)
                goto return_event_on;
            if (sc == 0)
                break;
            sc--;
            ETHR_SPIN_BODY;
            if (--until_yield == 0) {
                until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
                res = ETHR_YIELD();
                if (res != 0)
                    ETHR_FATAL_ERROR__(res);
            }
        }

        if (timeout >= 0) {
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
            time = timeout - (ethr_get_monotonic_time() - start);
#endif
set_timeout:
            if (time <= 0) {
                val = ethr_atomic32_read(&e->futex);
                if (val == ETHR_EVENT_ON__)
                    goto return_event_on;
                return ETIMEDOUT;
            }
            ts.tv_sec = time / (1000*1000*1000);
            ts.tv_nsec = time % (1000*1000*1000);
        }

        if (val != ETHR_EVENT_OFF_WAITER__) {
            val = ethr_atomic32_cmpxchg(&e->futex,
                                        ETHR_EVENT_OFF_WAITER__,
                                        ETHR_EVENT_OFF__);

            if (val == ETHR_EVENT_ON__)
                goto return_event_on;
            ETHR_ASSERT(val == ETHR_EVENT_OFF__);
        }

        res = ETHR_FUTEX__(&e->futex,
                           ETHR_FUTEX_WAIT__,
                           ETHR_EVENT_OFF_WAITER__,
                           tsp);
        switch (res) {
        case EINTR:
        case ETIMEDOUT:
            return res;
        case 0:
        case EWOULDBLOCK:
            break;
        default:
            ETHR_FATAL_ERROR__(res);
        }
    }

return_event_on:

    ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);

    return 0;

}
예제 #3
0
static ETHR_INLINE int
wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
{
    int sc = spincount;
    ethr_sint32_t val;
    int res, ulres;
    int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
    ethr_sint64_t time = 0; /* SHUT UP annoying faulty warning... */
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
    ethr_sint64_t start = 0; /* SHUT UP annoying faulty warning... */
#endif
#ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
    struct timespec cond_timeout;
#endif

    val = ethr_atomic32_read(&e->state);
    if (val == ETHR_EVENT_ON__)
        goto return_event_on;

    if (timeout < 0) {
        if (spincount == 0)
            goto set_event_off_waiter;
    }
    if (timeout == 0)
        return ETIMEDOUT;
    else {
        time = timeout;
        switch (e->fd[0]) {
        case ETHR_EVENT_INVALID_FD__:
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
            start = ethr_get_monotonic_time();
#endif
            setup_nonblocking_pipe(e);
            break;
#ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
        case ETHR_EVENT_COND_TIMEDWAIT__:
            time += ethr_get_monotonic_time();
            cond_timeout.tv_sec = time / (1000*1000*1000);
            cond_timeout.tv_nsec = time % (1000*1000*1000);
            if (spincount == 0)
                goto set_event_off_waiter;
            break;
#endif
        default:
            /* Already initialized pipe... */
            if (spincount == 0)
                goto set_select_timeout;
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
            start = ethr_get_monotonic_time();
#endif
            break;
        }
    }

    if (spincount < 0)
        ETHR_FATAL_ERROR__(EINVAL);

    while (1) {
        val = ethr_atomic32_read(&e->state);
        if (val == ETHR_EVENT_ON__)
            goto return_event_on;

        if (sc == 0)
            break;
        sc--;
        ETHR_SPIN_BODY;
        if (--until_yield == 0) {
            until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
            res = ETHR_YIELD();
            if (res != 0)
                ETHR_FATAL_ERROR__(res);
        }
    }

    if (timeout < 0
#ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
            || e->fd[0] == ETHR_EVENT_COND_TIMEDWAIT__
#endif
       ) {

set_event_off_waiter:

        if (val != ETHR_EVENT_OFF_WAITER__) {
            ethr_sint32_t act;
            act = ethr_atomic32_cmpxchg(&e->state,
                                        ETHR_EVENT_OFF_WAITER__,
                                        val);
            if (act == ETHR_EVENT_ON__)
                goto return_event_on;
            ETHR_ASSERT(act == val);
        }

        res = pthread_mutex_lock(&e->mtx);
        if (res != 0)
            ETHR_FATAL_ERROR__(res);

        while (1) {

            val = ethr_atomic32_read(&e->state);
            if (val == ETHR_EVENT_ON__) {
                ETHR_ASSERT(res == 0);
                ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);
                break;
            }

#ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
            if (timeout > 0) {
                res = pthread_cond_timedwait(&e->cnd, &e->mtx, &cond_timeout);
                if (res == EINTR || res == ETIMEDOUT)
                    break;
            }
            else
#endif
            {
                res = pthread_cond_wait(&e->cnd, &e->mtx);
                if (res == EINTR)
                    break;
            }
            if (res != 0)
                ETHR_FATAL_ERROR__(res);
        }

        ulres = pthread_mutex_unlock(&e->mtx);
        if (ulres != 0)
            ETHR_FATAL_ERROR__(ulres);

    }
    else {
        int fd;
        int sres;
        ssize_t rres;
#ifndef __DARWIN__
        fd_set rset, eset;
#endif
        fd_set *rsetp, *esetp;
        struct timeval select_timeout;

#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
        time -= ethr_get_monotonic_time() - start;
        if (time <= 0)
            return ETIMEDOUT;
#endif

set_select_timeout:

        ETHR_ASSERT(time > 0);

        /*
         * timeout in nano-second, but we can only wait
         * for micro-seconds...
         */
        time = ((time - 1) / 1000) + 1;

        select_timeout.tv_sec = time / (1000*1000);
        select_timeout.tv_usec = time % (1000*1000);

        ETHR_ASSERT(val != ETHR_EVENT_ON__);

        fd = e->fd[0];

        /* Cleanup pipe... */
        do {
            char buf[64];
            rres = read(fd, buf, sizeof(buf));
        } while (rres > 0 || (rres < 0 && errno == EINTR));
        if (rres < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
            ETHR_FATAL_ERROR__(errno);

        /*
         * Need to verify that state is still off
         * after cleaning the pipe...
         */
        if (val == ETHR_EVENT_OFF_WAITER_SELECT__) {
            val = ethr_atomic32_read(&e->state);
            if (val == ETHR_EVENT_ON__)
                goto return_event_on;
        }
        else {
            ethr_sint32_t act;
            act = ethr_atomic32_cmpxchg(&e->state,
                                        ETHR_EVENT_OFF_WAITER_SELECT__,
                                        val);
            if (act == ETHR_EVENT_ON__)
                goto return_event_on;
            ETHR_ASSERT(act == val);
        }


#ifdef __DARWIN__
        rsetp = e->fdsets->rsetp;
        esetp = e->fdsets->esetp;
        memset((void *) &e->fdsets->mem[0], 0, e->fdsets->mem_size);
#else
        FD_ZERO(&rset);
        FD_ZERO(&eset);
        rsetp = &rset;
        esetp = &eset;
#endif

        FD_SET(fd, rsetp);
        FD_SET(fd, esetp);

        sres = select(fd + 1, rsetp, NULL, esetp, &select_timeout);
        if (sres == 0)
            res = ETIMEDOUT;
        else {
            res = EINTR;
            if (sres < 0 && errno != EINTR)
                ETHR_FATAL_ERROR__(errno);
            /* else:
             *   Event is *probably* set, but it can be a
             *   lingering writer. That is, it is important
             *   that we verify that it actually is set. If
             *   it isn't, return EINTR (spurious wakeup).
             */
        }

        val = ethr_atomic32_read(&e->state);
        if (val == ETHR_EVENT_ON__)
            goto return_event_on;

    }

    return res;

return_event_on:

    ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);

    return 0;
}
예제 #4
0
파일: ethr_event.c 프로젝트: Dasudian/otp
static ETHR_INLINE int
wait(ethr_event *e, int spincount, ethr_sint64_t timeout)
{
    DWORD code, tmo;
    int sc, res, until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;

    if (timeout < 0)
	tmo = INFINITE;
    else if (timeout == 0) {
	ethr_sint32_t state = ethr_atomic32_read(&e->state);
	if (state == ETHR_EVENT_ON__) {
	    ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);
	    return 0;
	}
	return ETIMEDOUT;
    }	    
    else {
	/*
	 * Timeout in nano-seconds, but we can only
	 * wait for milli-seconds...
	 */
	tmo = (DWORD) (timeout - 1) / (1000*1000) + 1;
    }

    if (spincount < 0)
	ETHR_FATAL_ERROR__(EINVAL);

    sc = spincount;

    while (1) {
	ethr_sint32_t state;
	while (1) {
	    state = ethr_atomic32_read(&e->state);
	    if (state == ETHR_EVENT_ON__) {
		ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);
		return 0;
	    }
	    if (sc == 0)
		break;
	    sc--;
	    ETHR_SPIN_BODY;
	    if (--until_yield == 0) {
		until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
		res = ETHR_YIELD();
		if (res != 0)
		    ETHR_FATAL_ERROR__(res);
	    }
	}

	if (state != ETHR_EVENT_OFF_WAITER__) {
	    state = ethr_atomic32_cmpxchg(&e->state,
					  ETHR_EVENT_OFF_WAITER__,
					  ETHR_EVENT_OFF__);
	    if (state == ETHR_EVENT_ON__)
		return 0;
	    ETHR_ASSERT(state == ETHR_EVENT_OFF__);
	}

	code = WaitForSingleObject(e->handle, tmo);
        if (code == WAIT_TIMEOUT)
            return ETIMEDOUT;
	if (code != WAIT_OBJECT_0)
	    ETHR_FATAL_ERROR__(ethr_win_get_errno__());
    }

}
예제 #5
0
파일: ethr_event.c 프로젝트: 1153/otp
static ETHR_INLINE int
wait__(ethr_event *e, int spincount)
{
    int sc = spincount;
    ethr_sint32_t val;
    int res, ulres;
    int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;

    if (spincount < 0)
	ETHR_FATAL_ERROR__(EINVAL);

    while (1) {
	val = ethr_atomic32_read(&e->state);
	if (val == ETHR_EVENT_ON__)
	    return 0;
	if (sc == 0)
	    break;
	sc--;
	ETHR_SPIN_BODY;
	if (--until_yield == 0) {
	    until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
	    res = ETHR_YIELD();
	    if (res != 0)
		ETHR_FATAL_ERROR__(res);
	}
    }

    if (val != ETHR_EVENT_OFF_WAITER__) {
	val = ethr_atomic32_cmpxchg(&e->state,
				    ETHR_EVENT_OFF_WAITER__,
				    ETHR_EVENT_OFF__);
	if (val == ETHR_EVENT_ON__)
	    return 0;
	ETHR_ASSERT(val == ETHR_EVENT_OFF__);
    }

    ETHR_ASSERT(val == ETHR_EVENT_OFF_WAITER__
		|| val == ETHR_EVENT_OFF__);

    res = pthread_mutex_lock(&e->mtx);
    if (res != 0)
	ETHR_FATAL_ERROR__(res);

    while (1) {

	val = ethr_atomic32_read(&e->state);
	if (val == ETHR_EVENT_ON__)
	    break;

	res = pthread_cond_wait(&e->cnd, &e->mtx);
	if (res == EINTR)
	    break;
	if (res != 0)
	    ETHR_FATAL_ERROR__(res);
    }

    ulres = pthread_mutex_unlock(&e->mtx);
    if (ulres != 0)
	ETHR_FATAL_ERROR__(ulres);

    return res; /* 0 || EINTR */
}