static gboolean dispatch_func(GSource *source, AVAHI_GCC_UNUSED GSourceFunc callback, AVAHI_GCC_UNUSED gpointer userdata) { AvahiGLibPoll* g = (AvahiGLibPoll*) source; AvahiWatch *w; AvahiTimeout *next_timeout; g_assert(g); if ((next_timeout = find_next_timeout(g))) { GTimeVal now; struct timeval tvnow; g_source_get_current_time(source, &now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; if (avahi_timeval_compare(&next_timeout->expiry, &tvnow) < 0) { start_timeout_callback(next_timeout); return TRUE; } } for (w = g->watches; w; w = w->watches_next) if (w->pollfd.revents > 0) { assert(w->callback); w->callback(w, w->pollfd.fd, map_events_from_glib(w->pollfd.revents), w->userdata); w->pollfd.revents = 0; return TRUE; } return TRUE; }
static gboolean prepare_func(GSource *source, gint *timeout) { AvahiGLibPoll *g = (AvahiGLibPoll*) source; AvahiTimeout *next_timeout; g_assert(g); g_assert(timeout); if (g->watch_req_cleanup) cleanup_watches(g, 0); if (g->timeout_req_cleanup) cleanup_timeouts(g, 0); if ((next_timeout = find_next_timeout(g))) { GTimeVal now; struct timeval tvnow; AvahiUsec usec; g_source_get_current_time(source, &now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; usec = avahi_timeval_diff(&next_timeout->expiry, &tvnow); if (usec <= 0) { *timeout = 0; return TRUE; } *timeout = (gint) (usec / 1000); } else *timeout = -1; return FALSE; }
ErtsMonotonicTime erts_check_next_timeout_time(ErtsSchedulerData *esdp) { ErtsTimerWheel *tiw = esdp->timer_wheel; if (tiw->true_next_timeout_time) return tiw->next_timeout_time; return find_next_timeout(esdp, tiw, 1, 0, 0); }
int avahi_simple_poll_dispatch(AvahiSimplePoll *s) { AvahiTimeout *next_timeout; AvahiWatch *w; assert(s); assert(s->state == STATE_RAN); s->state = STATE_DISPATCHING; /* We execute only on callback in every iteration */ /* Check whether the wakeup time has been reached now */ if ((next_timeout = find_next_timeout(s))) { if (next_timeout->expiry.tv_sec == 0 && next_timeout->expiry.tv_usec == 0) { /* Just a shortcut so that we don't need to call gettimeofday() */ timeout_callback(next_timeout); goto finish; } if (avahi_age(&next_timeout->expiry) >= 0) { /* Timeout elapsed */ timeout_callback(next_timeout); goto finish; } } /* Look for some kind of I/O event */ for (w = s->watches; w; w = w->watches_next) { if (w->dead) continue; assert(w->idx >= 0); assert(w->idx < s->n_pollfds); if (s->pollfds[w->idx].revents != 0) { w->callback(w, w->pollfd.fd, s->pollfds[w->idx].revents, w->userdata); goto finish; } } finish: s->state = STATE_DISPATCHED; return 0; }
void timer_thread() { while (!isCancelled) { std::unique_lock<std::mutex> lock(m); std::chrono::system_clock::time_point now; while (keys.empty() || earliest > (now = std::chrono::system_clock::now())) { if (keys.empty()) { cv.wait(lock); } else { cv.wait_until(lock, earliest); } if (isCancelled) return; } std::vector<int> expired = remove_expired(now); earliest = find_next_timeout(); lock.unlock(); std::for_each(expired.begin(), expired.end(), callback); } }
static gboolean check_func(GSource *source) { AvahiGLibPoll *g = (AvahiGLibPoll*) source; AvahiWatch *w; AvahiTimeout *next_timeout; g_assert(g); if ((next_timeout = find_next_timeout(g))) { GTimeVal now; struct timeval tvnow; g_source_get_current_time(source, &now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; if (avahi_timeval_compare(&next_timeout->expiry, &tvnow) <= 0) return TRUE; } for (w = g->watches; w; w = w->watches_next) if (w->pollfd.revents > 0) return TRUE; return FALSE; }
int avahi_simple_poll_prepare(AvahiSimplePoll *s, int timeout) { AvahiTimeout *next_timeout; assert(s); assert(s->state == STATE_INIT || s->state == STATE_DISPATCHED || s->state == STATE_FAILURE); s->state = STATE_PREPARING; /* Clear pending wakeup requests */ clear_wakeup(s); /* Cleanup things first */ if (s->watch_req_cleanup) cleanup_watches(s, 0); if (s->timeout_req_cleanup) cleanup_timeouts(s, 0); /* Check whether a quit was requested */ if (s->quit) { s->state = STATE_QUIT; return 1; } /* Do we need to rebuild our array of pollfds? */ if (s->rebuild_pollfds) if (rebuild(s) < 0) { s->state = STATE_FAILURE; return -1; } /* Calculate the wakeup time */ if ((next_timeout = find_next_timeout(s))) { struct timeval now; int t; AvahiUsec usec; if (next_timeout->expiry.tv_sec == 0 && next_timeout->expiry.tv_usec == 0) { /* Just a shortcut so that we don't need to call gettimeofday() */ timeout = 0; goto finish; } gettimeofday(&now, NULL); usec = avahi_timeval_diff(&next_timeout->expiry, &now); if (usec <= 0) { /* Timeout elapsed */ timeout = 0; goto finish; } /* Calculate sleep time. We add 1ms because otherwise we'd * wake up too early most of the time */ t = (int) (usec / 1000) + 1; if (timeout < 0 || timeout > t) timeout = t; } finish: s->prepared_timeout = timeout; s->state = STATE_PREPARED; return 0; }
void erts_bump_timers(ErtsTimerWheel *tiw, ErtsMonotonicTime curr_time) { int tiw_pos_ix, slots, yielded_slot_restarted, yield_count; ErtsMonotonicTime bump_to, tmp_slots, old_pos; yield_count = ERTS_TWHEEL_BUMP_YIELD_LIMIT; /* * In order to be fair we always continue with work * where we left off when restarting after a yield. */ if (tiw->yield_slot >= 0) { yielded_slot_restarted = 1; tiw_pos_ix = tiw->yield_slot; slots = tiw->yield_slots_left; bump_to = tiw->pos; old_pos = tiw->yield_start_pos; goto restart_yielded_slot; } do { yielded_slot_restarted = 0; bump_to = ERTS_MONOTONIC_TO_CLKTCKS(curr_time); while (1) { ErtsTWheelTimer *p; old_pos = tiw->pos; if (tiw->nto == 0) { empty_wheel: ERTS_DBG_CHK_SAFE_TO_SKIP_TO(tiw, bump_to); tiw->true_next_timeout_time = 0; tiw->next_timeout_time = curr_time + ERTS_MONOTONIC_DAY; tiw->pos = bump_to; tiw->yield_slot = ERTS_TWHEEL_SLOT_INACTIVE; return; } p = tiw->at_once.head; while (p) { if (--yield_count <= 0) { ERTS_TW_ASSERT(tiw->nto > 0); ERTS_TW_ASSERT(tiw->at_once.nto > 0); tiw->yield_slot = ERTS_TWHEEL_SLOT_AT_ONCE; tiw->true_next_timeout_time = 1; tiw->next_timeout_time = ERTS_CLKTCKS_TO_MONOTONIC(old_pos); return; } ERTS_TW_ASSERT(tiw->nto > 0); ERTS_TW_ASSERT(tiw->at_once.nto > 0); tiw->nto--; tiw->at_once.nto--; tiw->at_once.head = p->next; if (p->next) p->next->prev = NULL; else tiw->at_once.tail = NULL; timeout_timer(p); p = tiw->at_once.head; } if (tiw->pos >= bump_to) break; if (tiw->nto == 0) goto empty_wheel; if (tiw->true_next_timeout_time) { ErtsMonotonicTime skip_until_pos; /* * No need inspecting slots where we know no timeouts * to trigger should reside. */ skip_until_pos = ERTS_MONOTONIC_TO_CLKTCKS(tiw->next_timeout_time); if (skip_until_pos > bump_to) skip_until_pos = bump_to; skip_until_pos--; if (skip_until_pos > tiw->pos) { ERTS_DBG_CHK_SAFE_TO_SKIP_TO(tiw, skip_until_pos); tiw->pos = skip_until_pos; } } tiw_pos_ix = (int) ((tiw->pos+1) & (ERTS_TIW_SIZE-1)); tmp_slots = (bump_to - tiw->pos); if (tmp_slots < (ErtsMonotonicTime) ERTS_TIW_SIZE) slots = (int) tmp_slots; else slots = ERTS_TIW_SIZE; tiw->pos = bump_to; while (slots > 0) { p = tiw->w[tiw_pos_ix]; if (p) { if (p->next == p) { ERTS_TW_ASSERT(tiw->sentinel.next == &tiw->sentinel); ERTS_TW_ASSERT(tiw->sentinel.prev == &tiw->sentinel); } else { tiw->sentinel.next = p->next; tiw->sentinel.prev = p->prev; tiw->sentinel.next->prev = &tiw->sentinel; tiw->sentinel.prev->next = &tiw->sentinel; } tiw->w[tiw_pos_ix] = NULL; while (1) { if (p->timeout_pos > bump_to) { /* Very unusual case... */ ++yield_count; insert_timer_into_slot(tiw, tiw_pos_ix, p); } else { /* Normal case... */ timeout_timer(p); tiw->nto--; } restart_yielded_slot: p = tiw->sentinel.next; if (p == &tiw->sentinel) { ERTS_TW_ASSERT(tiw->sentinel.prev == &tiw->sentinel); break; } if (--yield_count <= 0) { tiw->true_next_timeout_time = 1; tiw->next_timeout_time = ERTS_CLKTCKS_TO_MONOTONIC(old_pos); tiw->yield_slot = tiw_pos_ix; tiw->yield_slots_left = slots; tiw->yield_start_pos = old_pos; return; /* Yield! */ } tiw->sentinel.next = p->next; p->next->prev = &tiw->sentinel; } } tiw_pos_ix++; if (tiw_pos_ix == ERTS_TIW_SIZE) tiw_pos_ix = 0; slots--; } } } while (yielded_slot_restarted); tiw->yield_slot = ERTS_TWHEEL_SLOT_INACTIVE; tiw->true_next_timeout_time = 0; tiw->next_timeout_time = curr_time + ERTS_MONOTONIC_DAY; /* Search at most two seconds ahead... */ (void) find_next_timeout(NULL, tiw, 0, curr_time, ERTS_SEC_TO_MONOTONIC(2)); }