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; }
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; }